From 4cac6408d80eb522579b06fb098c311d33a23911 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Fri, 7 Mar 2014 04:43:55 +0000 Subject: [PATCH] Ninja.AABB updated with all the correct properties, now works fully as with Circle. Created new tests, all Ninja shapes now set Body.touching values correctly. TileSprites work as bodies. Trying out AABB vs. AABB collision now. --- README.md | 1 + examples/wip/ninja aabb vs aabb.js | 62 +++++ examples/wip/ninja tilesprite.js | 77 ++++++ examples/wip/ninja3.js | 1 - src/physics/ninja/AABB.js | 411 +++++++++++++++++++---------- src/physics/ninja/Body.js | 125 ++++++--- src/physics/ninja/Circle.js | 33 ++- src/physics/ninja/Tile.js | 117 +++++++- src/physics/ninja/World.js | 7 +- 9 files changed, 638 insertions(+), 196 deletions(-) create mode 100644 examples/wip/ninja aabb vs aabb.js create mode 100644 examples/wip/ninja tilesprite.js diff --git a/README.md b/README.md index b00b3007..92b7c791 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,7 @@ Updates: * Completely empty Tilemaps can now be created. This allows for dynamic map generation at runtime. * Keyboard.event now stores the most recent DOM keyboard event. * Animation.stop has a new parameter: dispatchComplete. If true it'll dispatch an Animation.onComplete event. +* TileSprites now have a physics body property and call it in the pre and post updates. As with all physics bodies it's null by default. Bug Fixes: diff --git a/examples/wip/ninja aabb vs aabb.js b/examples/wip/ninja aabb vs aabb.js new file mode 100644 index 00000000..88bc348f --- /dev/null +++ b/examples/wip/ninja aabb vs aabb.js @@ -0,0 +1,62 @@ + +// var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('block', 'assets/sprites/block.png'); + +} + +var sprite1; +var sprite2; +var cursors; + +function create() { + + game.physics.startSystem(Phaser.Physics.NINJA); + + sprite1 = game.add.sprite(100, 100, 'block'); + sprite2 = game.add.sprite(400, 100, 'block'); + + // game.physics.ninja.enableAABB([sprite1]); + game.physics.ninja.enableAABB([sprite1, sprite2]); + + cursors = game.input.keyboard.createCursorKeys(); + +} + +function update() { + + game.physics.ninja.collide(sprite1, sprite2); + + if (cursors.left.isDown) + { + sprite1.body.moveLeft(20); + } + else if (cursors.right.isDown) + { + sprite1.body.moveRight(20); + } + + // if (cursors.up.isDown && sprite1.body.touching.down) + if (cursors.up.isDown) + { + // sprite1.body.moveUp(1000); + sprite1.body.moveUp(30); + } + // else if (cursors.down.isDown) + // { + // sprite1.body.moveDown(20); + // } + +} + +function render() { + + game.debug.text('left: ' + sprite1.body.touching.left, 32, 32); + game.debug.text('right: ' + sprite1.body.touching.right, 256, 32); + game.debug.text('up: ' + sprite1.body.touching.up, 32, 64); + game.debug.text('down: ' + sprite1.body.touching.down, 256, 64); + +} diff --git a/examples/wip/ninja tilesprite.js b/examples/wip/ninja tilesprite.js new file mode 100644 index 00000000..d15e0070 --- /dev/null +++ b/examples/wip/ninja tilesprite.js @@ -0,0 +1,77 @@ + +// var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('starfield', 'assets/misc/starfield.jpg'); + game.load.image('ball', 'assets/sprites/shinyball.png'); + +} + +var ball; +var sprite; +var cursors; + +function create() { + + game.physics.startSystem(Phaser.Physics.NINJA); + + sprite = game.add.tileSprite(100, 100, 200, 200, 'starfield'); + sprite.autoScroll(0, 100); + + game.physics.ninja.enableAABB(sprite); + // game.physics.ninja.enableTile(sprite, 14); + + // By default Tiles have gravity and world collision disabled (as they are mostly used for platforms and the likes) + // We re-enable it here + // sprite.body.gravityScale = 1; + // sprite.body.collideWorldBounds = true; + + ball = game.add.sprite(400, 0, 'ball'); + + // Enable the physics body for the Ninja physics system + game.physics.ninja.enableCircle(ball, ball.width / 2); + + // A little more bounce + ball.body.bounce = 0.5; + + cursors = game.input.keyboard.createCursorKeys(); + +} + +function update() { + + game.physics.ninja.collide(sprite, ball); + + if (cursors.left.isDown) + { + sprite.body.moveLeft(20); + } + else if (cursors.right.isDown) + { + sprite.body.moveRight(20); + } + + if (cursors.up.isDown) + { + sprite.body.moveUp(20); + } + else if (cursors.down.isDown) + { + sprite.body.moveDown(20); + } + +} + +function render() { + + var r = new Phaser.Rectangle(sprite.body.x - (sprite.body.width / 2), sprite.body.y - (sprite.body.height / 2), sprite.body.width, sprite.body.height); + + // game.debug.text(sprite.body.x, 32, 32); + // game.debug.text(sprite.body.y, 32, 64); + // game.debug.text(sprite.body.width, 128, 32); + // game.debug.text(sprite.body.height, 128, 64); + // game.debug.geom(r, 'rgba(0,255,0,0.4)', true); + +} diff --git a/examples/wip/ninja3.js b/examples/wip/ninja3.js index 06a3fa48..608e5154 100644 --- a/examples/wip/ninja3.js +++ b/examples/wip/ninja3.js @@ -15,7 +15,6 @@ var sprite1; var tiles; var cursors; - function create() { var sky = game.add.image(0, 0, 'sky'); diff --git a/src/physics/ninja/AABB.js b/src/physics/ninja/AABB.js index 6010ebf0..be774d72 100644 --- a/src/physics/ninja/AABB.js +++ b/src/physics/ninja/AABB.js @@ -11,40 +11,80 @@ * @class Phaser.Physics.Ninja.AABB * @classdesc Arcade Physics Constructor * @constructor -* @param {Phaser.Physics.Ninja} system - A reference to the physics system. +* @param {Phaser.Physics.Ninja.Body} body - The body that owns this shape. * @param {number} x - The x coordinate to create this shape at. * @param {number} y - The y coordinate to create this shape at. * @param {number} width - The width of this AABB. * @param {number} height - The height of this AABB. */ -Phaser.Physics.Ninja.AABB = function (system, x, y, width, height) { +Phaser.Physics.Ninja.AABB = function (body, x, y, width, height) { - this.system = system; + /** + * @property {Phaser.Physics.Ninja.Body} system - A reference to the body that owns this shape. + */ + this.body = body; + + /** + * @property {Phaser.Physics.Ninja} system - A reference to the physics system. + */ + this.system = body.system; + + /** + * @property {Phaser.Point} pos - The position of this object. + */ this.pos = new Phaser.Point(x, y); + + /** + * @property {Phaser.Point} oldpos - The position of this object in the previous update. + */ this.oldpos = new Phaser.Point(x, y); + /** + * @property {number} xw - Half the width. + * @readonly + */ this.xw = Math.abs(width / 2); + + /** + * @property {number} xw - Half the height. + * @readonly + */ this.yw = Math.abs(height / 2); + /** + * @property {number} width - The width. + * @readonly + */ this.width = width; + + /** + * @property {number} height - The height. + * @readonly + */ this.height = height; + /** + * @property {number} oH - Internal var. + * @private + */ this.oH = 0; + + /** + * @property {number} oV - Internal var. + * @private + */ this.oV = 0; - // Setting drag to 0 and friction to 0 means you get a normalised speed (px psec) - this.drag = 1; - this.friction = 0.05; - this.gravityScale = 1; - this.bounce = 0.3; + /** + * @property {Phaser.Point} velocity - The velocity of this object. + */ this.velocity = new Phaser.Point(); - // temp collision values - this.px = 0; - this.py = 0; - - // collision mappings + /** + * @property {object} aabbTileProjections - All of the collision response handlers. + */ this.aabbTileProjections = {}; + this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_FULL] = this.projAABB_Full; this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_45DEG] = this.projAABB_45Deg; this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_CONCAVE] = this.projAABB_Concave; @@ -76,8 +116,12 @@ Phaser.Physics.Ninja.AABB.prototype = { var py = this.pos.y; // integrate - this.pos.x += (this.drag * this.pos.x) - (this.drag * this.oldpos.x); - this.pos.y += (this.drag * this.pos.y) - (this.drag * this.oldpos.y) + (this.system.gravity * this.gravityScale); + // this.pos.x += (this.body.drag * this.pos.x) - (this.body.drag * this.oldpos.x); + // this.pos.y += (this.body.drag * this.pos.y) - (this.body.drag * this.oldpos.y) + (this.system.gravity * this.body.gravityScale); + + this.pos.x += (this.body.drag * this.pos.x) - (this.body.drag * this.oldpos.x); + this.pos.y += (this.body.drag * this.pos.y) - (this.body.drag * this.oldpos.y) + (this.system.gravity * this.body.gravityScale); + // store this.velocity.set(this.pos.x - px, this.pos.y - py); @@ -100,48 +144,247 @@ Phaser.Physics.Ninja.AABB.prototype = { var p = this.pos; var o = this.oldpos; - //calc velocity + // Calc velocity var vx = p.x - o.x; var vy = p.y - o.y; - //find component of velocity parallel to collision normal + // Find component of velocity parallel to collision normal var dp = (vx * dx + vy * dy); - var nx = dp * dx;//project velocity onto collision normal + var nx = dp * dx; //project velocity onto collision normal - var ny = dp * dy;//nx,ny is normal velocity + var ny = dp * dy; //nx,ny is normal velocity - var tx = vx - nx;//px,py is tangent velocity + var tx = vx - nx; //px,py is tangent velocity var ty = vy - ny; - //we only want to apply collision response forces if the object is travelling into, and not out of, the collision - var b, bx, by, f, fx, fy; + // We only want to apply collision response forces if the object is travelling into, and not out of, the collision + var b, bx, by, fx, fy; if (dp < 0) { - //f = FRICTION; - fx = tx * this.friction; - fy = ty * this.friction; + fx = tx * this.body.friction; + fy = ty * this.body.friction; - b = 1 + this.bounce; + b = 1 + this.body.bounce; bx = (nx * b); by = (ny * b); + if (dx === 1) + { + this.body.touching.left = true; + } + else if (dx === -1) + { + this.body.touching.right = true; + } + + if (dy === 1) + { + this.body.touching.up = true; + } + else if (dy === -1) + { + this.body.touching.down = true; + } } else { - //moving out of collision, do not apply forces + // Moving out of collision, do not apply forces bx = by = fx = fy = 0; } - p.x += px;//project object out of collision + // Project object out of collision + p.x += px; p.y += py; - o.x += px + bx + fx;//apply bounce+friction impulses which alter velocity + // Apply bounce+friction impulses which alter velocity + o.x += px + bx + fx; o.y += py + by + fy; }, + /** + * Process a body collision and apply the resulting forces. + * + * @method Phaser.Physics.Ninja.AABB#reportCollisionVsBody + * @param {number} px - The tangent velocity + * @param {number} py - The tangent velocity + * @param {number} dx - Collision normal + * @param {number} dy - Collision normal + * @param {number} obj - Object this AABB collided with + */ + reportCollisionVsBody: function (px, py, dx, dy, obj) { + + var p = this.pos; + var o = this.oldpos; + + // Calc velocity + var vx = p.x - o.x; + var vy = p.y - o.y; + + // Find component of velocity parallel to collision normal + var dp = (vx * dx + vy * dy); + var nx = dp * dx; //project velocity onto collision normal + + var ny = dp * dy; //nx,ny is normal velocity + + var tx = vx - nx; //px,py is tangent velocity + var ty = vy - ny; + + // We only want to apply collision response forces if the object is travelling into, and not out of, the collision + var b, bx, by, fx, fy; + + if (dp < 0) + { + fx = tx * this.body.friction; + fy = ty * this.body.friction; + + b = 1 + this.body.bounce; + + bx = (nx * b); + by = (ny * b); + } + else + { + // Moving out of collision, do not apply forces + bx = by = fx = fy = 0; + } + + // Project object out of collision + p.x += px; + p.y += py; + + // Apply bounce+friction impulses which alter velocity + o.x += px + bx + fx; + o.y += py + by + fy; + + // apply to obj + if (obj) + { + // obj.oldpos.x = + // console.log('reportCollisionVsBody'); + // obj.reportCollisionVsBody(px *= -1, py *= -1, dx *= -1, dy *= -1, null); + } + + }, + + /** + * Collides this AABB against the world bounds. + * + * @method Phaser.Physics.Ninja.AABB#collideWorldBounds + */ + collideWorldBounds: function () { + + var dx = this.system.bounds.x - (this.pos.x - this.xw); + + if (0 < dx) + { + this.reportCollisionVsWorld(dx, 0, 1, 0, null); + } + else + { + dx = (this.pos.x + this.xw) - this.system.bounds.width; + + if (0 < dx) + { + this.reportCollisionVsWorld(-dx, 0, -1, 0, null); + } + } + + var dy = this.system.bounds.y - (this.pos.y - this.yw); + + if (0 < dy) + { + this.reportCollisionVsWorld(0, dy, 0, 1, null); + } + else + { + dy = (this.pos.y + this.yw) - this.system.bounds.height; + + if (0 < dy) + { + this.reportCollisionVsWorld(0, -dy, 0, -1, null); + } + } + + }, + + /** + * Collides this AABB against a AABB. + * + * @method Phaser.Physics.Ninja.AABB#collideAABBVsAABB + * @param {Phaser.Physics.Ninja.AABB} aabb - The AABB to collide against. + */ + collideAABBVsAABB: function (aabb) { + + var pos = this.pos; + var c = aabb; + + 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) + { + var dy = pos.y - ty;//tile->obj delta + var py = (tyw + this.yw) - Math.abs(dy);//pen depth in y + + if (0 < py) + { + //object may be colliding with tile; call tile-specific collision function + + //calculate projection vectors + if (px < py) + { + //project in x + if (dx < 0) + { + //project to the left + px *= -1; + py = 0; + } + else + { + //proj to right + py = 0; + } + } + else + { + //project in y + if (dy < 0) + { + //project up + px = 0; + py *= -1; + } + else + { + //project down + px = 0; + } + } + + // return this.aabbTileProjections[1](px, py, this, c); + + 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); + + return Phaser.Physics.Ninja.AABB.COL_AXIS; + + } + } + + return false; + + }, + /** * Collides this AABB against a Tile. * @@ -210,114 +453,6 @@ Phaser.Physics.Ninja.AABB.prototype = { }, - /** - * Collides this AABB against the world bounds. - * - * @method Phaser.Physics.Ninja.AABB#collideWorldBounds - */ - collideWorldBounds: function () { - - var p = this.pos; - var xw = this.xw; - var yw = this.yw; - - var XMIN = this.system.bounds.x; - var XMAX = this.system.bounds.width; - var YMIN = this.system.bounds.y; - var YMAX = this.system.bounds.height; - - var dx = this.system.bounds.x - (this.pos.x - this.xw); - - if (0 < dx) - { - this.reportCollisionVsWorld(dx, 0, 1, 0, null); - } - else - { - dx = (this.pos.x + this.xw) - this.system.bounds.width; - - if (0 < dx) - { - this.reportCollisionVsWorld(-dx, 0, -1, 0, null); - } - } - - var dy = this.system.bounds.y - (this.pos.y - this.yw); - - if (0 < dy) - { - this.reportCollisionVsWorld(0, dy, 0, 1, null); - } - else - { - dy = (this.pos.y + this.yw) - this.system.bounds.height; - - if (0 < dy) - { - this.reportCollisionVsWorld(0, -dy, 0, -1, null); - } - } - - }, - - /** - * Renders this AABB to the context. - * - * @method Phaser.Physics.Ninja.AABB#render - */ - render: function (context) { - - context.beginPath(); - context.strokeStyle = 'rgb(0,255,0)'; - context.strokeRect(this.pos.x - this.xw, this.pos.y - this.yw, this.xw * 2, this.yw * 2); - context.stroke(); - context.closePath(); - - context.fillStyle = 'rgb(0,255,0)'; - context.fillRect(this.pos.x, this.pos.y, 2, 2); - - /* - if (this.oH == 1) - { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius); - context.lineTo(this.pos.x - this.radius, this.pos.y + this.radius); - context.stroke(); - context.closePath(); - } - else if (this.oH == -1) - { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.pos.x + this.radius, this.pos.y - this.radius); - context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius); - context.stroke(); - context.closePath(); - } - - if (this.oV == 1) - { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius); - context.lineTo(this.pos.x + this.radius, this.pos.y - this.radius); - context.stroke(); - context.closePath(); - } - else if (this.oV == -1) - { - context.beginPath(); - context.strokeStyle = 'rgb(255,0,0)'; - context.moveTo(this.pos.x - this.radius, this.pos.y + this.radius); - context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius); - context.stroke(); - context.closePath(); - } - */ - - }, - /** * Resolves tile collision. * @@ -336,7 +471,7 @@ Phaser.Physics.Ninja.AABB.prototype = { } else { - console.warn("Ninja.AABB.resolveTile was called with an empty (or unknown) tile!: id=" + tile.id + ")"); + // console.warn("Ninja.AABB.resolveTile was called with an empty (or unknown) tile!: id=" + tile.id + ")"); return false; } diff --git a/src/physics/ninja/Body.js b/src/physics/ninja/Body.js index 75e2ab33..d769b440 100644 --- a/src/physics/ninja/Body.js +++ b/src/physics/ninja/Body.js @@ -63,35 +63,6 @@ Phaser.Physics.Ninja.Body = function (system, sprite, type, id, radius) { */ this.shape = null; - var sx = sprite.x; - var sy = sprite.y; - - if (sprite.anchor.x === 0) - { - sx += (sprite.width * 0.5); - } - - if (sprite.anchor.y === 0) - { - sy += (sprite.height * 0.5); - } - - if (type === 1) - { - this.aabb = new Phaser.Physics.Ninja.AABB(this, sx, sy, sprite.width, sprite.height); - this.shape = this.aabb; - } - else if (type === 2) - { - this.circle = new Phaser.Physics.Ninja.Circle(this, sx, sy, radius); - this.shape = this.circle; - } - else if (type === 3) - { - this.tile = new Phaser.Physics.Ninja.Tile(this, sx, sy, sprite.width, sprite.height, id); - this.shape = this.tile; - } - // Setting drag to 0 and friction to 0 means you get a normalised speed (px psec) /** @@ -160,8 +131,41 @@ Phaser.Physics.Ninja.Body = function (system, sprite, type, id, radius) { */ this.wasTouching = { none: true, up: false, down: false, left: false, right: false }; + /** + * @property {number} maxSpeed - The maximum speed this body can travel at (taking drag and friction into account) + * @default + */ this.maxSpeed = 8; + var sx = sprite.x; + var sy = sprite.y; + + if (sprite.anchor.x === 0) + { + sx += (sprite.width * 0.5); + } + + if (sprite.anchor.y === 0) + { + sy += (sprite.height * 0.5); + } + + if (type === 1) + { + this.aabb = new Phaser.Physics.Ninja.AABB(this, sx, sy, sprite.width, sprite.height); + this.shape = this.aabb; + } + else if (type === 2) + { + this.circle = new Phaser.Physics.Ninja.Circle(this, sx, sy, radius); + this.shape = this.circle; + } + else if (type === 3) + { + this.tile = new Phaser.Physics.Ninja.Tile(this, sx, sy, sprite.width, sprite.height, id); + this.shape = this.tile; + } + }; Phaser.Physics.Ninja.Body.prototype = { @@ -173,18 +177,6 @@ Phaser.Physics.Ninja.Body.prototype = { * @protected */ updateBounds: function (centerX, centerY, scaleX, scaleY) { - - if (scaleX != this._sx || scaleY != this._sy) - { - // this.width = this.sourceWidth * scaleX; - // this.height = this.sourceHeight * scaleY; - // this.halfWidth = Math.floor(this.width / 2); - // this.halfHeight = Math.floor(this.height / 2); - // this._sx = scaleX; - // this._sy = scaleY; - // this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); - } - }, /** @@ -228,8 +220,17 @@ Phaser.Physics.Ninja.Body.prototype = { */ postUpdate: function () { - this.sprite.x = this.shape.pos.x; - this.sprite.y = this.shape.pos.y; + if (this.sprite.type === Phaser.TILESPRITE) + { + // TileSprites don't use their anchor property, so we need to adjust the coordinates + this.sprite.x = this.shape.pos.x - this.shape.xw; + this.sprite.y = this.shape.pos.y - this.shape.yw; + } + else + { + this.sprite.x = this.shape.pos.x; + this.sprite.y = this.shape.pos.y; + } }, @@ -403,6 +404,44 @@ Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "y", { }); +/** +* @name Phaser.Physics.Ninja.Body#width +* @property {number} width - The width of this Body +* @readonly +*/ +Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "width", { + + /** + * The width of this Body + * @method width + * @return {number} + * @readonly + */ + get: function () { + return this.shape.width; + } + +}); + +/** +* @name Phaser.Physics.Ninja.Body#height +* @property {number} height - The height of this Body +* @readonly +*/ +Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "height", { + + /** + * The height of this Body + * @method height + * @return {number} + * @readonly + */ + get: function () { + return this.shape.height; + } + +}); + /** * @name Phaser.Physics.Ninja.Body#bottom * @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height) diff --git a/src/physics/ninja/Circle.js b/src/physics/ninja/Circle.js index 9c31a257..92af178d 100644 --- a/src/physics/ninja/Circle.js +++ b/src/physics/ninja/Circle.js @@ -158,6 +158,23 @@ Phaser.Physics.Ninja.Circle.prototype = { bx = (nx * b); by = (ny * b); + if (dx === 1) + { + this.body.touching.left = true; + } + else if (dx === -1) + { + this.body.touching.right = true; + } + + if (dy === 1) + { + this.body.touching.up = true; + } + else if (dy === -1) + { + this.body.touching.down = true; + } } else { @@ -182,15 +199,7 @@ Phaser.Physics.Ninja.Circle.prototype = { */ collideWorldBounds: function () { - var p = this.pos; - var r = this.radius; - - var XMIN = this.system.bounds.x; - var XMAX = this.system.bounds.width; - var YMIN = this.system.bounds.y; - var YMAX = this.system.bounds.height; - - var dx = this.system.bounds.x - (this.pos.x - this.radius); + var dx = this.system.bounds.x - (this.pos.x - this.xw); if (0 < dx) { @@ -198,7 +207,7 @@ Phaser.Physics.Ninja.Circle.prototype = { } else { - dx = (this.pos.x + this.radius) - this.system.bounds.width; + dx = (this.pos.x + this.xw) - this.system.bounds.width; if (0 < dx) { @@ -206,7 +215,7 @@ Phaser.Physics.Ninja.Circle.prototype = { } } - var dy = this.system.bounds.y - (this.pos.y - this.radius); + var dy = this.system.bounds.y - (this.pos.y - this.yw); if (0 < dy) { @@ -214,7 +223,7 @@ Phaser.Physics.Ninja.Circle.prototype = { } else { - dy = (this.pos.y + this.radius) - this.system.bounds.height; + dy = (this.pos.y + this.yw) - this.system.bounds.height; if (0 < dy) { diff --git a/src/physics/ninja/Tile.js b/src/physics/ninja/Tile.js index 12a0d628..cf2dcf0d 100644 --- a/src/physics/ninja/Tile.js +++ b/src/physics/ninja/Tile.js @@ -6,6 +6,9 @@ /** * Ninja Physics Tile constructor. +* A Tile is defined by its width, height and type. It's type can include slope data, such as 45 degree slopes, or convex slopes. +* Understand that for any type including a slope (types 2 to 29) the Tile must be SQUARE, i.e. have an equal width and height. +* Also note that as Tiles are primarily used for levels they have gravity disabled and world bounds collision disabled by default. * * Note: This class could be massively optimised and reduced in size. I leave that challenge up to you. * @@ -114,6 +117,10 @@ Phaser.Physics.Ninja.Tile = function (body, x, y, width, height, type) { */ this.sy = 0; + // By default Tiles disable gravity and world bounds collision + this.body.gravityScale = 0; + this.body.collideWorldBounds = false; + if (this.id > 0) { this.setType(this.id); @@ -136,7 +143,7 @@ Phaser.Physics.Ninja.Tile.prototype = { var py = this.pos.y; this.pos.x += (this.body.drag * this.pos.x) - (this.body.drag * this.oldpos.x); - this.pos.y += (this.body.drag * this.pos.y) - (this.body.drag * this.oldpos.y); + this.pos.y += (this.body.drag * this.pos.y) - (this.body.drag * this.oldpos.y) + (this.system.gravity * this.body.gravityScale); this.velocity.set(this.pos.x - px, this.pos.y - py); this.oldpos.set(px, py); @@ -149,6 +156,114 @@ Phaser.Physics.Ninja.Tile.prototype = { * @method Phaser.Physics.Ninja.Tile#collideWorldBounds */ collideWorldBounds: function () { + + var dx = this.system.bounds.x - (this.pos.x - this.xw); + + if (0 < dx) + { + this.reportCollisionVsWorld(dx, 0, 1, 0, null); + } + else + { + dx = (this.pos.x + this.xw) - this.system.bounds.width; + + if (0 < dx) + { + this.reportCollisionVsWorld(-dx, 0, -1, 0, null); + } + } + + var dy = this.system.bounds.y - (this.pos.y - this.yw); + + if (0 < dy) + { + this.reportCollisionVsWorld(0, dy, 0, 1, null); + } + else + { + dy = (this.pos.y + this.yw) - this.system.bounds.height; + + if (0 < dy) + { + this.reportCollisionVsWorld(0, -dy, 0, -1, null); + } + } + + }, + + /** + * Process a world collision and apply the resulting forces. + * + * @method Phaser.Physics.Ninja.Tile#reportCollisionVsWorld + * @param {number} px - The tangent velocity + * @param {number} py - The tangent velocity + * @param {number} dx - Collision normal + * @param {number} dy - Collision normal + * @param {number} obj - Object this Tile collided with + */ + reportCollisionVsWorld: function (px, py, dx, dy, obj) { + + var p = this.pos; + var o = this.oldpos; + + // Calc velocity + var vx = p.x - o.x; + var vy = p.y - o.y; + + // Find component of velocity parallel to collision normal + var dp = (vx * dx + vy * dy); + var nx = dp * dx; //project velocity onto collision normal + + var ny = dp * dy; //nx,ny is normal velocity + + var tx = vx - nx; //px,py is tangent velocity + var ty = vy - ny; + + // We only want to apply collision response forces if the object is travelling into, and not out of, the collision + var b, bx, by, fx, fy; + + if (dp < 0) + { + fx = tx * this.body.friction; + fy = ty * this.body.friction; + + b = 1 + this.body.bounce; + + bx = (nx * b); + by = (ny * b); + + if (dx === 1) + { + this.body.touching.left = true; + } + else if (dx === -1) + { + this.body.touching.right = true; + } + + if (dy === 1) + { + this.body.touching.up = true; + } + else if (dy === -1) + { + this.body.touching.down = true; + } + } + else + { + // Moving out of collision, do not apply forces + bx = by = fx = fy = 0; + } + + // Project object out of collision + p.x += px; + p.y += py; + + // Apply bounce+friction impulses which alter velocity + o.x += px + bx + fx; + o.y += py + by + fy; + }, /** diff --git a/src/physics/ninja/World.js b/src/physics/ninja/World.js index 0a10d537..d6aee8d9 100644 --- a/src/physics/ninja/World.js +++ b/src/physics/ninja/World.js @@ -457,7 +457,12 @@ Phaser.Physics.Ninja.prototype = { if (body1.type !== Phaser.Physics.NINJA || body2.type !== Phaser.Physics.NINJA) { - return; + return false; + } + + if (body1.aabb && body2.aabb) + { + return body1.aabb.collideAABBVsAABB(body2.aabb); } if (body1.aabb && body2.tile)