diff --git a/examples/wip/2ball.js b/examples/wip/2ball.js index a94f829b..ee60ee69 100644 --- a/examples/wip/2ball.js +++ b/examples/wip/2ball.js @@ -14,6 +14,7 @@ function preload() { var sprite; var sprite2; var sprite3; +var group; var bmd; @@ -30,24 +31,60 @@ function create() { } +function test4() { + + game.physics.gravity.y = 50; + + sprite = game.add.sprite(300, 0, 'gameboy', 0); + sprite.name = 'red'; + sprite.body.collideWorldBounds = true; + sprite.body.bounce.setTo(0.9, 0.9); + + sprite2 = game.add.sprite(310, 500, 'gameboy', 2); + sprite2.name = 'green'; + sprite2.body.collideWorldBounds = true; + // sprite2.body.bounce.setTo(0.9, 0.9); + + game.input.onDown.add(launch4, this); + +} + +function launch4() { + + sprite.body.velocity.y = 200; + +} + function test3() { - // game.physics.gravity.y = 100; + game.physics.gravity.y = 50; + + // group = game.add.group(); sprite = game.add.sprite(500, 400, 'gameboy', 0); sprite.name = 'red'; sprite.body.collideWorldBounds = true; - sprite.body.bounce.setTo(0.5, 0.5); + sprite.body.bounce.setTo(0.9, 0.9); - sprite2 = game.add.sprite(0, 400, 'gameboy', 2); + sprite2 = game.add.sprite(100, 400, 'gameboy', 2); sprite2.name = 'green'; sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.9, 0.9); + + // sprite2.body.immovable = true; + // sprite2.body.bounce.setTo(0.5, 0.5); sprite3 = game.add.sprite(700, 400, 'gameboy', 3); sprite3.name = 'yellow'; sprite3.body.collideWorldBounds = true; + sprite3.body.bounce.setTo(0.5, 0.5); - sprite.body.velocity.x = -300; + // sprite.body.velocity.x = -300; + // sprite.body.velocity.y = -200; + + // group.add(sprite); + // group.add(sprite2); + // group.add(sprite3); game.input.onDown.add(launch3, this); @@ -55,7 +92,8 @@ function test3() { function launch3() { - sprite.body.velocity.x *= 10; + sprite.body.velocity.x = -200; + sprite.body.velocity.y = -200; } @@ -116,11 +154,18 @@ function launch1() { function update() { - // game.physics.collide(sprite, sprite2); - // game.physics.collide(sprite2, sprite3); - game.physics.collideArray(sprite, [sprite2, sprite3]); + // game.physics.collide(group, group); + + if (sprite3) + { + game.physics.collideArray(sprite, [sprite2, sprite3]); + game.physics.collide(sprite2, sprite3); + } + else + { + game.physics.collide(sprite, sprite2); + } - // sprite.rotation = sprite.body.angle; if (sprite) { @@ -134,6 +179,12 @@ function update() { bmd.fillRect(sprite2.body.center.x, sprite2.body.center.y, 2, 2); } + if (sprite3) + { + bmd.fillStyle('#0000ff'); + bmd.fillRect(sprite3.body.center.x, sprite3.body.center.y, 2, 2); + } + } function render() { diff --git a/examples/wip/SAT.js b/examples/wip/SAT.js index 18040b9c..63570ece 100644 --- a/examples/wip/SAT.js +++ b/examples/wip/SAT.js @@ -95,6 +95,20 @@ return this; }; + // Rotate this vector (counter-clockwise) by the specified angle (in radians) which has already been calculated into sin and cos. + /** + * @param {number} sin - The Math.sin(angle) + * @param {number} cos - The Math.cos(angle) + * @return {Vector} This for chaining. + */ + Vector.prototype['rotatePrecalc'] = Vector.prototype.rotatePrecalc = function (sin, cos) { + var x = this['x']; + var y = this['y']; + this['x'] = x * cos - y * sin; + this['y'] = x * sin + y * cos; + return this; + }; + // Reverse this vector. /** * @return {Vector} This for chaining. @@ -318,10 +332,36 @@ var edges = this['edges']; var normals = this['normals']; var len = points.length; + + // Calc it just the once, rather than 4 times per array element + var cos = Math.cos(angle); + var sin = Math.sin(angle); + for (i = 0; i < len; i++) { - points[i].rotate(angle); - edges[i].rotate(angle); - normals[i].rotate(angle); + points[i].rotatePrecalc(sin, cos); + edges[i].rotatePrecalc(sin, cos); + normals[i].rotatePrecalc(sin, cos); + } + return this; + }; + + // Rotates this polygon counter-clockwise around the origin of *its local coordinate system* (i.e. `pos`). + // + // Note: You do **not** need to call `recalc` after rotation. + /** + * @param {number} angle The angle to rotate (in radians) + * @return {Polygon} This for chaining. + */ + Polygon.prototype['scale'] = Polygon.prototype.scale = function(x, y) { + var i; + var points = this['points']; + var edges = this['edges']; + var normals = this['normals']; + var len = points.length; + for (i = 0; i < len; i++) { + points[i].scale(x,y); + edges[i].scale(x,y); + normals[i].scale(x,y); } return this; }; diff --git a/examples/wip/group offset.js b/examples/wip/group offset.js new file mode 100644 index 00000000..02e59bff --- /dev/null +++ b/examples/wip/group offset.js @@ -0,0 +1,38 @@ +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, render: render }); + +function preload() { + + // game.load.image('atari1', 'assets/sprites/atari130xe.png'); + // game.load.image('atari2', 'assets/sprites/atari800xl.png'); + // game.load.image('atari4', 'assets/sprites/atari800.png'); + // game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + // game.load.image('duck', 'assets/sprites/darkwing_crazy.png'); + // game.load.image('firstaid', 'assets/sprites/firstaid.png'); + // game.load.image('diamond', 'assets/sprites/diamond.png'); + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + +} + +var group; +var sprite; + +function create() { + + var images = game.cache.getImageKeys(); + + group = game.add.group(); + + // for (var i = 0; i < 20; i++) + // { + sprite = group.create(200, game.world.randomY, game.rnd.pick(images)); + // } + + group.x = 200; + +} + +function render() { + + game.debug.renderText('sx: ' + sprite.x + ' wx: ' + sprite.world.x, 32, 32); + +} \ No newline at end of file diff --git a/examples/wip/index.php b/examples/wip/index.php index d7afdd8e..58a4a658 100644 --- a/examples/wip/index.php +++ b/examples/wip/index.php @@ -85,7 +85,6 @@ $f = $_GET['f']; ?> - diff --git a/examples/wip/multiball.js b/examples/wip/multiball.js index cd0c9c9e..314d31c2 100644 --- a/examples/wip/multiball.js +++ b/examples/wip/multiball.js @@ -5,9 +5,11 @@ function preload() { game.load.image('arrow', 'assets/sprites/asteroids_ship.png'); game.load.image('ball', 'assets/sprites/shinyball.png'); + game.load.spritesheet('gameboy', 'assets/sprites/gameboy_seize_color_40x60.png', 40, 60); } +var gameboy; var sprites; var bmd; @@ -24,23 +26,34 @@ function create() { sprites = game.add.group(); - for (var i = 0; i < 50; i++) + for (var i = 0; i < 100; i++) { var s = sprites.create(game.rnd.integerInRange(100, 700), game.rnd.integerInRange(32, 200), 'ball'); s.body.velocity.x = game.rnd.integerInRange(-400, 400); s.body.velocity.y = game.rnd.integerInRange(-200, 200); + s.name = 'ball' + i; } sprites.setAll('body.collideWorldBounds', true); - sprites.setAll('body.bounce.x', 0.8); - sprites.setAll('body.bounce.y', 0.8); + sprites.setAll('body.bounce.x', 0.9); + sprites.setAll('body.bounce.y', 0.9); sprites.setAll('body.minBounceVelocity', 0.8); + console.log(sprites._container.children); + + gameboy = game.add.sprite(300, 50, 'gameboy', 0); + gameboy.name = 'gameboy'; + gameboy.body.collideWorldBounds = true; + gameboy.body.bounce.setTo(0.9, 0.9); + gameboy.body.velocity.x = game.rnd.integerInRange(-400, 400); + gameboy.body.velocity.y = game.rnd.integerInRange(-200, 200); + } function update() { - // game.physics.collide(sprites, sprites); + // game.physics.collide(gameboy, sprites); + game.physics.collide(sprites); // sprite.rotation = sprite.body.angle; diff --git a/examples/wip/sat1.js b/examples/wip/sat1.js index 801fcee3..803079d7 100644 --- a/examples/wip/sat1.js +++ b/examples/wip/sat1.js @@ -21,8 +21,7 @@ var r; function create() { - // game.stage.backgroundColor = '#124184'; - game.stage.backgroundColor = '#000'; + game.stage.backgroundColor = '#124184'; test1(); @@ -38,9 +37,21 @@ function create() { function test1() { sprite = game.add.sprite(500, 400, 'gameboy', 0); + // sprite = game.add.sprite(0, 0, 'gameboy', 0); sprite.name = 'red'; + // sprite.pivot.x = 20; + // sprite.pivot.y = 30; + // sprite.anchor.setTo(0.5, 0.5); + + // sprite.body.polygon.translate(20, 20); + + // sprite.body.polygon.rotate(game.math.degToRad(45)); + // sprite.angle = 45; + + // sprite.scale.setTo(2, 2); + // sprite.body.polygon.scale(2, 2); + sprite.body.bounce.x = 0.8; - // sprite.body = null; sprite2 = game.add.sprite(0, 400, 'gameboy', 2); sprite2.name = 'green'; @@ -50,13 +61,13 @@ function test1() { sprite3.name = 'yellow'; // sprite3.body = null; - b1 = new SAT.Box(new SAT.Vector(sprite.x, sprite.y), sprite.width, sprite.height); - b2 = new SAT.Box(new SAT.Vector(sprite2.x, sprite2.y), sprite2.width, sprite2.height); - b3 = new SAT.Box(new SAT.Vector(sprite3.x, sprite3.y), sprite3.width, sprite3.height); + // b1 = new SAT.Box(new SAT.Vector(sprite.x, sprite.y), sprite.width, sprite.height); + // b2 = new SAT.Box(new SAT.Vector(sprite2.x, sprite2.y), sprite2.width, sprite2.height); + // b3 = new SAT.Box(new SAT.Vector(sprite3.x, sprite3.y), sprite3.width, sprite3.height); - r = new SAT.Response(); + // r = new SAT.Response(); - console.log(b2); + // console.log(b2); game.input.onDown.add(launch1, this); @@ -64,9 +75,10 @@ function test1() { function launch1() { + // console.log(b1); - sprite.body.velocity.x = -200; + sprite.body.velocity.x = -100; // sprite2.body.velocity.x = -225; } @@ -74,6 +86,10 @@ function launch1() { function update() { + // sprite.angle += 0.5; + // sprite.body.polygon.rotate(game.math.degToRad(0.5)); + + /* b1.pos.x = sprite.x; b1.pos.y = sprite.y; @@ -83,6 +99,8 @@ function update() { b3.pos.x = sprite3.x; b3.pos.y = sprite3.y; + r.clear(); + if (SAT.testPolygonPolygon(b1.toPolygon(), b2.toPolygon(), r)) { console.log(r, b1.pos, b2.pos); @@ -96,36 +114,65 @@ function update() { console.log('sprite moved to', sprite.x); // sprite.x = b1.pos.x; // sprite.y = b1.pos.y; + } + */ + + sprite.body.collide(sprite2.body); bmd.clear(); if (sprite) { - bmd.fillStyle('rgba(255,0,0,0.8'); - bmd.fillRect(b1.pos.x, b1.pos.y, b1.w, b1.h); + renderPolygon(sprite.body.polygon); + // bmd.fillStyle('rgba(255,0,0,0.8'); + // bmd.fillRect(sprite.body.polygon.pos.x, sprite.body.polygon.pos.y, sprite.body.shape.w, sprite.body.shape.h); } if (sprite2) { - bmd.fillStyle('rgba(0,255,0,0.8'); - bmd.fillRect(b2.pos.x, b2.pos.y, b2.w, b2.h); + renderPolygon(sprite2.body.polygon); + // bmd.fillStyle('rgba(0,255,0,0.8'); + // bmd.fillRect(sprite2.body.polygon.pos.x, sprite2.body.polygon.pos.y, sprite2.body.shape.w, sprite2.body.shape.h); } if (sprite3) { - bmd.fillStyle('rgba(0,0,255,0.8'); - bmd.fillRect(b3.pos.x, b3.pos.y, b3.w, b3.h); + renderPolygon(sprite3.body.polygon); + // bmd.fillStyle('rgba(0,0,255,0.8'); + // bmd.fillRect(sprite3.body.polygon.pos.x, sprite3.body.polygon.pos.y, sprite3.body.shape.w, sprite3.body.shape.h); } } +function renderPolygon (polygon, color) { + +// console.log(polygon); + // this.start(0, 0, color); + + bmd.context.beginPath(); + bmd.context.moveTo(polygon.pos.x + polygon.points[0].x, polygon.pos.y + polygon.points[0].y); + + for (var i = 1; i < polygon.points.length; i++) + { + bmd.context.lineTo(polygon.pos.x + polygon.points[i].x, polygon.pos.y + polygon.points[i].y); + } + + bmd.context.closePath(); + bmd.context.strokeStyle = 'rgba(255, 255, 255, 1)'; + // bmd.context.strokeStyle = color; + bmd.context.stroke(); + +} + + function render() { if (sprite) { // game.debug.renderBodyInfo(sprite, 16, 24); game.debug.renderText(sprite.name + ' x: ' + sprite.x, 16, 500); + game.debug.renderText(sprite.name + ' world x: ' + sprite.world.x, 16, 520); } if (sprite2) diff --git a/src/math/Math.js b/src/math/Math.js index 91f0bb86..c74a8620 100644 --- a/src/math/Math.js +++ b/src/math/Math.js @@ -340,7 +340,7 @@ Phaser.Math = { }, /** - * Set an angle within the bounds of -π toπ. + * Set an angle within the bounds of -π to π. * @method Phaser.Math#normalizeAngle * @param {number} angle * @param {boolean} radians - True if angle size is expressed in radians. diff --git a/src/physics/arcade/ArcadePhysics.js b/src/physics/arcade/ArcadePhysics.js index 0e8dcdcb..357ed540 100644 --- a/src/physics/arcade/ArcadePhysics.js +++ b/src/physics/arcade/ArcadePhysics.js @@ -386,6 +386,12 @@ Phaser.Physics.Arcade.prototype = { collideHandler: function (object1, object2, collideCallback, processCallback, callbackContext) { // Only collide valid objects + if (typeof object2 === 'undefined' && object1.type === Phaser.GROUP) + { + this.collideGroupVsSelf(object1, collideCallback, processCallback, callbackContext, false); + return; + } + if (object1 && object2 && object1.exists && object2.exists) { // SPRITES @@ -510,6 +516,34 @@ Phaser.Physics.Arcade.prototype = { }, + /** + * An internal function. Use Phaser.Physics.Arcade.collide instead. + * + * @method Phaser.Physics.Arcade#collideGroupVsSelf + * @private + */ + collideGroupVsSelf: function (group, collideCallback, processCallback, callbackContext, overlapOnly) { + + if (group.length === 0) + { + return; + } + + var len = group._container.children.length; + + for (var i = 0; i < len; i++) + { + for (var j = i + 1; j <= len; j++) + { + if (group._container.children[i] && group._container.children[j] && group._container.children[i].exists && group._container.children[j].exists) + { + this.collideSpriteVsSprite(group._container.children[i], group._container.children[j], collideCallback, processCallback, callbackContext, overlapOnly); + } + } + } + + }, + /** * An internal function. Use Phaser.Physics.Arcade.collide instead. * @@ -646,342 +680,23 @@ Phaser.Physics.Arcade.prototype = { return false; } - var r = false; - - if (body1.deltaX() === 0 && body2.deltaX() === 0) + if (overlapOnly) { - // They overlap but neither of them are moving - body1.embedded = true; - body2.embedded = true; - } - else if (body1.deltaX() != 0 && body2.deltaX() === 0) - { - r = body1.separate(body2); - } - else if (body2.deltaX() != 0 && body1.deltaX() === 0) - { - r = body2.separate(body1); + return body1.overlap(body2); } else { - // Dual motion thingy - r = body1.separate(body2); - } - - return r; - - - - // return body2.separate(body1); - - /* - - // We got this far, so the bodies overlap and our process was good, which means we can separate ... - this._overlap = 0; - - this._maxOverlap = body1.deltaAbsX() + body2.deltaAbsX() + this.OVERLAP_BIAS; - - if (body1.deltaX() === 0 && body2.deltaX() === 0) - { - // 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 - this._overlap = body1.x + body1.width - body2.x; - - if ((this._overlap > this._maxOverlap) || body1.allowCollision.right === false || body2.allowCollision.left === false) + if (body1.overlap(body2)) { - this._overlap = 0; - } - else - { - body1.touching.right = true; - body2.touching.left = true; - } - } - else if (body1.deltaX() < body2.deltaX()) - { - // Body1 is moving left and/or Body2 is moving right - this._overlap = body1.x - body2.width - body2.x; + // console.log('-----------------------------------------------------------------------------'); + // console.log(body1.sprite.name, 'overlaps', body2.sprite.name, 'x', body1.overlapX, 'y', body1.overlapY); - if ((-this._overlap > this._maxOverlap) || body1.allowCollision.left === false || body2.allowCollision.right === false) - { - this._overlap = 0; - } - else - { - body1.touching.left = true; - body2.touching.right = true; + body1.separate(body2); + return true; } } - // Then adjust their positions and velocities accordingly (if there was any overlap) - if (this._overlap !== 0) - { - body1.overlapX = this._overlap; - body2.overlapX = this._overlap; - - if (!overlapOnly && !body1.customSeparateX && !body2.customSeparateX) - { - this._velocity1 = body1.velocity.x; - this._velocity2 = body2.velocity.x; - - if (!body1.immovable && !body2.immovable) - { - // If either of the bodies are blocked on either side then we don't exchange velocity but treat it like an immovable collision - if (body1.blocked.left || body1.blocked.right) - { - if (body1.blocked.left && body2.deltaX() < 0) - { - body2.x += this._overlap; - body2.velocity.x *= -body2.bounce.x; - } - else if (body1.blocked.right && body2.deltaX() > 0) - { - body2.x -= this._overlap; - body2.velocity.x *= -body2.bounce.x; - } - } - else if (body2.blocked.left || body2.blocked.right) - { - if (body2.blocked.left && body1.deltaX() < 0) - { - body1.x += this._overlap; - body1.velocity.x *= -body1.bounce.x; - } - else if (body2.blocked.right && body1.deltaX() > 0) - { - body1.x -= this._overlap; - body1.velocity.x *= -body1.bounce.x; - } - } - else - { - // Exchange velocities - this._overlap *= 0.5; - body1.overlapX = this._overlap; - body2.overlapX = 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; - - if (body1.deltaX() < 0) - { - body1.x += this._overlap; - } - else - { - body1.x -= this._overlap; - } - - if (body2.deltaX() < 0) - { - body2.x += this._overlap; - } - else - { - body2.x -= this._overlap; - } - - body1.velocity.x = this._average + this._newVelocity1 * body1.bounce.x; - body2.velocity.x = this._average + this._newVelocity2 * body2.bounce.x; - } - } - else if (!body1.immovable) - { - if (body1.deltaX() < 0) - { - body1.x += this._overlap; - } - else - { - body1.x -= this._overlap; - } - - body1.velocity.x = this._velocity2 - this._velocity1 * body1.bounce.x; - } - else if (!body2.immovable) - { - if (body2.deltaX() < 0) - { - body2.x += this._overlap; - } - else - { - body2.x -= this._overlap; - } - - body2.velocity.x = this._velocity1 - this._velocity2 * body2.bounce.x; - } - } - } - - // Now for the vertical - this._overlap = 0; - - this._maxOverlap = body1.deltaAbsY() + body2.deltaAbsY() + this.OVERLAP_BIAS; - - if (body1.deltaY() === 0 && body2.deltaY() === 0) - { - // 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 - this._overlap = body1.y + body1.height - body2.y; - - if ((this._overlap > this._maxOverlap) || body1.allowCollision.down === false || body2.allowCollision.up === false) - { - this._overlap = 0; - } - else - { - body1.touching.down = true; - body2.touching.up = true; - } - } - else if (body1.deltaY() < body2.deltaY()) - { - // Body1 is moving up and/or Body2 is moving down - this._overlap = body1.y - body2.height - body2.y; - - if ((-this._overlap > this._maxOverlap) || body1.allowCollision.up === false || body2.allowCollision.down === false) - { - this._overlap = 0; - } - else - { - body1.touching.up = true; - body2.touching.down = true; - } - } - - // Then adjust their positions and velocities accordingly (if there was any overlap) - if (this._overlap !== 0) - { - body1.overlapY = this._overlap; - body2.overlapY = this._overlap; - - if (!overlapOnly && !body1.customSeparateY && !body2.customSeparateY) - { - this._velocity1 = body1.velocity.y; - this._velocity2 = body2.velocity.y; - - if (!body1.immovable && !body2.immovable) - { - // If either of the bodies are blocked on either side then we don't exchange velocity but treat it like an immovable collision - if (body1.blocked.up || body1.blocked.down) - { - if (body1.blocked.up && body2.deltaY() < 0) - { - body2.y += this._overlap; - body2.velocity.y *= -body2.bounce.y; - } - else if (body1.blocked.down && body2.deltaY() > 0) - { - body2.y -= this._overlap; - body2.velocity.y *= -body2.bounce.y; - } - } - else if (body2.blocked.up || body2.blocked.down) - { - if (body2.blocked.up && body1.deltaY() < 0) - { - body1.y += this._overlap; - body1.velocity.y *= -body1.bounce.y; - } - else if (body2.blocked.down && body1.deltaY() > 0) - { - body1.y -= this._overlap; - body1.velocity.y *= -body1.bounce.y; - } - } - else - { - // Exchange velocities - this._overlap *= 0.5; - body1.overlapY = this._overlap; - body2.overlapY = 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; - - if (body1.deltaY() < 0) - { - body1.y += this._overlap; - } - else - { - body1.y -= this._overlap; - } - - if (body2.deltaY() < 0) - { - body2.y += this._overlap; - } - else - { - body2.y -= this._overlap; - } - - body1.velocity.y = this._average + this._newVelocity1 * body1.bounce.y; - body2.velocity.y = this._average + this._newVelocity2 * body2.bounce.y; - } - } - else if (!body1.immovable) - { - if (body1.deltaY() < 0) - { - body1.y += this._overlap; - } - else - { - body1.y -= this._overlap; - } - - body1.velocity.y = this._velocity2 - this._velocity1 * 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.preX; - } - } - else if (!body2.immovable) - { - if (body2.deltaY() < 0) - { - body2.y += this._overlap; - } - else - { - body2.y -= this._overlap; - } - - body2.velocity.y = this._velocity1 - this._velocity2 * 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.preX; - } - } - } - } - - return true; - */ + return false; }, diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index cb44ca9e..077d60dc 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -60,16 +60,50 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.preRotation = sprite.angle; + /** + * @property {number} screenX - The x position of the physics body translated to screen space. + * @readonly + */ + this.screenX = sprite.x; + + /** + * @property {number} screenY - The y position of the physics body translated to screen space. + * @readonly + */ + this.screenY = sprite.y; + + /** + * @property {number} sourceWidth - The un-scaled original size. + * @readonly + */ + this.sourceWidth = sprite.currentFrame.sourceSizeW; + + /** + * @property {number} sourceHeight - The un-scaled original size. + * @readonly + */ + this.sourceHeight = sprite.currentFrame.sourceSizeH; + /** * @property {number} width - The calculated width of the physics body. */ this.width = sprite.currentFrame.sourceSizeW; /** - * @property {number} height - The calculated height of the physics body. + * @property .numInternal ID cache */ this.height = sprite.currentFrame.sourceSizeH; + /** + * @property {number} halfWidth - The calculated width / 2 of the physics body. + */ + this.halfWidth = Math.floor(sprite.currentFrame.sourceSizeW / 2); + + /** + * @property {number} halfHeight - The calculated height / 2 of the physics body. + */ + this.halfHeight = Math.floor(sprite.currentFrame.sourceSizeH / 2); + /** * @property {Phaser.Point} center - The center coordinate of the Physics Body. */ @@ -81,12 +115,12 @@ Phaser.Physics.Arcade.Body = function (sprite) { this.motionVelocity = new Phaser.Point(); /** - * @property {Phaser.Point} velocity - The velocity in pixels per second sq. of the Body. + * @property {Phaser.Point} velocity - The velocity of the Body. */ this.velocity = new Phaser.Point(); /** - * @property {Phaser.Point} acceleration - The velocity in pixels per second sq. of the Body. + * @property {Phaser.Point} acceleration - The acceleration in pixels per second sq. of the Body. */ this.acceleration = new Phaser.Point(); @@ -103,12 +137,12 @@ Phaser.Physics.Arcade.Body = function (sprite) { /** * @property {number} minBounceVelocity - The minimum bounce velocity (could just be the bounce value?). */ - // this.minBounceVelocity = 0.5; + this.minBounceVelocity = 0.5; this._debug = 0; /** - * @property {Phaser.Point} gravity - The gravity applied to the motion of the Body. + * @property {Phaser.Point} gravity - The gravity applied to the motion of the Body. This works in addition to any gravity set on the world. */ this.gravity = new Phaser.Point(); @@ -121,22 +155,22 @@ Phaser.Physics.Arcade.Body = function (sprite) { * @property {Phaser.Point} minVelocity - When a body rebounds off another the minVelocity is checked, if the new velocity is lower than the minVelocity the body is stopped. * @default */ - this.minVelocity = new Phaser.Point(20, 20); + this.minVelocity = new Phaser.Point(10, 10); /** - * @property {Phaser.Point} maxVelocity - The maximum velocity in pixels per second sq. that the Body can reach. + * @property {Phaser.Point} maxVelocity - The maximum velocity that the Body can reach. * @default */ this.maxVelocity = new Phaser.Point(10000, 10000); /** - * @property {number} angularVelocity - The angular velocity in pixels per second sq. of the Body. + * @property {number} angularVelocity - The angular velocity of the Body. * @default */ this.angularVelocity = 0; /** - * @property {number} angularAcceleration - The angular acceleration in pixels per second sq. of the Body. + * @property {number} angularAcceleration - The angular acceleration of the Body. * @default */ this.angularAcceleration = 0; @@ -148,7 +182,7 @@ Phaser.Physics.Arcade.Body = function (sprite) { this.angularDrag = 0; /** - * @property {number} maxAngular - The maximum angular velocity in pixels per second sq. that the Body can reach. + * @property {number} maxAngular - The maximum angular velocity that the Body can reach. * @default */ this.maxAngular = 1000; @@ -173,6 +207,18 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.touching = { none: true, up: false, down: false, left: false, right: false }; + /** + * This object is populated with previous touching values from the bodies previous collision. + * @property {object} wasTouching - An object containing previous touching results. + */ + this.wasTouching = { none: true, up: false, down: false, left: false, right: false }; + + /** + * @property {number} facing - A const reference to the direction the Body is traveling or facing. + * @default + */ + this.facing = Phaser.NONE; + /** * @property {boolean} immovable - An immovable Body will not receive any impacts or exchanges of velocity from other bodies. * @default @@ -180,7 +226,7 @@ Phaser.Physics.Arcade.Body = function (sprite) { this.immovable = false; /** - * @property {boolean} moves - Set to true to allow the Physics system to move this Body, other false to move it manually. + * @property {boolean} moves - Set to true to allow the Physics system to move this Body, or false to move it manually. * @default */ this.moves = true; @@ -237,6 +283,12 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.friction = 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. + */ + this.embedded = false; + /** * A Body can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World. * @property {boolean} collideWorldBounds - Should the Body collide with the World bounds? @@ -250,6 +302,8 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.blocked = { up: false, down: false, left: false, right: false }; + this.blockedPoint = new Phaser.Point(0, 0); + /** * @property {number} _dx - Internal cache var. * @private @@ -274,6 +328,10 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this._sy = sprite.scale.y; + this._newVelocity1 = 0; + this._newVelocity2 = 0; + this._average = 0; + }; Phaser.Physics.Arcade.Body.prototype = { @@ -286,16 +344,16 @@ Phaser.Physics.Arcade.Body.prototype = { */ 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); - // } + 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); + } }, @@ -307,18 +365,26 @@ Phaser.Physics.Arcade.Body.prototype = { */ preUpdate: function () { - // this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; - // this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y; + // 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; + + this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; + this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y; this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x; this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y; this.preRotation = this.sprite.angle; - // This all needs to move - because a body may start the preUpdate already touching something - // this.blocked.up = false; - // this.blocked.down = false; - // this.blocked.left = false; - // this.blocked.right = false; + this.blocked.up = false; + this.blocked.down = false; + this.blocked.left = false; + this.blocked.right = false; + + // this.embedded = false; this.x = this.preX; this.y = this.preY; @@ -341,6 +407,18 @@ Phaser.Physics.Arcade.Body.prototype = { this.applyMotion(); } + if (this.deltaX() != 0) + { + this.touching.left = false; + this.touching.right = false; + } + + if (this.deltaY() != 0) + { + this.touching.up = false; + this.touching.down = false; + } + }, /** @@ -351,34 +429,38 @@ Phaser.Physics.Arcade.Body.prototype = { */ checkWorldBounds: function () { - if (this.x <= this.game.world.bounds.x) + this.blockedPoint.setTo(0, 0); + + if (this.x < this.game.world.bounds.x) { - this.overlapX = this.game.world.bounds.x - this.x; + this.blockedPoint.x = this.game.world.bounds.x - this.x; + // this.overlapX = this.game.world.bounds.x - this.x; this.blocked.left = true; // console.log(this._debug, 'cwl', this.overlapX, this.x, this.game.world.bounds.x); } - else if (this.right >= this.game.world.bounds.right) + else if (this.right > this.game.world.bounds.right) { - this.overlapX = this.right - this.game.world.bounds.right; + this.blockedPoint.x = this.right - this.game.world.bounds.right; + // this.overlapX = this.right - this.game.world.bounds.right; this.blocked.right = true; // console.log(this._debug, 'cwr', this.overlapX, this.x, this.game.world.bounds.x); } - if (this.y <= this.game.world.bounds.y) + if (this.y < this.game.world.bounds.y) { - this.overlapY = this.game.world.bounds.y - this.y; + this.blockedPoint.y = this.game.world.bounds.y - this.y; + // this.overlapY = this.game.world.bounds.y - this.y; this.blocked.up = true; // console.log(this._debug, 'cwu', this.overlapY, this.y, this.height, this.bottom, this.game.world.bounds.bottom); } - else if (this.bottom >= this.game.world.bounds.bottom) + else if (this.bottom > this.game.world.bounds.bottom) { - this.overlapY = this.bottom - this.game.world.bounds.bottom; + this.blockedPoint.y = this.bottom - this.game.world.bounds.bottom; + // this.overlapY = this.bottom - this.game.world.bounds.bottom; this.blocked.down = true; // console.log(this._debug, 'cwd', this.overlapY, this.y, this.height, this.bottom, this.game.world.bounds.bottom); } - this.blockedPoint.setTo(this.x, this.y); - }, /** @@ -405,10 +487,11 @@ Phaser.Physics.Arcade.Body.prototype = { } // overlapX/Y values at this point will be penetration into the bounds and DELTA WILL BE ZERO - if (this.blocked.left) + if (this.blocked.left && this.blockedPoint.x > 0) { // Separate - this.x += this.overlapX; + // this.x += this.overlapX; + this.x += this.blockedPoint.x; // console.log(this._debug, 'blocked left', this.x, this.overlapX); @@ -416,8 +499,8 @@ Phaser.Physics.Arcade.Body.prototype = { this._dx = this.game.time.physicsElapsed * (this.velocity.x + this.motionVelocity.x / 2); - // if (this._dx > this.minBounceVelocity) - if (Math.abs(this.velocity.x) > this.minVelocity.x) + if (this._dx > this.minBounceVelocity) + // if (Math.abs(this.velocity.x) > this.minVelocity.x) { this.x += this._dx; this.velocity.x += this.motionVelocity.x; @@ -432,10 +515,11 @@ Phaser.Physics.Arcade.Body.prototype = { // console.log(this._debug, 'blocked left KILL', this._dx, 'overlap', this.overlapX, 'delta', this.deltaX(), 'newy', this.x); } } - else if (this.blocked.right) + else if (this.blocked.right && this.blockedPoint.x > 0) { // Separate - this.x -= this.overlapX; + this.x -= this.blockedPoint.x; + // this.x -= this.overlapX; this.velocity.x *= -this.bounce.x; @@ -463,17 +547,18 @@ Phaser.Physics.Arcade.Body.prototype = { } // overlapX/Y values at this point will be penetration into the bounds and DELTA WILL BE ZERO - if (this.blocked.up) + if (this.blocked.up && this.blockedPoint.y > 0) { // Separate - this.y += this.overlapY; + // this.y += this.overlapY; + this.y += this.blockedPoint.y; this.velocity.y *= -this.bounce.y; this._dy = this.game.time.physicsElapsed * (this.velocity.y + this.motionVelocity.y / 2); - // if (this._dy > this.minBounceVelocity) - if (Math.abs(this.velocity.y) > this.minVelocity.y) + if (this._dy > this.minBounceVelocity) + // if (Math.abs(this.velocity.y) > this.minVelocity.y) { this.y += this._dy; this.velocity.y += this.motionVelocity.y; @@ -487,17 +572,18 @@ Phaser.Physics.Arcade.Body.prototype = { // console.log(this._debug, 'void1', this.velocity.y, 'delta', this.deltaY()); } } - else if (this.blocked.down) + else if (this.blocked.down && this.blockedPoint.y > 0) { // Separate - this.y -= this.overlapY; + // this.y -= this.overlapY; + this.y -= this.blockedPoint.y; this.velocity.y *= -this.bounce.y; this._dy = this.game.time.physicsElapsed * (this.velocity.y + this.motionVelocity.y / 2); - // if (this._dy < -this.minBounceVelocity) - if (Math.abs(this.velocity.y) > this.minVelocity.y) + if (this._dy < -this.minBounceVelocity) + // if (Math.abs(this.velocity.y) > this.minVelocity.y) { this.y += this._dy; this.velocity.y += this.motionVelocity.y; @@ -538,6 +624,242 @@ Phaser.Physics.Arcade.Body.prototype = { }, + overlap: function (body) { + + this.overlapX = 0; + this.overlapY = 0; + + if (this.x < body.x && this.allowCollision.right && body.allowCollision.left) + { + // Negative = body touched this one on the right face + this.overlapX = body.x - this.right; + this.touching.right = true; + } + else if (this.x > body.x && this.allowCollision.left && body.allowCollision.right) + { + // Positive means body touched this one on the left face + this.overlapX = body.right - this.x; + this.touching.left = true; + } + + if (this.y < body.y && this.allowCollision.down && body.allowCollision.up) + { + // Negative = body touched this one on the bottom face + this.overlapY = body.y - this.bottom; + this.touching.down = true; + } + else if (this.y > body.y && this.allowCollision.up && body.allowCollision.down) + { + // Positive means body touched this one on the top face + this.overlapY = body.bottom - this.y; + this.touching.up = true; + } + + // Which is the largest? + if (this.overlapX !== 0 && this.overlapY !== 0) + { + // console.log('pcheck', Math.abs(this.overlapX), Math.abs(this.overlapY)); + + // find out which is the largest penetration side + if (Math.abs(this.overlapX) > Math.abs(this.overlapY)) + { + // Vertical penetration (as x is larger than y) + this.overlapX = 0; + this.touching.left = false; + this.touching.right = false; + } + else + { + // Horizontal penetration (as y is larger than x) + this.overlapY = 0; + this.touching.up = false; + this.touching.down = false; + } + } + + // overlapX/Y now contains either zero or a positive value containing the overlapping area + return (this.overlapX !== 0 || this.overlapY !== 0); + + }, + + // The left-hand face of this Body was hit + // overlapX will be a positive value + hitLeft: function (x, body, nv1, nv2, avg) { + + // This body isn't moving horizontally, so it was hit by something moving right + if (this.immovable || this.blocked.right) + { + // console.log(this.sprite.name, 'hitLeft', 'immovable'); + body.x -= x; + body.velocity.x = this.velocity.x - body.velocity.x * body.bounce.x; + } + else + { + if (body.immovable || body.blocked.left) + { + // console.log(this.sprite.name, 'hitLeft', 'full'); + // We take the full separation as what hit is isn't moveable + this.x += x; + this.velocity.x = body.velocity.x - this.velocity.x * this.bounce.x; + } + else + { + // console.log(this.sprite.name, 'hitLeft', 'shared'); + // Share the separation + x *= 0.5; + this.x += x; + body.x -= x; + this.velocity.x = avg + nv1 * this.bounce.x; + body.velocity.x = avg + nv2 * body.bounce.x; + } + } + + }, + + // The right-hand face of this Body was hit + // overlapX will be a negative value + hitRight: function (x, body, nv1, nv2, avg) { + + // This body isn't moving horizontally, so it was hit by something moving right + if (this.immovable || this.blocked.left) + { + // console.log(this.sprite.name, 'hitRight', 'immovable'); + body.x -= x; + body.velocity.x = this.velocity.x - body.velocity.x * body.bounce.x; + } + else + { + if (body.immovable || body.blocked.right) + { + // console.log(this.sprite.name, 'hitRight', 'full'); + // We take the full separation as what hit is isn't moveable + this.x += x; + this.velocity.x = body.velocity.x - this.velocity.x * this.bounce.x; + } + else + { + // console.log(this.sprite.name, 'hitRight', 'shared'); + // Share the separation + x *= 0.5; + this.x += x; + body.x -= x; + this.velocity.x = avg + nv1 * this.bounce.x; + body.velocity.x = avg + nv2 * body.bounce.x; + } + } + + }, + + // The top face of this Body was hit + // overlapY will be a positive value + hitUp: function (y, body, nv1, nv2, avg) { + + // This body isn't moving horizontally, so it was hit by something moving right + if (this.immovable || this.blocked.down) + { + // console.log(this.sprite.name, 'hitUp', 'immovable'); + body.y -= y; + body.velocity.y = this.velocity.y - body.velocity.y * body.bounce.y; + } + else + { + if (body.immovable || body.blocked.up) + { + // console.log(this.sprite.name, 'hitUp', 'full'); + // We take the full separation as what hit is isn't moveable + this.y += y; + this.velocity.y = body.velocity.y - this.velocity.y * this.bounce.y; + } + else + { + // console.log(this.sprite.name, 'hitUp', 'shared'); + // Share the separation + y *= 0.5; + this.y += y; + body.y -= y; + this.velocity.y = avg + nv1 * this.bounce.y; + body.velocity.y = avg + nv2 * body.bounce.y; + } + } + + }, + + // The bottom face of this Body was hit + // overlapY will be a negative value + hitDown: function (y, body, nv1, nv2, avg) { + + // This body isn't moving horizontally, so it was hit by something moving right + if (this.immovable || this.blocked.up) + { + // console.log(this.sprite.name, 'hitDown', 'immovable'); + body.y -= y; + body.velocity.y = this.velocity.y - body.velocity.y * body.bounce.y; + } + else + { + if (body.immovable || body.blocked.down) + { + // console.log(this.sprite.name, 'hitDown', 'full'); + // We take the full separation as what hit is isn't moveable + this.y += y; + this.velocity.y = body.velocity.y - this.velocity.y * this.bounce.y; + } + else + { + // console.log(this.sprite.name, 'hitDown', 'shared'); + // Share the separation + y *= 0.5; + this.y += y; + body.y -= y; + this.velocity.y = avg + nv1 * this.bounce.y; + body.velocity.y = avg + nv2 * body.bounce.y; + } + } + + }, + + separate: function (body) { + + // We already know the overlap in this.overlapX/Y + + if (this.overlapX !== 0) + { + this._newVelocity1 = Math.sqrt((body.velocity.x * body.velocity.x * body.mass) / this.mass) * ((body.velocity.x > 0) ? 1 : -1); + this._newVelocity2 = Math.sqrt((this.velocity.x * this.velocity.x * this.mass) / body.mass) * ((this.velocity.x > 0) ? 1 : -1); + this._average = (this._newVelocity1 + this._newVelocity2) * 0.5; + this._newVelocity1 -= this._average; + this._newVelocity2 -= this._average; + + if (this.overlapX < 0) + { + this.hitLeft(this.overlapX, body, this._newVelocity1, this._newVelocity2, this._average); + } + else if (this.overlapX > 0) + { + this.hitRight(this.overlapX, body, this._newVelocity1, this._newVelocity2, this._average); + } + } + + if (this.overlapY !== 0) + { + this._newVelocity1 = Math.sqrt((body.velocity.y * body.velocity.y * body.mass) / this.mass) * ((body.velocity.y > 0) ? 1 : -1); + this._newVelocity2 = Math.sqrt((this.velocity.y * this.velocity.y * this.mass) / body.mass) * ((this.velocity.y > 0) ? 1 : -1); + this._average = (this._newVelocity1 + this._newVelocity2) * 0.5; + this._newVelocity1 -= this._average; + this._newVelocity2 -= this._average; + + if (this.overlapY < 0) + { + this.hitDown(this.overlapY, body, this._newVelocity1, this._newVelocity2, this._average); + } + else if (this.overlapY > 0) + { + this.hitUp(this.overlapY, body, this._newVelocity1, this._newVelocity2, this._average); + } + } + + }, + /** * Internal method. This is called directly before the sprites are sent to the renderer. * @@ -548,8 +870,29 @@ Phaser.Physics.Arcade.Body.prototype = { if (this.moves) { - // this.sprite.x += this.deltaX(); - // this.sprite.y += this.deltaY(); + if (this.deltaX() < 0) + { + this.facing = Phaser.LEFT; + } + else if (this.deltaX() > 0) + { + this.facing = Phaser.RIGHT; + } + + if (this.deltaY() < 0) + { + this.facing = Phaser.UP; + } + else if (this.deltaY() > 0) + { + this.facing = Phaser.DOWN; + } + + this.sprite.x += this.deltaX(); + this.sprite.y += this.deltaY(); + + this.sprite.worldTransform[2] += this.deltaX(); + this.sprite.worldTransform[5] += this.deltaY(); this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); @@ -561,6 +904,35 @@ Phaser.Physics.Arcade.Body.prototype = { }, + + /** + * You can modify the size of the physics Body to be any dimension you need. + * So it could be smaller or larger than the parent Sprite. 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#setSize + * @param {number} width - The width of the Body. + * @param {number} height - The height of the Body. + * @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. + */ + setSize: function (width, height, offsetX, offsetY) { + + offsetX = offsetX || this.offset.x; + offsetY = offsetY || this.offset.y; + + this.sourceWidth = width; + this.sourceHeight = height; + 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.x + this.halfWidth, this.y + this.halfHeight); + + }, + /** * Resets all Body values (velocity, acceleration, rotation, etc) * diff --git a/src/physics/arcade/ArcadeBody.js b/src/physics/arcade/SATBody.js similarity index 69% rename from src/physics/arcade/ArcadeBody.js rename to src/physics/arcade/SATBody.js index 22446347..ab9a4b8a 100644 --- a/src/physics/arcade/ArcadeBody.js +++ b/src/physics/arcade/SATBody.js @@ -60,50 +60,16 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.preRotation = sprite.angle; - /** - * @property {number} screenX - The x position of the physics body translated to screen space. - * @readonly - */ - this.screenX = sprite.x; - - /** - * @property {number} screenY - The y position of the physics body translated to screen space. - * @readonly - */ - this.screenY = sprite.y; - - /** - * @property {number} sourceWidth - The un-scaled original size. - * @readonly - */ - this.sourceWidth = sprite.currentFrame.sourceSizeW; - - /** - * @property {number} sourceHeight - The un-scaled original size. - * @readonly - */ - this.sourceHeight = sprite.currentFrame.sourceSizeH; - /** * @property {number} width - The calculated width of the physics body. */ this.width = sprite.currentFrame.sourceSizeW; /** - * @property .numInternal ID cache + * @property {number} height - The calculated height of the physics body. */ this.height = sprite.currentFrame.sourceSizeH; - /** - * @property {number} halfWidth - The calculated width / 2 of the physics body. - */ - this.halfWidth = Math.floor(sprite.currentFrame.sourceSizeW / 2); - - /** - * @property {number} halfHeight - The calculated height / 2 of the physics body. - */ - this.halfHeight = Math.floor(sprite.currentFrame.sourceSizeH / 2); - /** * @property {Phaser.Point} center - The center coordinate of the Physics Body. */ @@ -206,19 +172,6 @@ Phaser.Physics.Arcade.Body = function (sprite) { * @property {object} touching - An object containing touching results. */ this.touching = { none: true, up: false, down: false, left: false, right: false }; - this.touchingPoint = new Phaser.Point(this.x, this.y); - - /** - * This object is populated with previous touching values from the bodies previous collision. - * @property {object} wasTouching - An object containing previous touching results. - */ - this.wasTouching = { none: true, up: false, down: false, left: false, right: false }; - - /** - * @property {number} facing - A const reference to the direction the Body is traveling or facing. - * @default - */ - this.facing = Phaser.NONE; /** * @property {boolean} immovable - An immovable Body will not receive any impacts or exchanges of velocity from other bodies. @@ -284,12 +237,6 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this.friction = 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. - */ - this.embedded = false; - /** * A Body can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World. * @property {boolean} collideWorldBounds - Should the Body collide with the World bounds? @@ -302,7 +249,6 @@ Phaser.Physics.Arcade.Body = function (sprite) { * @property {object} blocked - An object containing on which faces this Body is blocked from moving, if any. */ this.blocked = { up: false, down: false, left: false, right: false }; - this.blockedPoint = new Phaser.Point(); /** * @property {number} _dx - Internal cache var. @@ -328,6 +274,10 @@ Phaser.Physics.Arcade.Body = function (sprite) { */ this._sy = sprite.scale.y; + this.shape = new SAT.Box(new SAT.Vector(this.x, this.y), this.width, this.height); + this.polygon = this.shape.toPolygon(); + this.response = new SAT.Response(); + }; Phaser.Physics.Arcade.Body.prototype = { @@ -340,16 +290,16 @@ Phaser.Physics.Arcade.Body.prototype = { */ 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); - } + // 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); + // } }, @@ -361,42 +311,23 @@ Phaser.Physics.Arcade.Body.prototype = { */ preUpdate: function () { - // 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; - - this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; - this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y; + // this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x; + // this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y; this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x; this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y; - this.preRotation = this.sprite.angle; + // this.preRotation = this.sprite.angle; + this.preRotation = this.sprite.rotation; // This all needs to move - because a body may start the preUpdate already touching something - // See if we can reduce this down? this.blocked.up = false; this.blocked.down = false; this.blocked.left = false; this.blocked.right = false; - this.embedded = false; - this.x = this.preX; this.y = this.preY; - this.rotation = this.preRotation; - - // if (this.deltaX() == 0 && (this.touchingPoint.x !== this.x || this.touchingPoint.y !== this.y)) - // { - // console.log('touch reset', this.x, this.y, this.touchingPoint); - // this.touching.none = true; - // this.touching.up = false; - // this.touching.down = false; - // this.touching.left = false; - // this.touching.right = false; - // } + // this.rotation = this.preRotation; this.speed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y); this.angle = Math.atan2(this.velocity.y, this.velocity.x); @@ -415,6 +346,16 @@ Phaser.Physics.Arcade.Body.prototype = { this.applyMotion(); } + this.polygon.pos.x = this.x; + this.polygon.pos.y = this.y; + + if (this.deltaZ() !== 0) + { + // this.polygon.rotate(this.sprite.rotation); + // console.log(this.sprite.rotation); + } + // this.polygon.rotate(this.game.math.degToRad(this.rotation)); + }, /** @@ -612,142 +553,31 @@ Phaser.Physics.Arcade.Body.prototype = { }, - // This body is the one that is checking against 'body' - separateX: function (body) { + collide: function (body) { - // Doesn't matter if this is moving or not - console.log('--- separateX -----------------------------------------------------------------------------'); - console.log(this.sprite.name, 'testing against', body.sprite.name); - console.log(this.sprite.name, 'moving left:', (this.deltaX() < 0), 'moving right:', (this.deltaX() > 0)); + this.response.clear(); - this.overlapX = 0; + // if (this._debug === 100) + // { + // console.log(this.sprite.name, this.polygon); + // } - if (this.x < body.x) + if (SAT.testPolygonPolygon(this.polygon, body.polygon, this.response)) { - this.overlapX = this.right - body.x; + + // b1.pos.sub(r.overlapV); + // sprite.body.velocity.x *= -sprite.body.bounce.x; + + this.velocity.x = 0; + + // separate + this.x += Math.ceil(Math.abs(this.response.overlapV.x)); + this.y += Math.ceil(Math.abs(this.response.overlapV.y)); + + console.log(this.response, this.deltaX()); + + console.log('sprite moved to', this.x, this.deltaX()); } - else - { - this.overlapX = body.right - this.x; - } - - // There are 5 possible collisions taking place - // if (this.deltaX() === 0 && body.deltaX()) - - // if (this.deltaX() < 0 ) - - // if (this.deltaX() < 0 && this.allowCollision.left && body.allowCollision.right) - - // This body is moving, the body it collided with is not - - }, - - separate: function (body) { - - console.log('-----------------------------------------------------------------------------'); - console.log(this.sprite.name, 'testing against', body.sprite.name); - console.log(this.sprite.name, 'moving left:', (this.deltaX() < 0), 'moving right:', (this.deltaX() > 0)); - - this.overlapX = 0; - this.overlapY = 0; - - if (this.deltaX() < 0 && this.allowCollision.left && body.allowCollision.right) - { - // LEFT (will create a negative overlapX value) - this.overlapX = this.x - body.right; - console.log(this.sprite.name, 'check left', body.right, this.overlapX); - } - else if (this.deltaX() > 0 && this.allowCollision.right && body.allowCollision.left) - { - // RIGHT (will create a positive overlapX value) - this.overlapX = this.right - body.x; - console.log(this.sprite.name, 'check right', this.overlapX); - } - - if (this.deltaY() < 0 && this.allowCollision.up && body.allowCollision.down) - { - // UP (will create a negative overlapY value) - this.overlapY = this.y - body.bottom; - } - else if (this.deltaY() > 0 && this.allowCollision.down && body.allowCollision.up) - { - // DOWN - this.overlapY = this.bottom - body.y; - } - - if (this.overlapX === 0 && this.overlapY === 0) - { - return false; - } - else - { - this.overlapHandler(this.overlapX, this.overlapY, body); - body.overlapHandler(this.overlapX, this.overlapY, this); - - return true; - } - - }, - - overlapHandler: function (x, y, body) { - - if (x !== 0) - { - // Both moving, so let's cut the overlap in half - if (this.deltaX() != 0 && body.deltaX() != 0) - { - console.log(this.sprite.name, 'both overlap, halving'); - x * 0.5; - } - - if (this.deltaX() !== 0) - { - // Not moving, caught impact from another object - - } - else - { - - } - - if (this.deltaX() < 0 && !this.blocked.right) - { - // This body is moving left - this.x += x; - console.log(this.sprite.name, 'touch h-left', this.x, x); - } - else if (this.deltaX() > 0 && !this.body.blocked.left) - { - this.x -= x; - console.log(this.sprite.name, 'touch h-right', this.x); - } - else - { - } - - if (this.bounce.x === 0) - { - this.velocity.x = 0; - } - else - { - this.velocity.x = -this.velocity.x * this.bounce.x; - - if (Math.abs(this.velocity.x) < this.minVelocity.x) - { - this.velocity.x = 0; - } - } - } - - this.sprite.x += this.deltaX(); - this.sprite.y += this.deltaY(); - - console.log(this.sprite.name, 'separate finished. Sprite.x', this.sprite.x, 'body x', this.x); - - // reset delta ready for next collision - this.preX = this.x; - this.preY = this.y; }, @@ -761,68 +591,24 @@ Phaser.Physics.Arcade.Body.prototype = { if (this.moves) { - // if (this.deltaX() < 0) - // { - // this.facing = Phaser.LEFT; - // } - // else if (this.deltaX() > 0) - // { - // this.facing = Phaser.RIGHT; - // this.sprite.x += this.deltaX(); - // } - - // if (this.deltaY() < 0) - // { - // this.facing = Phaser.UP; - // this.sprite.y += this.deltaY(); - // } - // else if (this.deltaY() > 0) - // { - // this.facing = Phaser.DOWN; - // } - this.sprite.x += this.deltaX(); this.sprite.y += this.deltaY(); + this.sprite.worldTransform[2] += this.deltaX(); + this.sprite.worldTransform[5] += this.deltaY(); + this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); + this.rotation = this.preRotation; + if (this.allowRotation) { - this.sprite.angle += this.deltaZ(); + // this.sprite.angle += this.deltaZ(); } } }, - - /** - * You can modify the size of the physics Body to be any dimension you need. - * So it could be smaller or larger than the parent Sprite. 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#setSize - * @param {number} width - The width of the Body. - * @param {number} height - The height of the Body. - * @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. - */ - setSize: function (width, height, offsetX, offsetY) { - - offsetX = offsetX || this.offset.x; - offsetY = offsetY || this.offset.y; - - this.sourceWidth = width; - this.sourceHeight = height; - 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.x + this.halfWidth, this.y + this.halfHeight); - - }, - /** * Resets all Body values (velocity, acceleration, rotation, etc) * diff --git a/src/utils/Debug.js b/src/utils/Debug.js index c4950572..c5a9e0b3 100644 --- a/src/utils/Debug.js +++ b/src/utils/Debug.js @@ -922,6 +922,40 @@ Phaser.Utils.Debug.prototype = { }, + /** + * Renders the corners and point information of the given Sprite. + * @method Phaser.Utils.Debug#renderPolygon + * @param {array} polygon + * @param {string} [color='rgb(255,255,255)'] - The color the polygon is stroked in. + */ + renderPolygon: function (polygon, color, context) { + + if (this.context === null && context === null) + { + return; + } + + color = color || 'rgb(255,255,255)'; + + this.start(0, 0, color); + + this.context.beginPath(); + this.context.moveTo(polygon[0].x, polygon[0].y); + + for (var i = 1; i < polygon.length; i++) + { + this.context.lineTo(polygon[i].x, polygon[i].y); + } + + this.context.closePath(); + // this.context.strokeStyle = 'rgba(255, 0, 255, 0.7)'; + this.context.strokeStyle = color; + this.context.stroke(); + + this.stop(); + + }, + /** * Dumps the Linked List to the console. *