World.separate has been optimized to cut down on the number of calls to intersect from 3 calls per Game Object collision check, to 2. So if you were colliding 50 sprites it will reduce the call count from 150 to 100 per frame. It also reduces the calls made to seperateX and seperateY by the same factor.

Two immovable bodies would never set their overlap data, even if an overlap only check was being made. As this is useful data to have this has been changed. Two immovable bodies will still never separate from each other, but they _will_ have their `overlapX` and `overlapY` properties calculated now.
This commit is contained in:
photonstorm 2016-04-07 18:04:45 +01:00
parent 50e126f59e
commit cc5361dd6d
3 changed files with 204 additions and 223 deletions

View file

@ -333,11 +333,13 @@ You can read all about the philosophy behind Lazer [here](http://phaser.io/news/
### New Arcade Physics Features
* Body has two new properties: `left` and `top`. These are the same as `Body.x` and `Body.y` but allow you to pass the Body to geometry level functions such as Circle.contains.
* Body.setCircle allows you to define a Body as using a circle to collide with instead of a rectangle. You can set the radius of the collision circle and an offset.
* Body.render now renders both circle and rectangle body shapes to the Debug canvas.
* World.intersects has been updated to support both circle and rectangle body shapes, and supports quick-paths for circle vs. circle and rect vs. rect checks.
* World.circleBodyIntersects is a new method that checks for intersection between a Body that has been defined as a circle, and a normal rectangle based Body. This is used internally by World.intersects, but exposed for direct calls as well.
* Body has two new properties: `left` and `top`. These are the same as `Body.x` and `Body.y` but allow you to pass the Body to geometry level functions such as Circle.contains.
* World.separate has been optimized to cut down on the number of calls to `intersect` from 3 calls per Game Object collision check, to 2. So if you were colliding 50 sprites it will reduce the call count from 150 to 100 per frame. It also reduces the calls made to `seperateX` and `seperateY` by the same factor.
* Two immovable bodies would never set their overlap data, even if an overlap only check was being made. As this is useful data to have this has been changed. Two immovable bodies will still never separate from each other, but they _will_ have their `overlapX` and `overlapY` properties calculated now.
### Updates

View file

@ -1000,6 +1000,9 @@ Phaser.Physics.Arcade.Body.render = function (context, body, color, filled) {
context.stroke();
}
context.strokeStyle = '#ffff00';
context.strokeRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
context.restore();
}
else

View file

@ -947,29 +947,32 @@ Phaser.Physics.Arcade.prototype = {
return false;
}
var resultX = false;
var resultY = false;
// Do we separate on x or y first?
var result = false;
// If we weren't having to carry around so much legacy baggage with us, we could do this properly. But alas ...
if (this.forceX || Math.abs(this.gravity.y + body1.gravity.y) < Math.abs(this.gravity.x + body1.gravity.x))
{
result = (this.separateX(body1, body2, overlapOnly) || this.separateY(body1, body2, overlapOnly));
resultX = this.separateX(body1, body2, overlapOnly);
// Are they still intersecting? Let's do the other axis then
if (this.intersects(body1, body2))
{
resultY = this.separateY(body1, body2, overlapOnly);
}
}
else
{
result = (this.separateY(body1, body2, overlapOnly) || this.separateX(body1, body2, overlapOnly));
resultY = this.separateY(body1, body2, overlapOnly);
// Are they still intersecting? Let's do the other axis then
if (this.intersects(body1, body2))
{
resultX = this.separateX(body1, body2, overlapOnly);
}
}
if (overlapOnly)
{
// We already know they intersect from the check above, but by this point we know they've now had their overlapX/Y values populated
return true;
}
else
{
return result;
}
return (resultX || resultY);
},
@ -1057,127 +1060,114 @@ Phaser.Physics.Arcade.prototype = {
*
* @private
* @method Phaser.Physics.Arcade#separateX
* @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate.
* @param {Phaser.Physics.Arcade.Body} body2 - The Body object to separate.
* @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
* @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate.
* @param {boolean} overlapOnly - If true the bodies will only have their overlap data set, no separation or exchange of velocity will take place.
* @return {boolean} Returns true if the bodies were separated, otherwise false.
* @return {boolean} Returns true if the bodies were separated or overlap, otherwise false.
*/
separateX: function (body1, body2, overlapOnly) {
// Can't separate two immovable bodies
if (body1.immovable && body2.immovable)
{
return false;
}
var overlap = 0;
var maxOverlap = body1.deltaAbsX() + body2.deltaAbsX() + this.OVERLAP_BIAS;
// Check if the hulls actually overlap
if (this.intersects(body1, body2))
if (body1.deltaX() === 0 && body2.deltaX() === 0)
{
var maxOverlap = body1.deltaAbsX() + body2.deltaAbsX() + this.OVERLAP_BIAS;
// They overlap but neither of them are moving
body1.embedded = true;
body2.embedded = true;
}
else if (body1.deltaX() > body2.deltaX())
{
// Body1 is moving right and / or Body2 is moving left
overlap = body1.right - body2.x;
if (body1.deltaX() === 0 && body2.deltaX() === 0)
if ((overlap > maxOverlap) || body1.checkCollision.right === false || body2.checkCollision.left === false)
{
// They overlap but neither of them are moving
body1.embedded = true;
body2.embedded = true;
overlap = 0;
}
else if (body1.deltaX() > body2.deltaX())
else
{
// Body1 is moving right and/or Body2 is moving left
overlap = body1.right - body2.x;
if ((overlap > maxOverlap) || body1.checkCollision.right === false || body2.checkCollision.left === false)
{
overlap = 0;
}
else
{
body1.touching.none = false;
body1.touching.right = true;
body2.touching.none = false;
body2.touching.left = true;
}
body1.touching.none = false;
body1.touching.right = true;
body2.touching.none = false;
body2.touching.left = true;
}
else if (body1.deltaX() < body2.deltaX())
{
// Body1 is moving left and/or Body2 is moving right
overlap = body1.x - body2.width - body2.x;
}
else if (body1.deltaX() < body2.deltaX())
{
// Body1 is moving left and/or Body2 is moving right
overlap = body1.x - body2.width - body2.x;
if ((-overlap > maxOverlap) || body1.checkCollision.left === false || body2.checkCollision.right === false)
{
overlap = 0;
}
else
{
body1.touching.none = false;
body1.touching.left = true;
body2.touching.none = false;
body2.touching.right = true;
}
if ((-overlap > maxOverlap) || body1.checkCollision.left === false || body2.checkCollision.right === false)
{
overlap = 0;
}
// Resets the overlapX to zero if there is no overlap, or to the actual pixel value if there is
body1.overlapX = overlap;
body2.overlapX = overlap;
// Then adjust their positions and velocities accordingly (if there was any overlap)
if (overlap !== 0)
else
{
if (overlapOnly || body1.customSeparateX || body2.customSeparateX)
{
return true;
}
var v1 = body1.velocity.x;
var v2 = body2.velocity.x;
if (!body1.immovable && !body2.immovable)
{
overlap *= 0.5;
body1.x = body1.x - overlap;
body2.x += overlap;
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;
body1.velocity.x = avg + nv1 * body1.bounce.x;
body2.velocity.x = avg + nv2 * body2.bounce.x;
}
else if (!body1.immovable)
{
body1.x = body1.x - overlap;
body1.velocity.x = v2 - v1 * body1.bounce.x;
// This is special case code that handles things like vertically moving platforms you can ride
if (body2.moves)
{
body1.y += (body2.y - body2.prev.y) * body2.friction.y;
}
}
else if (!body2.immovable)
{
body2.x += overlap;
body2.velocity.x = v1 - v2 * body2.bounce.x;
// This is special case code that handles things like vertically moving platforms you can ride
if (body1.moves)
{
body2.y += (body1.y - body1.prev.y) * body1.friction.y;
}
}
return true;
body1.touching.none = false;
body1.touching.left = true;
body2.touching.none = false;
body2.touching.right = true;
}
}
return false;
// Resets the overlapX to zero if there is no overlap, or to the actual pixel value if there is
body1.overlapX = overlap;
body2.overlapX = overlap;
// Can't separate two immovable bodies, or a body with its own custom separation logic
if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateX || body2.customSeparateX)
{
// return true if there was some overlap, otherwise false
return (overlap !== 0);
}
// Adjust their positions and velocities accordingly (if there was any overlap)
var v1 = body1.velocity.x;
var v2 = body2.velocity.x;
if (!body1.immovable && !body2.immovable)
{
overlap *= 0.5;
body1.x = body1.x - overlap;
body2.x += overlap;
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;
body1.velocity.x = avg + nv1 * body1.bounce.x;
body2.velocity.x = avg + nv2 * body2.bounce.x;
}
else if (!body1.immovable)
{
body1.x = body1.x - overlap;
body1.velocity.x = v2 - v1 * body1.bounce.x;
// This is special case code that handles things like vertically moving platforms you can ride
if (body2.moves)
{
body1.y += (body2.y - body2.prev.y) * body2.friction.y;
}
}
else if (!body2.immovable)
{
body2.x += overlap;
body2.velocity.x = v1 - v2 * body2.bounce.x;
// This is special case code that handles things like vertically moving platforms you can ride
if (body1.moves)
{
body2.y += (body1.y - body1.prev.y) * body1.friction.y;
}
}
// If we got this far then there WAS overlap, and separation is complete, so return true
return true;
},
@ -1186,128 +1176,114 @@ Phaser.Physics.Arcade.prototype = {
*
* @private
* @method Phaser.Physics.Arcade#separateY
* @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate.
* @param {Phaser.Physics.Arcade.Body} body2 - The Body object to separate.
* @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
* @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate.
* @param {boolean} overlapOnly - If true the bodies will only have their overlap data set, no separation or exchange of velocity will take place.
* @return {boolean} Returns true if the bodies were separated, otherwise false.
* @return {boolean} Returns true if the bodies were separated or overlap, otherwise false.
*/
separateY: function (body1, body2, overlapOnly) {
// Can't separate two immovable or non-existing bodies
if (body1.immovable && body2.immovable)
{
return false;
}
var overlap = 0;
var maxOverlap = body1.deltaAbsY() + body2.deltaAbsY() + this.OVERLAP_BIAS;
// Check if the hulls actually overlap
if (this.intersects(body1, body2))
if (body1.deltaY() === 0 && body2.deltaY() === 0)
{
var maxOverlap = body1.deltaAbsY() + body2.deltaAbsY() + this.OVERLAP_BIAS;
// They overlap but neither of them are moving
body1.embedded = true;
body2.embedded = true;
}
else if (body1.deltaY() > body2.deltaY())
{
// Body1 is moving down and/or Body2 is moving up
overlap = body1.bottom - body2.y;
if (body1.deltaY() === 0 && body2.deltaY() === 0)
if ((overlap > maxOverlap) || body1.checkCollision.down === false || body2.checkCollision.up === false)
{
// They overlap but neither of them are moving
body1.embedded = true;
body2.embedded = true;
overlap = 0;
}
else if (body1.deltaY() > body2.deltaY())
else
{
// Body1 is moving down and/or Body2 is moving up
overlap = body1.bottom - body2.y;
if ((overlap > maxOverlap) || body1.checkCollision.down === false || body2.checkCollision.up === false)
{
overlap = 0;
}
else
{
body1.touching.none = false;
body1.touching.down = true;
body2.touching.none = false;
body2.touching.up = true;
}
body1.touching.none = false;
body1.touching.down = true;
body2.touching.none = false;
body2.touching.up = true;
}
else if (body1.deltaY() < body2.deltaY())
}
else if (body1.deltaY() < body2.deltaY())
{
// Body1 is moving up and/or Body2 is moving down
overlap = body1.y - body2.bottom;
if ((-overlap > maxOverlap) || body1.checkCollision.up === false || body2.checkCollision.down === false)
{
// Body1 is moving up and/or Body2 is moving down
overlap = body1.y - body2.bottom;
if ((-overlap > maxOverlap) || body1.checkCollision.up === false || body2.checkCollision.down === false)
{
overlap = 0;
}
else
{
body1.touching.none = false;
body1.touching.up = true;
body2.touching.none = false;
body2.touching.down = true;
}
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;
// Then adjust their positions and velocities accordingly (if there was any overlap)
if (overlap !== 0)
else
{
if (overlapOnly || body1.customSeparateY || body2.customSeparateY)
{
return true;
}
var v1 = body1.velocity.y;
var v2 = body2.velocity.y;
if (!body1.immovable && !body2.immovable)
{
overlap *= 0.5;
body1.y = body1.y - overlap;
body2.y += overlap;
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;
body1.velocity.y = avg + nv1 * body1.bounce.y;
body2.velocity.y = avg + nv2 * body2.bounce.y;
}
else if (!body1.immovable)
{
body1.y = body1.y - overlap;
body1.velocity.y = v2 - v1 * body1.bounce.y;
// This is special case code that handles things like horizontal moving platforms you can ride
if (body2.moves)
{
body1.x += (body2.x - body2.prev.x) * body2.friction.x;
}
}
else if (!body2.immovable)
{
body2.y += overlap;
body2.velocity.y = v1 - v2 * body2.bounce.y;
// This is special case code that handles things like horizontal moving platforms you can ride
if (body1.moves)
{
body2.x += (body1.x - body1.prev.x) * body1.friction.x;
}
}
return true;
body1.touching.none = false;
body1.touching.up = true;
body2.touching.none = false;
body2.touching.down = true;
}
}
return false;
// 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;
// Can't separate two immovable bodies, or a body with its own custom separation logic
if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateY || body2.customSeparateY)
{
// return true if there was some overlap, otherwise false
return (overlap !== 0);
}
// Adjust their positions and velocities accordingly (if there was any overlap)
var v1 = body1.velocity.y;
var v2 = body2.velocity.y;
if (!body1.immovable && !body2.immovable)
{
overlap *= 0.5;
body1.y = body1.y - overlap;
body2.y += overlap;
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;
body1.velocity.y = avg + nv1 * body1.bounce.y;
body2.velocity.y = avg + nv2 * body2.bounce.y;
}
else if (!body1.immovable)
{
body1.y = body1.y - overlap;
body1.velocity.y = v2 - v1 * body1.bounce.y;
// This is special case code that handles things like horizontal moving platforms you can ride
if (body2.moves)
{
body1.x += (body2.x - body2.prev.x) * body2.friction.x;
}
}
else if (!body2.immovable)
{
body2.y += overlap;
body2.velocity.y = v1 - v2 * body2.bounce.y;
// This is special case code that handles things like horizontal moving platforms you can ride
if (body1.moves)
{
body2.x += (body1.x - body1.prev.x) * body1.friction.x;
}
}
// If we got this far then there WAS overlap, and separation is complete, so return true
return true;
},