mirror of
https://github.com/photonstorm/phaser
synced 2024-11-26 22:52:14 +00:00
Merged the arcade-circles branch back into 2.6 and tidied up lots of the source code. Needs checking as not working properly with rect vs. circle, but fine with circle vs. circle.
This commit is contained in:
parent
880275c165
commit
261155a683
2 changed files with 485 additions and 59 deletions
|
@ -35,6 +35,25 @@ Phaser.Physics.Arcade.Body = function (sprite) {
|
|||
*/
|
||||
this.enable = true;
|
||||
|
||||
/**
|
||||
* If `true` this Body is using circular collision detection. If `false` it is using rectangular.
|
||||
* Use `Body.setCircle` to control the collision shape this Body uses.
|
||||
* @property {boolean} isCircle
|
||||
* @default
|
||||
* @readOnly
|
||||
*/
|
||||
this.isCircle = false;
|
||||
|
||||
/**
|
||||
* The radius of the circular collision shape this Body is using if Body.setCircle has been enabled.
|
||||
* If you wish to change the radius then call `setCircle` again with the new value.
|
||||
* If you wish to stop the Body using a circle then call `setCircle` with a radius of zero (or undefined).
|
||||
* @property {float} radius
|
||||
* @default
|
||||
* @readOnly
|
||||
*/
|
||||
this.radius = 0;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
|
||||
*/
|
||||
|
@ -271,6 +290,12 @@ Phaser.Physics.Arcade.Body = function (sprite) {
|
|||
*/
|
||||
this.overlapY = 0;
|
||||
|
||||
/**
|
||||
* If `Body.isCircle` is true, and this body collides with another circular body, the amount of overlap is stored here.
|
||||
* @property {number} overlapR - The amount of overlap during the collision.
|
||||
*/
|
||||
this.overlapR = 0;
|
||||
|
||||
/**
|
||||
* If a body is overlapping with another body, but neither of them are moving (maybe they spawned on-top of each other?) this is set to true.
|
||||
* @property {boolean} embedded - Body embed value.
|
||||
|
@ -725,30 +750,67 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
var bx = (this.worldBounce) ? -this.worldBounce.x : -this.bounce.x;
|
||||
var by = (this.worldBounce) ? -this.worldBounce.y : -this.bounce.y;
|
||||
|
||||
if (pos.x < bounds.x && check.left)
|
||||
if (this.isCircle)
|
||||
{
|
||||
pos.x = bounds.x;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.left = true;
|
||||
}
|
||||
else if (this.right > bounds.right && check.right)
|
||||
{
|
||||
pos.x = bounds.right - this.width;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.right = true;
|
||||
}
|
||||
var bodyBounds = {};
|
||||
bodyBounds.x = this.center.x - this.radius;
|
||||
bodyBounds.y = this.center.y - this.radius;
|
||||
bodyBounds.right = this.center.x + this.radius;
|
||||
bodyBounds.bottom = this.center.y + this.radius;
|
||||
|
||||
if (pos.y < bounds.y && check.up)
|
||||
{
|
||||
pos.y = bounds.y;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.up = true;
|
||||
if (bodyBounds.x < bounds.x && check.left)
|
||||
{
|
||||
pos.x = bounds.x - this.halfWidth + this.radius;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.left = true;
|
||||
}
|
||||
else if (bodyBounds.right > bounds.right && check.right)
|
||||
{
|
||||
pos.x = bounds.right - this.halfWidth - this.radius;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.right = true;
|
||||
}
|
||||
|
||||
if (bodyBounds.y < bounds.y && check.up)
|
||||
{
|
||||
pos.y = bounds.y - this.halfHeight + this.radius;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.up = true;
|
||||
}
|
||||
else if (bodyBounds.bottom > bounds.bottom && check.down)
|
||||
{
|
||||
pos.y = bounds.bottom - this.halfHeight - this.radius;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.down = true;
|
||||
}
|
||||
}
|
||||
else if (this.bottom > bounds.bottom && check.down)
|
||||
else
|
||||
{
|
||||
pos.y = bounds.bottom - this.height;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.down = true;
|
||||
if (pos.x < bounds.x && check.left)
|
||||
{
|
||||
pos.x = bounds.x;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.left = true;
|
||||
}
|
||||
else if (this.right > bounds.right && check.right)
|
||||
{
|
||||
pos.x = bounds.right - this.width;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.right = true;
|
||||
}
|
||||
|
||||
if (pos.y < bounds.y && check.up)
|
||||
{
|
||||
pos.y = bounds.y;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.up = true;
|
||||
}
|
||||
else if (this.bottom > bounds.bottom && check.down)
|
||||
{
|
||||
pos.y = bounds.bottom - this.height;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.down = true;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -937,6 +999,11 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
setSize: function (width, height, offsetX, offsetY) {
|
||||
|
||||
if (this.isCircle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (offsetX === undefined) { offsetX = this.offset.x; }
|
||||
if (offsetY === undefined) { offsetY = this.offset.y; }
|
||||
|
||||
|
@ -952,6 +1019,47 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets this Body as using a circle, of the given radius, for all collision detection instead of a rectangle.
|
||||
* The radius is given in pixels and is the distance from the center of the circle to the edge.
|
||||
*
|
||||
* You can also control the x and y offset, which is the position of the Body relative to the top-left of the Sprite.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade.Body#setCircle
|
||||
* @param {number} [radius] - The radius of the Body in pixels. Pass a value of zero / undefined, to stop the Body using a circle for collision.
|
||||
* @param {number} [offsetX] - The X offset of the Body from the Sprite position.
|
||||
* @param {number} [offsetY] - The Y offset of the Body from the Sprite position.
|
||||
*/
|
||||
setCircle: function (radius, offsetX, offsetY) {
|
||||
|
||||
if (offsetX === undefined) { offsetX = this.offset.x; }
|
||||
if (offsetY === undefined) { offsetY = this.offset.y; }
|
||||
|
||||
if (radius > 0)
|
||||
{
|
||||
this.isCircle = true;
|
||||
this.radius = radius;
|
||||
|
||||
this.sourceWidth = radius * 2;
|
||||
this.sourceHeight = radius * 2;
|
||||
|
||||
this.width = this.sourceWidth * this._sx;
|
||||
this.height = this.sourceHeight * this._sy;
|
||||
|
||||
this.halfWidth = Math.floor(this.width / 2);
|
||||
this.halfHeight = Math.floor(this.height / 2);
|
||||
|
||||
this.offset.setTo(offsetX, offsetY);
|
||||
|
||||
this.center.setTo(this.position.x + this.halfWidth, this.position.y + this.halfHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isCircle = false;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets all Body values (velocity, acceleration, rotation, etc)
|
||||
*
|
||||
|
@ -987,6 +1095,35 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the bounds of this physics body.
|
||||
* Only used internally by the World collision methods.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade.Body#getBounds
|
||||
* @param {object} obj - The object in which to set the bounds values.
|
||||
* @return {object} The object that was given to this method.
|
||||
*/
|
||||
getBounds: function (obj) {
|
||||
|
||||
if (this.isCircle)
|
||||
{
|
||||
obj.x = this.center.x - this.radius;
|
||||
obj.y = this.center.y - this.radius;
|
||||
obj.right = this.center.x + this.radius;
|
||||
obj.bottom = this.center.y + this.radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.x = this.x;
|
||||
obj.y = this.y;
|
||||
obj.right = this.right;
|
||||
obj.bottom = this.bottom;
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Tests if a world point lies within this Body.
|
||||
*
|
||||
|
@ -997,7 +1134,7 @@ Phaser.Physics.Arcade.Body.prototype = {
|
|||
*/
|
||||
hitTest: function (x, y) {
|
||||
|
||||
return Phaser.Rectangle.contains(this, x, y);
|
||||
return (this.isCircle) ? Phaser.Circle.contains(this, x, y) : Phaser.Rectangle.contains(this, x, y);
|
||||
|
||||
},
|
||||
|
||||
|
@ -1231,15 +1368,43 @@ Phaser.Physics.Arcade.Body.render = function (context, body, color, filled) {
|
|||
|
||||
color = color || 'rgba(0,255,0,0.4)';
|
||||
|
||||
if (filled)
|
||||
if (body.isCircle)
|
||||
{
|
||||
context.fillStyle = color;
|
||||
context.fillRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
|
||||
context.save();
|
||||
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||
|
||||
context.beginPath();
|
||||
context.arc(body.center.x - body.game.camera.x, body.center.y - body.game.camera.y, body.radius, 0, 2 * Math.PI);
|
||||
context.closePath();
|
||||
|
||||
if (filled)
|
||||
{
|
||||
context.fillStyle = color;
|
||||
context.fill();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.strokeStyle = color;
|
||||
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
|
||||
{
|
||||
context.strokeStyle = color;
|
||||
context.strokeRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
|
||||
if (filled)
|
||||
{
|
||||
context.fillStyle = color;
|
||||
context.fillRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.strokeStyle = color;
|
||||
context.strokeRect(body.position.x - body.game.camera.x, body.position.y - body.game.camera.y, body.width, body.height);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -704,10 +704,10 @@ Phaser.Physics.Arcade.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
var body;
|
||||
|
||||
if (this.skipQuadTree || sprite.body.skipQuadTree)
|
||||
{
|
||||
var bounds;
|
||||
|
||||
for (var i = 0; i < group.hash.length; i++)
|
||||
{
|
||||
// Skip duff entries - we can't check a non-existent sprite or one with no body
|
||||
|
@ -716,49 +716,50 @@ Phaser.Physics.Arcade.prototype = {
|
|||
continue;
|
||||
}
|
||||
|
||||
body = group.hash[i].body;
|
||||
// Inject the Body bounds data into the bounds object
|
||||
group.hash[i].body.getBounds(bounds);
|
||||
|
||||
// Skip items either side of the sprite
|
||||
if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
|
||||
{
|
||||
if (sprite.body.right < body.x)
|
||||
if (sprite.body.right < bounds.x)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (body.right < sprite.body.x)
|
||||
else if (bounds.right < sprite.body.x)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (this.sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
|
||||
{
|
||||
if (sprite.body.x > body.right)
|
||||
if (sprite.body.x > bounds.right)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (body.x > sprite.body.right)
|
||||
else if (bounds.x > sprite.body.right)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (this.sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
|
||||
{
|
||||
if (sprite.body.bottom < body.y)
|
||||
if (sprite.body.bottom < bounds.y)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (body.bottom < sprite.body.y)
|
||||
else if (bounds.bottom < sprite.body.y)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (this.sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
|
||||
{
|
||||
if (sprite.body.y > body.bottom)
|
||||
if (sprite.body.y > bounds.bottom)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (body.y > sprite.body.bottom)
|
||||
else if (bounds.y > sprite.body.bottom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -816,65 +817,75 @@ Phaser.Physics.Arcade.prototype = {
|
|||
|
||||
for (var i = 0; i < group.hash.length; i++)
|
||||
{
|
||||
var bounds1;
|
||||
var object1 = group.hash[i];
|
||||
|
||||
// Skip duff entries - we can't check a non-existent sprite or one with no body
|
||||
if (!group.hash[i] || !group.hash[i].exists || !group.hash[i].body)
|
||||
if (!object1 || !object1.exists || !object1.body)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var object1 = group.hash[i];
|
||||
// Inject the Body bounds data into the bounds1 object
|
||||
object1.body.getBounds(bounds1);
|
||||
// bounds1.ref = object1;
|
||||
|
||||
for (var j = i + 1; j < group.hash.length; j++)
|
||||
{
|
||||
var bounds2;
|
||||
var object2 = group.hash[j];
|
||||
|
||||
// Skip duff entries - we can't check a non-existent sprite or one with no body
|
||||
if (!group.hash[j] || !group.hash[j].exists || !group.hash[j].body)
|
||||
if (!object2 || !object2.exists || !object2.body)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var object2 = group.hash[j];
|
||||
// Inject the Body bounds data into the bounds2 object
|
||||
object2.body.getBounds(bounds2);
|
||||
// bounds2.ref = object2;
|
||||
|
||||
// Skip items either side of the sprite
|
||||
if (this.sortDirection === Phaser.Physics.Arcade.LEFT_RIGHT)
|
||||
{
|
||||
if (object1.body.right < object2.body.x)
|
||||
if (bounds1.right < bounds2.x)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (object2.body.right < object1.body.x)
|
||||
else if (bounds2.right < bounds1.x)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (this.sortDirection === Phaser.Physics.Arcade.RIGHT_LEFT)
|
||||
{
|
||||
if (object1.body.x > object2.body.right)
|
||||
if (bounds1.x > bounds2.right)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (object2.body.x > object1.body.right)
|
||||
else if (bounds2.x > bounds1.right)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (this.sortDirection === Phaser.Physics.Arcade.TOP_BOTTOM)
|
||||
{
|
||||
if (object1.body.bottom < object2.body.y)
|
||||
if (bounds1.bottom < bounds2.y)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (object2.body.bottom < object1.body.y)
|
||||
else if (bounds2.bottom < bounds1.y)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (this.sortDirection === Phaser.Physics.Arcade.BOTTOM_TOP)
|
||||
{
|
||||
if (object1.body.y > object2.body.bottom)
|
||||
if (bounds1.y > bounds2.bottom)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (object2.body.y > object1.body.bottom)
|
||||
else if (bounds2.y > object1.body.bottom)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -947,6 +958,35 @@ Phaser.Physics.Arcade.prototype = {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Circle vs. Circle quick bail out
|
||||
if (body1.isCircle && body2.isCircle)
|
||||
{
|
||||
return this.separateCircle(body1, body2, overlapOnly);
|
||||
}
|
||||
|
||||
// We define the behavior of bodies in a collision circle and rectangle
|
||||
// If a collision occurs in the corner points of the rectangle, the body behave like circles
|
||||
|
||||
if (body1.isCircle !== body2.isCircle)
|
||||
{
|
||||
var rect = {
|
||||
x: (body2.isCircle) ? body1.position.x : body2.position.x,
|
||||
y: (body2.isCircle) ? body1.position.y : body2.position.y,
|
||||
right: (body2.isCircle) ? body1.right : body2.right,
|
||||
bottom: (body2.isCircle) ? body1.bottom : body2.bottom
|
||||
};
|
||||
|
||||
var circle = {
|
||||
x: (body1.isCircle) ? (body1.position.x + body1.radius) : (body2.position.x + body2.radius),
|
||||
y: (body1.isCircle) ? (body1.position.y + body1.radius) : (body2.position.y + body2.radius)
|
||||
};
|
||||
|
||||
if (circle.y < rect.y || circle.y > rect.bottom)
|
||||
{
|
||||
return this.separateCircle(body1, body2, overlapOnly);
|
||||
}
|
||||
}
|
||||
|
||||
var resultX = false;
|
||||
var resultY = false;
|
||||
|
||||
|
@ -990,26 +1030,230 @@ Phaser.Physics.Arcade.prototype = {
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rect vs. Rect
|
||||
if (body1.right <= body2.position.x)
|
||||
|
||||
if (body1.isCircle)
|
||||
{
|
||||
return false;
|
||||
if (body2.isCircle)
|
||||
{
|
||||
// Circle vs. Circle
|
||||
return Phaser.Math.distance(body1.center.x, body1.center.y, body2.center.x, body2.center.y) <= (body1.radius + body2.radius);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Circle vs. Rect
|
||||
return this.circleBodyIntersects(body1, body2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (body2.isCircle)
|
||||
{
|
||||
// Rect vs. Circle
|
||||
return this.circleBodyIntersects(body2, body1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rect vs. Rect
|
||||
if (body1.right <= body2.position.x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.bottom <= body2.position.y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.position.x >= body2.right)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.position.y >= body2.bottom)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (body1.bottom <= body2.position.y)
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks to see if a circular Body intersects with a Rectangular Body.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#circleBodyIntersects
|
||||
* @param {Phaser.Physics.Arcade.Body} circle - The Body with `isCircle` set.
|
||||
* @param {Phaser.Physics.Arcade.Body} body - The Body with `isCircle` not set (i.e. uses Rectangle shape)
|
||||
* @return {boolean} Returns true if the bodies intersect, otherwise false.
|
||||
*/
|
||||
circleBodyIntersects: function (circle, body) {
|
||||
|
||||
var x = Phaser.Math.clamp(circle.center.x, body.left, body.right);
|
||||
var y = Phaser.Math.clamp(circle.center.y, body.top, body.bottom);
|
||||
|
||||
var dx = (circle.center.x - x) * (circle.center.x - x);
|
||||
var dy = (circle.center.y - y) * (circle.center.y - y);
|
||||
|
||||
return (dx + dy) <= (circle.radius * circle.radius);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The core separation function to separate two circular physics bodies.
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#separateCircle
|
||||
* @private
|
||||
* @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate. Must have `Body.isCircle` true and a positive `radius`.
|
||||
* @param {Phaser.Physics.Arcade.Body} body2 - The second Body to separate. Must have `Body.isCircle` true and a positive `radius`.
|
||||
* @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 or overlap, otherwise false.
|
||||
*/
|
||||
separateCircle: function (body1, body2, overlapOnly) {
|
||||
|
||||
// Set the bounding box overlap values
|
||||
this.getOverlapX(body1, body2);
|
||||
this.getOverlapY(body1, body2);
|
||||
|
||||
var angleCollision = this.angleBetweenCenters(body1, body2);
|
||||
|
||||
var overlap = 0;
|
||||
|
||||
if (body1.isCircle !== body2.isCircle)
|
||||
{
|
||||
return false;
|
||||
var rect = {
|
||||
x: (body2.isCircle) ? body1.position.x : body2.position.x,
|
||||
y: (body2.isCircle) ? body1.position.y : body2.position.y,
|
||||
right: (body2.isCircle) ? body1.right : body2.right,
|
||||
bottom: (body2.isCircle) ? body1.bottom : body2.bottom
|
||||
};
|
||||
|
||||
var circle = {
|
||||
x: (body1.isCircle) ? (body1.position.x + body1.radius) : (body2.position.x + body2.radius),
|
||||
y: (body1.isCircle) ? (body1.position.y + body1.radius) : (body2.position.y + body2.radius),
|
||||
radius: (body1.isCircle) ? body1.radius : body2.radius
|
||||
};
|
||||
|
||||
if (circle.y < rect.y)
|
||||
{
|
||||
if (circle.x < rect.x)
|
||||
{
|
||||
overlap = Phaser.Math.distance(circle.x, circle.y, rect.x, rect.y) - circle.radius;
|
||||
}
|
||||
else if (circle.x > rect.right)
|
||||
{
|
||||
overlap = Phaser.Math.distance(circle.x, circle.y, rect.right, rect.y) - circle.radius;
|
||||
}
|
||||
}
|
||||
else if (circle.y > rect.bottom)
|
||||
{
|
||||
if (circle.x < rect.x)
|
||||
{
|
||||
overlap = Phaser.Math.distance(circle.x, circle.y, rect.x, rect.bottom) - circle.radius;
|
||||
}
|
||||
else if (circle.x > rect.right)
|
||||
{
|
||||
overlap = Phaser.Math.distance(circle.x, circle.y, rect.right, rect.bottom) - circle.radius;
|
||||
}
|
||||
}
|
||||
|
||||
overlap *= -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlap = (body1.radius + body2.radius) - Phaser.Math.distance(body1.center.x, body1.center.y, body2.center.x, body2.center.y);
|
||||
}
|
||||
|
||||
if (body1.position.x >= body2.right)
|
||||
// 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 false;
|
||||
// return true if there was some overlap, otherwise false
|
||||
return (overlap !== 0);
|
||||
}
|
||||
|
||||
if (body1.position.y >= body2.bottom)
|
||||
// Transform the velocity vector to the coordinate system oriented along the direction of impact.
|
||||
// This is done to eliminate the vertical component of the velocity
|
||||
var v1 = {
|
||||
x : body1.velocity.x * Math.cos(angleCollision) + body1.velocity.y * Math.sin(angleCollision),
|
||||
y : body1.velocity.x * Math.sin(angleCollision) - body1.velocity.y * Math.cos(angleCollision)
|
||||
};
|
||||
|
||||
var v2 = {
|
||||
x : body2.velocity.x * Math.cos(angleCollision) + body2.velocity.y * Math.sin(angleCollision),
|
||||
y : body2.velocity.x * Math.sin(angleCollision) - body2.velocity.y * Math.cos(angleCollision)
|
||||
};
|
||||
|
||||
// We expect the new velocity after impact
|
||||
var tempVel1 = ((body1.mass - body2.mass) * v1.x + 2 * body2.mass * v2.x) / (body1.mass + body2.mass);
|
||||
var tempVel2 = (2 * body1.mass * v1.x + (body2.mass - body1.mass) * v2.x) / (body1.mass + body2.mass);
|
||||
|
||||
// We convert the vector to the original coordinate system and multiplied by factor of rebound
|
||||
if (!body1.immovable)
|
||||
{
|
||||
return false;
|
||||
body1.velocity.x = (tempVel1 * Math.cos(angleCollision) - v1.y * Math.sin(angleCollision)) * body1.bounce.x;
|
||||
body1.velocity.y = (v1.y * Math.cos(angleCollision) + tempVel1 * Math.sin(angleCollision)) * body1.bounce.y;
|
||||
}
|
||||
|
||||
if (!body2.immovable)
|
||||
{
|
||||
body2.velocity.x = (tempVel2 * Math.cos(angleCollision) - v2.y * Math.sin(angleCollision)) * body2.bounce.x;
|
||||
body2.velocity.y = (v2.y * Math.cos(angleCollision) + tempVel2 * Math.sin(angleCollision)) * body2.bounce.y;
|
||||
}
|
||||
|
||||
// When the collision angle is almost perpendicular to the total initial velocity vector
|
||||
// (collision on a tangent) vector direction can be determined incorrectly.
|
||||
// This code fixes the problem
|
||||
|
||||
if (Math.abs(angleCollision) < Math.PI / 2)
|
||||
{
|
||||
if (body1.velocity.x > 0 && !body1.immovable && body2.velocity.x > body1.velocity.x)
|
||||
{
|
||||
body1.velocity.x *= -1;
|
||||
}
|
||||
else if (body2.velocity.x < 0 && !body2.immovable && body1.velocity.x < body2.velocity.x)
|
||||
{
|
||||
body2.velocity.x *= -1;
|
||||
}
|
||||
else if (body1.velocity.y > 0 && !body1.immovable && body2.velocity.y > body1.velocity.y)
|
||||
{
|
||||
body1.velocity.y *= -1;
|
||||
}
|
||||
else if (body2.velocity.y < 0 && !body2.immovable && body1.velocity.y < body2.velocity.y)
|
||||
{
|
||||
body2.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
else if (Math.abs(angleCollision) > Math.PI / 2)
|
||||
{
|
||||
if (body1.velocity.x < 0 && !body1.immovable && body2.velocity.x < body1.velocity.x)
|
||||
{
|
||||
body1.velocity.x *= -1;
|
||||
}
|
||||
else if (body2.velocity.x > 0 && !body2.immovable && body1.velocity.x > body2.velocity.x)
|
||||
{
|
||||
body2.velocity.x *= -1;
|
||||
}
|
||||
else if (body1.velocity.y < 0 && !body1.immovable && body2.velocity.y < body1.velocity.y)
|
||||
{
|
||||
body1.velocity.y *= -1;
|
||||
}
|
||||
else if (body2.velocity.y > 0 && !body2.immovable && body1.velocity.x > body2.velocity.y)
|
||||
{
|
||||
body2.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!body1.immovable)
|
||||
{
|
||||
body1.x += (body1.velocity.x * this.game.time.physicsElapsed) - overlap * Math.cos(angleCollision);
|
||||
body1.y += (body1.velocity.y * this.game.time.physicsElapsed) - overlap * Math.sin(angleCollision);
|
||||
}
|
||||
|
||||
if (!body2.immovable)
|
||||
{
|
||||
body2.x += (body2.velocity.x * this.game.time.physicsElapsed) + overlap * Math.cos(angleCollision);
|
||||
body2.y += (body2.velocity.y * this.game.time.physicsElapsed) + overlap * Math.sin(angleCollision);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1709,6 +1953,23 @@ Phaser.Physics.Arcade.prototype = {
|
|||
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the angle in radians between centers of two display objects (like Sprites).
|
||||
*
|
||||
* @method Phaser.Physics.Arcade#angleBetweenCenters
|
||||
* @param {any} source - The Display Object to test from.
|
||||
* @param {any} target - The Display Object to test to.
|
||||
* @return {number} The angle in radians between the source and target display objects.
|
||||
*/
|
||||
angleBetweenCenters: function (source, target) {
|
||||
|
||||
var dx = target.center.x - source.center.x;
|
||||
var dy = target.center.y - source.center.y;
|
||||
|
||||
return Math.atan2(dy, dx);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the angle in radians between a display object (like a Sprite) and the given x/y coordinate.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue