From 89e33ae53e28ef505cd1c06167a0ab44f75adf1a Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Mon, 11 Mar 2019 09:19:41 +0000 Subject: [PATCH] Testing. Please do not use this build, it will break AP. --- src/physics/arcade/Body.js | 184 ++++++++++++++++++------------ src/physics/arcade/GetOverlapY.js | 80 +++++++++---- src/physics/arcade/SeparateY.js | 154 +++++++++++++++++++++---- src/physics/arcade/World.js | 20 +++- 4 files changed, 314 insertions(+), 124 deletions(-) diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index 4ef4d954e..8d16eb58a 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -666,13 +666,22 @@ var Body = new Class({ this.wasTouching = { none: true, up: false, down: false, left: false, right: false }; /** - * Whether this Body is colliding with a tile or the world boundary. + * Whether this Body is blocked from moving in a given direction. * * @name Phaser.Physics.Arcade.Body#blocked * @type {Phaser.Physics.Arcade.Types.ArcadeBodyCollision} * @since 3.0.0 */ - this.blocked = { none: true, up: false, down: false, left: false, right: false }; + this.blocked = { none: true, up: false, down: false, left: false, right: false, x: 0, y: 0 }; + + /** + * Whether this Body is colliding with a tile or the world boundary. + * + * @name Phaser.Physics.Arcade.Body#worldBlocked + * @type {Phaser.Physics.Arcade.Types.ArcadeBodyCollision} + * @since 3.17.0 + */ + this.worldBlocked = { up: false, down: false, left: false, right: false }; /** * Whether to automatically synchronize this Body's dimensions to the dimensions of its Game Object's visual bounds. @@ -718,17 +727,6 @@ var Body = new Class({ */ this.physicsType = CONST.DYNAMIC_BODY; - /** - * Whether the Body's position needs updating from its Game Object. - * - * @name Phaser.Physics.Arcade.Body#_reset - * @type {boolean} - * @private - * @default true - * @since 3.0.0 - */ - this._reset = true; - /** * Cached horizontal scale of the Body's Game Object. * @@ -875,24 +873,28 @@ var Body = new Class({ */ preUpdate: function () { + var wasTouching = this.wasTouching; + var touching = this.touching; + var blocked = this.blocked; + var worldBlocked = this.worldBlocked; + // Store and reset collision flags - this.wasTouching.none = this.touching.none; - this.wasTouching.up = this.touching.up; - this.wasTouching.down = this.touching.down; - this.wasTouching.left = this.touching.left; - this.wasTouching.right = this.touching.right; + wasTouching.none = touching.none; + wasTouching.up = touching.up; + wasTouching.down = touching.down; + wasTouching.left = touching.left; + wasTouching.right = touching.right; - this.touching.none = true; - this.touching.up = false; - this.touching.down = false; - this.touching.left = false; - this.touching.right = false; + touching.none = true; + touching.up = false; + touching.down = false; + touching.left = false; + touching.right = false; - this.blocked.none = true; - this.blocked.up = false; - this.blocked.down = false; - this.blocked.left = false; - this.blocked.right = false; + worldBlocked.left = false; + worldBlocked.right = false; + worldBlocked.up = false; + worldBlocked.down = false; this.overlapR = 0; this.overlapX = 0; @@ -908,17 +910,27 @@ var Body = new Class({ this.position.x = sprite.x + sprite.scaleX * (this.offset.x - sprite.displayOriginX); this.position.y = sprite.y + sprite.scaleY * (this.offset.y - sprite.displayOriginY); - this.updateCenter(); + if (this.collideWorldBounds) + { + this.checkWorldBounds(); + } + else + { + this.updateCenter(); + } + + blocked.up = worldBlocked.up; + blocked.down = worldBlocked.down; + blocked.left = worldBlocked.left; + blocked.right = worldBlocked.right; + blocked.none = (!blocked.up && !blocked.down && !blocked.left && !blocked.right); this.rotation = sprite.rotation; this.preRotation = this.rotation; - if (this._reset) - { - this.prev.x = this.position.x; - this.prev.y = this.position.y; - } + this.prev.x = this.position.x; + this.prev.y = this.position.y; }, /** @@ -937,21 +949,31 @@ var Body = new Class({ */ update: function (delta) { + console.log(this.gameObject.name, 'upd'); + if (this.moves) { this.world.updateMotion(this, delta); - var vx = this.velocity.x; - var vy = this.velocity.y; + var velocity = this.velocity; - this.newVelocity.set(vx * delta, vy * delta); + var nx = velocity.x * delta; + var ny = velocity.y * delta; - this.position.add(this.newVelocity); + if (nx !== 0) + { + this.position.x += this.getMoveX(nx); + } + + if (ny !== 0) + { + this.position.y += this.getMoveY(ny); + } this.updateCenter(); - this.angle = Math.atan2(vy, vx); - this.speed = Math.sqrt(vx * vx + vy * vy); + this.angle = Math.atan2(velocity.y, velocity.x); + this.speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y); } // Calculate the delta @@ -959,35 +981,33 @@ var Body = new Class({ this._dy = this.position.y - this.prev.y; // World Bounds check - if (this.collideWorldBounds && this.checkWorldBounds()) + if (this.collideWorldBounds) { var bx = (this.worldBounce) ? -this.worldBounce.x : -this.bounce.x; var by = (this.worldBounce) ? -this.worldBounce.y : -this.bounce.y; - var blocked = this.blocked; - - if (blocked.left || blocked.right) + var worldBlocked = this.worldBlocked; + + if ((worldBlocked.left || worldBlocked.right)) { if (bx !== 0) { // Reverse the velocity for the bounce and flip the delta - this.velocity.x *= bx; - this._dx *= -1; + velocity.x *= bx; } } - if (blocked.up || blocked.down) + if ((worldBlocked.up || worldBlocked.down)) { if (by !== 0) { // Reverse the velocity for the bounce and flip the delta - this.velocity.y *= by; - this._dy *= -1; + velocity.y *= by; } } if (this.onWorldBounds) { - this.world.emit(Events.WORLD_BOUNDS, this, this.blocked.up, this.blocked.down, this.blocked.left, this.blocked.right); + this.world.emit(Events.WORLD_BOUNDS, this, worldBlocked.up, worldBlocked.down, worldBlocked.left, worldBlocked.right); } } @@ -1005,8 +1025,16 @@ var Body = new Class({ */ postUpdate: function () { - var dx = this.position.x - this.prev.x; - var dy = this.position.y - this.prev.y; + // var dx = this.position.x - this.prev.x; + // var dy = this.position.y - this.prev.y; + + var gameObject = this.gameObject; + + var px = gameObject.x + gameObject.scaleX * (this.offset.x - gameObject.displayOriginX); + var py = gameObject.y + gameObject.scaleY * (this.offset.y - gameObject.displayOriginY); + + var dx = this.position.x - px; + var dy = this.position.y - py; if (this.moves) { @@ -1036,13 +1064,11 @@ var Body = new Class({ dy = my; } } - - this.gameObject.x += dx; - this.gameObject.y += dy; - - this._reset = true; } + gameObject.x += dx; + gameObject.y += dy; + if (dx < 0) { this.facing = CONST.FACING_LEFT; @@ -1066,7 +1092,7 @@ var Body = new Class({ if (this.allowRotation) { - this.gameObject.angle += this.deltaZ(); + gameObject.angle += this.deltaZ(); } this.prev.x = this.position.x; @@ -1083,6 +1109,8 @@ var Body = new Class({ */ checkWorldBounds: function () { + var worldBlocked = this.worldBlocked; + var pos = this.position; var bounds = this.world.bounds; var check = this.world.checkCollision; @@ -1092,26 +1120,26 @@ var Body = new Class({ { set = true; pos.x = bounds.x; - this.setBlockedLeft(); + worldBlocked.left = true; } else if (this.right >= bounds.right && check.right) { set = true; pos.x = bounds.right - this.width; - this.setBlockedRight(); + worldBlocked.right = true; } if (pos.y <= bounds.y && check.up) { set = true; pos.y = bounds.y; - this.setBlockedUp(); + worldBlocked.up = true; } else if (this.bottom >= bounds.bottom && check.down) { set = true; pos.y = bounds.bottom - this.height; - this.setBlockedDown(); + worldBlocked.down = true; } if (set) @@ -1766,10 +1794,8 @@ var Body = new Class({ return this; }, - getMoveX: function (amount, setBlocked) + getMoveX: function (amount) { - if (setBlocked === undefined) { setBlocked = false; } - var blocked = this.blocked; if (amount < 0 && blocked.left || amount > 0 && blocked.right) @@ -1783,15 +1809,16 @@ var Body = new Class({ var pos = this.position; var bounds = this.world.bounds; var check = this.world.checkCollision; + var worldBlocked = this.worldBlocked; if (amount < 0 && check.left && pos.x + amount < bounds.x) { - this.setBlockedLeft(); + worldBlocked.left = true; return amount - ((pos.x + amount) - bounds.x); } else if (amount > 0 && check.right && this.right + amount > bounds.right) { - this.setBlockedRight(); + worldBlocked.right = true; return amount - ((this.right + amount) - bounds.right); } } @@ -1799,10 +1826,8 @@ var Body = new Class({ return amount; }, - getMoveY: function (amount, setBlocked) + getMoveY: function (amount) { - if (setBlocked === undefined) { setBlocked = false; } - var blocked = this.blocked; if (amount < 0 && blocked.up || amount > 0 && blocked.down) @@ -1816,15 +1841,18 @@ var Body = new Class({ var pos = this.position; var bounds = this.world.bounds; var check = this.world.checkCollision; + var worldBlocked = this.worldBlocked; if (amount < 0 && check.up && pos.y + amount < bounds.y) { - this.setBlockedUp(); + worldBlocked.up = true; + blocked.up = true; return amount - ((pos.y + amount) - bounds.y); } else if (amount > 0 && check.down && this.bottom + amount > bounds.bottom) { - this.setBlockedDown(); + worldBlocked.down = true; + blocked.down = true; return amount - ((this.bottom + amount) - bounds.bottom); } } @@ -2270,7 +2298,6 @@ var Body = new Class({ * * @name Phaser.Physics.Arcade.Body#right * @type {number} - * @readonly * @since 3.0.0 */ right: { @@ -2278,6 +2305,11 @@ var Body = new Class({ get: function () { return this.position.x + this.width; + }, + + set: function (value) + { + this.position.x = value - this.width; } }, @@ -2304,7 +2336,6 @@ var Body = new Class({ * * @name Phaser.Physics.Arcade.Body#bottom * @type {number} - * @readonly * @since 3.0.0 */ bottom: { @@ -2312,6 +2343,11 @@ var Body = new Class({ get: function () { return this.position.y + this.height; + }, + + set: function (value) + { + this.position.y = value - this.height; } } diff --git a/src/physics/arcade/GetOverlapY.js b/src/physics/arcade/GetOverlapY.js index 32486c56d..240080504 100644 --- a/src/physics/arcade/GetOverlapY.js +++ b/src/physics/arcade/GetOverlapY.js @@ -6,6 +6,9 @@ /** * Calculates and returns the vertical overlap between two arcade physics bodies. + * + * We know the bodies are intersecting based on a previous check, so the point of this function + * is to determine which face the overlap is occurring on and at what depth. * * @function Phaser.Physics.Arcade.GetOverlapY * @since 3.0.0 @@ -15,44 +18,34 @@ * @param {boolean} overlapOnly - Is this an overlap only check, or part of separation? * @param {number} bias - A value added to the delta values during collision checks. Increase it to prevent sprite tunneling (sprites passing through each other instead of colliding). * - * @return {number} The amount of overlap. + * @return {number[]} An array containing the amount of overlap in element 0 and the face of body1 in element 1 (true = bottom, false = top). */ var GetOverlapY = function (body1, body2, overlapOnly, bias) { var overlap = 0; var maxOverlap = body1.deltaAbsY() + body2.deltaAbsY() + bias; - var body1Down = (body1._dy > body2._dy); + var distance1 = body1.bottom - body2.y; + var distance2 = body2.bottom - body1.y; + var topFace = false; - if (body1._dy === body2._dy) + if (distance1 < distance2) { - // Neither of them has a faster velocity, but we still need to separate them + // Less intersection between the bottom of body1 and the top of body2 + overlap = distance1; - // Try to figure it out based on overlap size - var distance1 = body1.bottom - body2.y; - var distance2 = body2.bottom - body1.y; - - body1Down = (distance1 < distance2); - } - - if (body1Down) - { - // body1 is moving down and body2 is either moving up, moving slower than body1, or static - overlap = body1.bottom - body2.y; - - if ((overlap > maxOverlap && !overlapOnly) || body1.checkCollision.down === false || body2.checkCollision.up === false) + if ((overlap > maxOverlap && !overlapOnly) || !body1.checkCollision.down || !body2.checkCollision.up) { overlap = 0; } } else { - // body1 is moving up and body2 is either moving down, moving slower than body1, or static - overlap = body1.y - body2.bottom; + // Less intersection between the top of body1 and the bottom of body2 + overlap = distance2; + topFace = true; - // console.log('body1 faster up', overlap); - - if ((-overlap > maxOverlap && !overlapOnly) || body1.checkCollision.up === false || body2.checkCollision.down === false) + if ((overlap > maxOverlap && !overlapOnly) || !body1.checkCollision.up || !body2.checkCollision.down) { overlap = 0; } @@ -62,7 +55,48 @@ var GetOverlapY = function (body1, body2, overlapOnly, bias) body1.overlapY = overlap; body2.overlapY = overlap; - return overlap; + return [ overlap, topFace ]; + + /* + var body1Down = (body1.deltaY() > body2.deltaY()); + + if (body1.deltaY() === body2.deltaY()) + { + // Neither of them has a faster velocity, but we still need to separate them, + // so try to figure it out based on overlap depth + var distance1 = body1.bottom - body2.y; + var distance2 = body2.bottom - body1.y; + + body1Down = (distance1 < distance2); + } + + if (body1Down || body2.blocked.down) + { + // body1 is moving down and body2 is either moving up, moving slower than body1, or static + overlap = body1.bottom - body2.y; + + if ((overlap > maxOverlap && !overlapOnly) || !body1.checkCollision.down || !body2.checkCollision.up) + { + overlap = 0; + } + } + else + { + // body1 is moving up and body2 is either moving down, moving slower than body1, or static + overlap = body1.y - body2.bottom; + + if ((-overlap > maxOverlap && !overlapOnly) || !body1.checkCollision.up || !body2.checkCollision.down) + { + overlap = 0; + } + } + + // Resets the overlapY to zero if there is no overlap, or to the actual pixel value if there is + body1.overlapY = overlap; + body2.overlapY = overlap; + + return [ overlap, body1Down ]; + */ }; module.exports = GetOverlapY; diff --git a/src/physics/arcade/SeparateY.js b/src/physics/arcade/SeparateY.js index 3b1fc82d2..7dc703cb6 100644 --- a/src/physics/arcade/SeparateY.js +++ b/src/physics/arcade/SeparateY.js @@ -28,13 +28,22 @@ var GetOverlapY = require('./GetOverlapY'); */ var SeparateY = function (body1, body2, overlapOnly, bias) { - // console.log('SeparateY start', body1.gameObject.name, body2.gameObject.name); + var result = GetOverlapY(body1, body2, overlapOnly, bias); - var overlap = GetOverlapY(body1, body2, overlapOnly, bias); + var overlap = result[0]; + var faceTop = result[1]; + var faceBottom = !faceTop; var velocity1 = body1.velocity; var velocity2 = body2.velocity; + var blocked1 = body1.blocked; + var blocked2 = body2.blocked; + + console.log('SY', overlap, 'faceTop?', faceTop); + + // console.log('SY', body1.gameObject.name, body2.gameObject.name, overlap, 'faceTop?', faceTop); + var body1Immovable = (body1.physicsType === CONST.STATIC_BODY || body1.immovable); var body2Immovable = (body2.physicsType === CONST.STATIC_BODY || body2.immovable); @@ -49,6 +58,51 @@ var SeparateY = function (body1, body2, overlapOnly, bias) var v1 = velocity1.y; var v2 = velocity2.y; + if (faceTop) + { + body1.setTouchingUp(); + body2.setTouchingDown(); + + if (blocked2.up) + { + body1.setBlockedUp(); + } + else if (blocked1.up) + { + body2.setBlockedUp(); + } + } + else + { + body1.setTouchingDown(); + body2.setTouchingUp(); + + if (blocked2.down) + { + console.log('b1'); + body1.setBlockedDown(); + } + else if (blocked1.down) + { + console.log('b2'); + body2.setBlockedDown(); + } + else if (blocked1.up) + { + console.log('b3'); + body2.setBlockedUp(); + } + else if (blocked2.up) + { + console.log('b4'); + body1.setBlockedUp(); + } + else + { + console.log('bum', blocked1.up, blocked2.up); + } + } + // At this point, the velocity from gravity, world rebounds, etc has been factored in. // The body is moving the direction it wants to, but may be blocked. @@ -56,11 +110,65 @@ var SeparateY = function (body1, body2, overlapOnly, bias) { // Neither body is immovable, so they get an equal amount of separation and a new velocity based on mass // Share the overlap equally if both bodies are unblocked - + overlap *= 0.5; + var d1 = body1.getMoveY(-overlap); + var d2 = body2.getMoveY(overlap); - body1.y -= body1.getMoveY(overlap, true); - body2.y += body2.getMoveY(overlap, true); + body1.y -= d1; + body2.y += d2; + + // body1.y -= body1.getMoveY(overlap); + // body2.y += body2.getMoveY(overlap); + + if (faceBottom && blocked2.down) + { + body1.bottom = body2.y; + console.log('a', d1, d2); + } + else if (faceTop && blocked1.down) + { + body2.bottom = body1.y; + console.log('b', d1, d2); + } + else if (faceBottom && blocked1.up) + { + body2.y = body1.bottom; + console.log('c', d1, d2, body1.bottom, body2.y); + } + else if (faceTop && blocked2.up) + { + body1.y = body2.bottom; + console.log('d', d1, d2); + } + + var nv1 = Math.sqrt((v2 * v2 * body2.mass) / body1.mass) * ((v2 > 0) ? 1 : -1); + var nv2 = Math.sqrt((v1 * v1 * body1.mass) / body2.mass) * ((v1 > 0) ? 1 : -1); + var avg = (nv1 + nv2) * 0.5; + + nv1 -= avg; + nv2 -= avg; + + velocity1.y = avg + nv1 * body1.bounce.y; + velocity2.y = avg + nv2 * body2.bounce.y; + } + + + /* + if (!body1Immovable && !body2Immovable) + { + // Neither body is immovable, so they get an equal amount of separation and a new velocity based on mass + // Share the overlap equally if both bodies are unblocked + + var diff1 = body1.getMoveY(overlap * 0.5); + + body1.y -= diff1; + body2.y += body2.getMoveY((overlap - diff1)); + + // -2 -5 false block vs. mush + // 2 5 true mush vs. block + + console.log('p2', diff1, overlap, 'bottom?', overlapBottom); var nv1 = Math.sqrt((v2 * v2 * body2.mass) / body1.mass) * ((v2 > 0) ? 1 : -1); var nv2 = Math.sqrt((v1 * v1 * body1.mass) / body2.mass) * ((v1 > 0) ? 1 : -1); @@ -75,8 +183,7 @@ var SeparateY = function (body1, body2, overlapOnly, bias) else if (!body1Immovable) { // Body2 is immovable, but Body1 can move, so it gets all the separation unless blocked - - body1.y -= body1.getMoveY(overlap, true); + body1.y -= body1.getMoveY(overlap); velocity1.y = v2 - v1 * body1.bounce.y; @@ -89,7 +196,7 @@ var SeparateY = function (body1, body2, overlapOnly, bias) else if (!body2Immovable) { // Body1 is immovable, but Body2 can move, so it gets all the separation unless blocked - body2.y += body2.getMoveY(overlap, true); + body2.y += body2.getMoveY(overlap); velocity2.y = v1 - v2 * body2.bounce.y; @@ -102,31 +209,36 @@ var SeparateY = function (body1, body2, overlapOnly, bias) // It's possible both bodies were equally immovable, in which case neither of them have moved - /* - var blocked1 = body1.blocked; - var blocked2 = body2.blocked; - // Set flags - if (overlap < 0) + if (overlapBottom) { - // body1 was moving down + // body1 was moving down prior to the collision body1.setTouchingDown(); body2.setTouchingUp(); if (blocked2.down) { body1.setBlockedDown(); - - // If we're still moving, but blocked, and the velocity hasn't inversed (i.e. rebounded) we should zero it. - if (velocity1.y > 0) - { - velocity1.y = 0; - } + } + else if (blocked1.down) + { + body2.setBlockedDown(); } } else { - // body1 was moving up + // body1 was moving up prior to the collision + body1.setTouchingUp(); + body2.setTouchingDown(); + + if (blocked2.up) + { + body1.setBlockedUp(); + } + else if (blocked1.up) + { + body2.setBlockedUp(); + } } */ diff --git a/src/physics/arcade/World.js b/src/physics/arcade/World.js index ddd0f57c1..9707ed604 100644 --- a/src/physics/arcade/World.js +++ b/src/physics/arcade/World.js @@ -908,6 +908,8 @@ var World = new Class({ */ update: function (time, delta) { + console.log('World.update ------>', time); + if (this.isPaused || this.bodies.size === 0) { return; @@ -927,12 +929,16 @@ var World = new Class({ } } - var stepsThisFrame = 0; + var stepsThisFrame = 1; var fixedDelta = this._frameTime; var msPerFrame = this._frameTimeMS * this.timeScale; - this._elapsed += delta; + this._elapsed += delta - msPerFrame; + // Always step once, no matter what + this.step(fixedDelta); + + // Additional steps based on remaining time while (this._elapsed >= msPerFrame) { this._elapsed -= msPerFrame; @@ -1000,6 +1006,8 @@ var World = new Class({ */ postUpdate: function () { + console.log('<----- World.postUpdate'); + var i; var body; var bodies = this.bodies.entries; @@ -1589,10 +1597,10 @@ var World = new Class({ { // Rect vs. Rect return !( - body1.right <= body2.position.x || - body1.bottom <= body2.position.y || - body1.position.x >= body2.right || - body1.position.y >= body2.bottom + body1.right <= body2.x || + body1.bottom <= body2.y || + body1.x >= body2.right || + body1.y >= body2.bottom ); } else if (body1.isCircle)