Finished Ninja Physics updates.

This commit is contained in:
photonstorm 2014-03-11 14:21:20 +00:00
parent 170776ada1
commit d2d77f37dd
4 changed files with 130 additions and 187 deletions

View file

@ -41,7 +41,7 @@ function create() {
function t() { function t() {
sprite1.body.shape.oldpos.x = sprite1.body.shape.pos.x - 20; sprite1.body.shape.oldpos.x = sprite1.body.shape.pos.x - 30;
sprite2.body.shape.oldpos.x = sprite2.body.shape.pos.x + 20; sprite2.body.shape.oldpos.x = sprite2.body.shape.pos.x + 20;
} }

View file

@ -200,8 +200,37 @@ Phaser.Physics.Ninja.AABB.prototype = {
}, },
reverse: function () {
var vx = this.pos.x - this.oldpos.x;
var vy = this.pos.y - this.oldpos.y;
if (this.oldpos.x < this.pos.x)
{
this.oldpos.x = this.pos.x + vx;
// this.oldpos.x = this.pos.x + (vx + 1 + this.body.bounce);
}
else if (this.oldpos.x > this.pos.x)
{
this.oldpos.x = this.pos.x - vx;
// this.oldpos.x = this.pos.x - (vx + 1 + this.body.bounce);
}
if (this.oldpos.y < this.pos.y)
{
this.oldpos.y = this.pos.y + vy;
// this.oldpos.y = this.pos.y + (vy + 1 + this.body.bounce);
}
else if (this.oldpos.y > this.pos.y)
{
this.oldpos.y = this.pos.y - vy;
// this.oldpos.y = this.pos.y - (vy + 1 + this.body.bounce);
}
},
/** /**
* Process a body collision and apply the resulting forces. * Process a body collision and apply the resulting forces. Still very much WIP and doesn't work fully. Feel free to fix!
* *
* @method Phaser.Physics.Ninja.AABB#reportCollisionVsBody * @method Phaser.Physics.Ninja.AABB#reportCollisionVsBody
* @param {number} px - The tangent velocity * @param {number} px - The tangent velocity
@ -226,13 +255,7 @@ Phaser.Physics.Ninja.AABB.prototype = {
var nx2 = dp2 * dx2; // Project velocity onto collision normal var nx2 = dp2 * dx2; // Project velocity onto collision normal
var ny2 = dp2 * dy2; // nx, ny is normal velocity var ny2 = dp2 * dy2; // nx, ny is normal velocity
console.log(this.body.sprite.name, 'hit', obj.body.sprite.name, 'at', px, py, 'dx', dx, dy, 'dx2', dx2, dy2);
console.log(this.body.sprite.name, 'x', (this.pos.x + this.xw), obj.body.sprite.name, 'x', (obj.pos.x - obj.xw));
console.log('vx1', vx1, vy1, 'dp1', dp1, 'nx1', nx1, ny1);
console.log('vx2', vx2, vy2, 'dp2', dp2, 'nx2', nx2, ny2);
// We only want to apply collision response forces if the object is travelling into, and not out of, the collision // We only want to apply collision response forces if the object is travelling into, and not out of, the collision
if (this.body.immovable && obj.body.immovable) if (this.body.immovable && obj.body.immovable)
{ {
// Split the separation then return, no forces applied as they come to a stand-still // Split the separation then return, no forces applied as they come to a stand-still
@ -249,104 +272,38 @@ Phaser.Physics.Ninja.AABB.prototype = {
} }
else if (!this.body.immovable && !obj.body.immovable) else if (!this.body.immovable && !obj.body.immovable)
{ {
// separate
px *= 0.5; px *= 0.5;
py *= 0.5; py *= 0.5;
this.pos.add(px, py); this.pos.add(px, py);
this.oldpos.set(this.pos.x, this.pos.y);
obj.pos.subtract(px, py); obj.pos.subtract(px, py);
obj.oldpos.set(obj.pos.x, obj.pos.y);
// x velocity if (dp1 < 0)
var nv1 = Math.sqrt((vx2 * vx2 * 1) / 1) * ((vx2 > 0) ? 1 : -1); {
var nv2 = Math.sqrt((vx1 * vx1 * 1) / 1) * ((vx1 > 0) ? 1 : -1); this.reverse();
var avg = (nv1 + nv2) * 0.5; obj.reverse();
nv1 -= avg; }
nv2 -= avg;
this.pos.x += avg + nv1 * this.body.bounce;
obj.pos.x += avg + nv2 * obj.body.bounce;
// y velocity
var nv1 = Math.sqrt((vy2 * vy2 * 1) / 1) * ((vy2 > 0) ? 1 : -1);
var nv2 = Math.sqrt((vy1 * vy1 * 1) / 1) * ((vy1 > 0) ? 1 : -1);
var avg = (nv1 + nv2) * 0.5;
nv1 -= avg;
nv2 -= avg;
this.pos.y += avg + nv1 * this.body.bounce;
obj.pos.y += avg + nv2 * obj.body.bounce;
} }
else if (!this.body.immovable) else if (!this.body.immovable)
{ {
/* this.pos.subtract(px, py);
if (dp1 < 0) if (dp1 < 0)
{ {
this.pos.add(px, py); this.reverse();
// px + bounce + friction
this.oldpos.x += px + (nx1 * (1 + this.body.bounce)) + ((vx2 - nx1) * this.body.friction);
this.oldpos.y += py + (ny1 * (1 + this.body.bounce)) + ((vy2 - ny1) * this.body.friction);
} }
else
{
// Moving out of collision, do not apply forces
this.pos.add(px, py);
this.oldpos.add(px, py);
}
*/
} }
else if (!obj.body.immovable) else if (!obj.body.immovable)
{ {
/* obj.pos.subtract(px, py);
if (dp2 < 0)
if (dp1 < 0)
{ {
obj.pos.add(px, py); obj.reverse();
// px + bounce + friction
obj.oldpos.x += px + (nx2 * (1 + obj.body.bounce)) + ((vx2 - nx2) * obj.body.friction);
obj.oldpos.y += py + (ny2 * (1 + obj.body.bounce)) + ((vy2 - ny2) * obj.body.friction);
} }
else
{
// Moving out of collision, do not apply forces
obj.pos.add(px, py);
obj.oldpos.add(px, py);
}
*/
} }
/*
if (!body1.immovable && !body2.immovable)
{
this._overlap *= 0.5;
body1.x = body1.x - this._overlap;
body2.x += this._overlap;
this._newVelocity1 = Math.sqrt((this._velocity2 * this._velocity2 * body2.mass) / body1.mass) * ((this._velocity2 > 0) ? 1 : -1);
this._newVelocity2 = Math.sqrt((this._velocity1 * this._velocity1 * body1.mass) / body2.mass) * ((this._velocity1 > 0) ? 1 : -1);
this._average = (this._newVelocity1 + this._newVelocity2) * 0.5;
this._newVelocity1 -= this._average;
this._newVelocity2 -= this._average;
body1.velocity.x = this._average + this._newVelocity1 * body1.bounce.x;
body2.velocity.x = this._average + this._newVelocity2 * body2.bounce.x;
}
else if (!body1.immovable)
{
body1.x = body1.x - this._overlap;
body1.velocity.x = this._velocity2 - this._velocity1 * body1.bounce.x;
}
else if (!body2.immovable)
{
body2.x += this._overlap;
body2.velocity.x = this._velocity1 - this._velocity2 * body2.bounce.x;
}
*/
}, },
/** /**
@ -450,10 +407,7 @@ Phaser.Physics.Ninja.AABB.prototype = {
} }
} }
// return this.aabbTileProjections[1](px, py, this, c);
var l = Math.sqrt(px * px + py * py); var l = Math.sqrt(px * px + py * py);
// this.reportCollisionVsWorld(px, py, px / l, py / l, c);
this.reportCollisionVsBody(px, py, px / l, py / l, c); this.reportCollisionVsBody(px, py, px / l, py / l, c);
return Phaser.Physics.Ninja.AABB.COL_AXIS; return Phaser.Physics.Ninja.AABB.COL_AXIS;
@ -473,59 +427,50 @@ Phaser.Physics.Ninja.AABB.prototype = {
*/ */
collideAABBVsTile: function (tile) { collideAABBVsTile: function (tile) {
var pos = this.pos; var dx = this.pos.x - tile.pos.x; // tile->obj delta
var c = tile; var px = (tile.xw + this.xw) - Math.abs(dx); // penetration depth in x
var tx = c.pos.x;
var ty = c.pos.y;
var txw = c.xw;
var tyw = c.yw;
var dx = pos.x - tx;//tile->obj delta
var px = (txw + this.xw) - Math.abs(dx);//penetration depth in x
if (0 < px) if (0 < px)
{ {
var dy = pos.y - ty;//tile->obj delta var dy = this.pos.y - tile.pos.y; // tile->obj delta
var py = (tyw + this.yw) - Math.abs(dy);//pen depth in y var py = (tile.yw + this.yw) - Math.abs(dy); // pen depth in y
if (0 < py) if (0 < py)
{ {
//object may be colliding with tile; call tile-specific collision function // Calculate projection vectors
//calculate projection vectors
if (px < py) if (px < py)
{ {
//project in x // Project in x
if (dx < 0) if (dx < 0)
{ {
//project to the left // Project to the left
px *= -1; px *= -1;
py = 0; py = 0;
} }
else else
{ {
//proj to right // Project to the right
py = 0; py = 0;
} }
} }
else else
{ {
//project in y // Project in y
if (dy < 0) if (dy < 0)
{ {
//project up // Project up
px = 0; px = 0;
py *= -1; py *= -1;
} }
else else
{ {
//project down // Project down
px = 0; px = 0;
} }
} }
return this.resolveTile(px, py, this, c); // Object may be colliding with tile; call tile-specific collision function
return this.resolveTile(px, py, this, tile);
} }
} }

View file

@ -94,12 +94,6 @@ Phaser.Physics.Ninja.Body = function (system, sprite, type, id, radius) {
*/ */
this.velocity = new Phaser.Point(); this.velocity = new Phaser.Point();
/**
* @property {boolean} skipQuadTree - If the Body is an irregular shape you can set this to true to avoid it being added to any QuadTrees.
* @default
*/
this.skipQuadTree = false;
/** /**
* @property {number} facing - A const reference to the direction the Body is traveling or facing. * @property {number} facing - A const reference to the direction the Body is traveling or facing.
* @default * @default
@ -107,7 +101,7 @@ Phaser.Physics.Ninja.Body = function (system, sprite, type, id, radius) {
this.facing = Phaser.NONE; this.facing = Phaser.NONE;
/** /**
* @property {boolean} immovable - An immovable Body will not receive any impacts from other bodies. * @property {boolean} immovable - An immovable Body will not receive any impacts from other bodies. Not fully implemented.
* @default * @default
*/ */
this.immovable = false; this.immovable = false;
@ -170,15 +164,6 @@ Phaser.Physics.Ninja.Body = function (system, sprite, type, id, radius) {
Phaser.Physics.Ninja.Body.prototype = { Phaser.Physics.Ninja.Body.prototype = {
/**
* Internal method.
*
* @method Phaser.Physics.Ninja.Body#updateBounds
* @protected
*/
updateBounds: function (centerX, centerY, scaleX, scaleY) {
},
/** /**
* Internal method. * Internal method.
* *
@ -207,9 +192,6 @@ Phaser.Physics.Ninja.Body.prototype = {
this.shape.collideWorldBounds(); this.shape.collideWorldBounds();
} }
this.speed = Math.sqrt(this.shape.velocity.x * this.shape.velocity.x + this.shape.velocity.y * this.shape.velocity.y);
this.angle = Math.atan2(this.shape.velocity.y, this.shape.velocity.x);
}, },
/** /**
@ -232,6 +214,24 @@ Phaser.Physics.Ninja.Body.prototype = {
this.sprite.y = this.shape.pos.y; this.sprite.y = this.shape.pos.y;
} }
if (this.velocity.x < 0)
{
this.facing = Phaser.LEFT;
}
else if (this.velocity.x > 0)
{
this.facing = Phaser.RIGHT;
}
if (this.velocity.y < 0)
{
this.facing = Phaser.UP;
}
else if (this.velocity.y > 0)
{
this.facing = Phaser.DOWN;
}
}, },
/** /**
@ -343,12 +343,20 @@ Phaser.Physics.Ninja.Body.prototype = {
}, },
/** /**
* Resets all Body values (velocity, acceleration, rotation, etc) * Resets all Body values and repositions on the Sprite.
* *
* @method Phaser.Physics.Ninja.Body#reset * @method Phaser.Physics.Ninja.Body#reset
*/ */
reset: function () { reset: function () {
},
this.velocity.set(0);
this.shape.pos.x = this.sprite.x;
this.shape.pos.y = this.sprite.y;
this.shape.oldpos.copyFrom(this.shape.pos);
}
}; };
@ -358,20 +366,10 @@ Phaser.Physics.Ninja.Body.prototype = {
*/ */
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "x", { Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "x", {
/**
* The x position.
* @method x
* @return {number}
*/
get: function () { get: function () {
return this.shape.pos.x; return this.shape.pos.x;
}, },
/**
* The x position.
* @method x
* @param {number} value
*/
set: function (value) { set: function (value) {
this.shape.pos.x = value; this.shape.pos.x = value;
} }
@ -384,20 +382,10 @@ Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "x", {
*/ */
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "y", { Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "y", {
/**
* The y position.
* @method y
* @return {number}
*/
get: function () { get: function () {
return this.shape.pos.y; return this.shape.pos.y;
}, },
/**
* The y position.
* @method y
* @param {number} value
*/
set: function (value) { set: function (value) {
this.shape.pos.y = value; this.shape.pos.y = value;
} }
@ -411,12 +399,6 @@ Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "y", {
*/ */
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "width", { Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "width", {
/**
* The width of this Body
* @method width
* @return {number}
* @readonly
*/
get: function () { get: function () {
return this.shape.width; return this.shape.width;
} }
@ -430,12 +412,6 @@ Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "width", {
*/ */
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "height", { Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "height", {
/**
* The height of this Body
* @method height
* @return {number}
* @readonly
*/
get: function () { get: function () {
return this.shape.height; return this.shape.height;
} }
@ -449,12 +425,6 @@ Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "height", {
*/ */
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "bottom", { Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "bottom", {
/**
* The sum of the y and height properties.
* @method bottom
* @return {number}
* @readonly
*/
get: function () { get: function () {
return this.shape.pos.y + this.shape.height; return this.shape.pos.y + this.shape.height;
} }
@ -468,14 +438,35 @@ Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "bottom", {
*/ */
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "right", { Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "right", {
/**
* The sum of the x and width properties.
* @method right
* @return {number}
* @readonly
*/
get: function () { get: function () {
return this.shape.pos.x + this.shape.width; return this.shape.pos.x + this.shape.width;
} }
}); });
/**
* @name Phaser.Physics.Ninja.Body#speed
* @property {number} speed - The speed of this Body
* @readonly
*/
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "speed", {
get: function () {
return Math.sqrt(this.shape.velocity.x * this.shape.velocity.x + this.shape.velocity.y * this.shape.velocity.y);
}
});
/**
* @name Phaser.Physics.Ninja.Body#angle
* @property {number} angle - The angle of this Body
* @readonly
*/
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "angle", {
get: function () {
return Math.atan2(this.shape.velocity.y, this.shape.velocity.x);
}
});

View file

@ -5,9 +5,22 @@
*/ */
/** /**
* Ninja Physics constructor. * Ninja Physics. The Ninja Physics system was created in Flash by Metanet Software and ported to JavaScript by Richard Davey.
* *
* The Ninja Physics system was created in Flash by Metanet Software and ported to JavaScript by Richard Davey. * It allows for AABB and Circle to Tile collision. Tiles can be any of 34 different types, including slopes, convex and concave shapes.
*
* It does what it does very well, but is ripe for expansion and optimisation. Here are some features that I'd love to see the community add:
*
* AABB to AABB collision
* AABB to Circle collision
* AABB and Circle 'immovable' property support
* n-way collision, so an AABB/Circle could pass through a tile from below and land upon it.
* QuadTree or spatial grid for faster Body vs. Tile Group look-ups.
* Optimise the internal vector math and reduce the quantity of temporary vars created.
* Expand Gravity and Bounce to allow for separate x/y axis values.
* Support Bodies linked to Sprites that don't have anchor set to 0.5
*
* Feel free to attempt any of the above and submit a Pull Request with your code! Be sure to include test cases proving they work.
* *
* @class Phaser.Physics.Ninja * @class Phaser.Physics.Ninja
* @classdesc Ninja Physics Constructor * @classdesc Ninja Physics Constructor
@ -51,12 +64,6 @@ Phaser.Physics.Ninja = function (game) {
*/ */
this.quadTree = new Phaser.QuadTree(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels); this.quadTree = new Phaser.QuadTree(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels);
/**
* @property {Array} _mapData - Internal cache var.
* @private
*/
this._mapData = [];
}; };
Phaser.Physics.Ninja.prototype.constructor = Phaser.Physics.Ninja; Phaser.Physics.Ninja.prototype.constructor = Phaser.Physics.Ninja;
@ -140,7 +147,7 @@ Phaser.Physics.Ninja.prototype = {
} }
else else
{ {
this.enableBody(object[i]); this.enableBody(object[i], type, id, radius);
if (children && object[i].hasOwnProperty('children') && object[i].children.length > 0) if (children && object[i].hasOwnProperty('children') && object[i].children.length > 0)
{ {
@ -158,7 +165,7 @@ Phaser.Physics.Ninja.prototype = {
} }
else else
{ {
this.enableBody(object); this.enableBody(object, type, id, radius);
if (children && object.hasOwnProperty('children') && object.children.length > 0) if (children && object.hasOwnProperty('children') && object.children.length > 0)
{ {