From a27f6d65628a6a0cd570cb70a9586e5bd8a9bb43 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Tue, 3 Sep 2013 17:28:12 +0100 Subject: [PATCH] Forces working, collision half way there. --- src/core/Game.js | 5 +- src/core/World.js | 24 +++ src/gameobjects/Sprite.js | 6 + src/physics/arcade/ArcadePhysics.js | 288 ++++++++++++++++++++++++++++ src/physics/arcade/Body.js | 4 +- 5 files changed, 322 insertions(+), 5 deletions(-) diff --git a/src/core/Game.js b/src/core/Game.js index b3b2f867..3a8e168d 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -379,16 +379,17 @@ Phaser.Game.prototype = { this.input.update(); this.tweens.update(); - // this.stage.update(); this.sound.update(); - // this.physics.update(); this.world.update(); this.state.update(); + // this.physics.update(); this.plugins.update(); this.renderer.render(this.world._stage); this.state.render(); + this.world.postUpdate(); + this.plugins.postRender(); }, diff --git a/src/core/World.js b/src/core/World.js index 228d0b51..3b5a1c1d 100644 --- a/src/core/World.js +++ b/src/core/World.js @@ -71,6 +71,30 @@ Phaser.World.prototype = { }, + postUpdate: function () { + + //this.camera.update(); + + var displayObject = this._stage; + + // once the display object hits this. we can break the loop + var testObject = displayObject.last._iNext; + displayObject = displayObject.first; + + do + { + if (displayObject['postUpdate']) + { + displayObject.postUpdate(); + } + + // count++ + displayObject = displayObject._iNext; + } + while(displayObject != testObject) + + }, + /** * Updates the size of this world. * diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index 59ee393e..1ef20759 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -250,6 +250,12 @@ Phaser.Sprite.prototype.update = function() { } +Phaser.Sprite.prototype.postUpdate = function() { + + this.body.postUpdate(); + +} + Phaser.Sprite.prototype.updateBounds = function() { // Update the edge points diff --git a/src/physics/arcade/ArcadePhysics.js b/src/physics/arcade/ArcadePhysics.js index 89eae036..bf7bf6d9 100644 --- a/src/physics/arcade/ArcadePhysics.js +++ b/src/physics/arcade/ArcadePhysics.js @@ -11,6 +11,16 @@ Phaser.Physics.Arcade = function (game) { */ this.worldDivisions = 6; + this.LEFT = 0x0001; + this.RIGHT = 0x0010; + this.UP = 0x0100; + this.DOWN = 0x1000; + this.NONE = 0; + this.CEILING = this.UP; + this.FLOOR = this.DOWN; + this.WALL = this.LEFT | this.RIGHT; + this.ANY = this.LEFT | this.RIGHT | this.UP | this.DOWN; + // this.angularDrag = 0; // this.gravity = new Phaser.Point; // this.drag = new Phaser.Point; @@ -23,6 +33,12 @@ Phaser.Physics.Arcade = function (game) { Phaser.Physics.Arcade.prototype = { + collide: function (objectOrGroup1, objectOrGroup2, notifyCallback) { + + return this.overlap(objectOrGroup1, objectOrGroup2, notifyCallback, this.separate); + + }, + updateMotion: function (body) { this._velocityDelta = (this.computeVelocity(body.angularVelocity, body.gravity.x, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity) / 2; @@ -101,7 +117,279 @@ Phaser.Physics.Arcade.prototype = { }, + /** + * Checks for overlaps between two objects using the world QuadTree. Can be GameObject vs. GameObject, GameObject vs. Group or Group vs. Group. + * Note: Does not take the objects scrollFactor into account. All overlaps are check in world space. + * @param object1 The first GameObject or Group to check. If null the world.group is used. + * @param object2 The second GameObject or Group to check. + * @param notifyCallback A callback function that is called if the objects overlap. The two objects will be passed to this function in the same order in which you passed them to Collision.overlap. + * @param processCallback A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then notifyCallback will only be called if processCallback returns true. + * @returns {boolean} true if the objects overlap, otherwise false. + */ + overlap: function (object1, object2, notifyCallback, processCallback) { + + if (object1 == null) + { + object1 = this._game.world.group; + } + + if (object2 == object1) + { + object2 = null; + } + + Phaser.QuadTree.divisions = this.worldDivisions; + + var quadTree = new Phaser.QuadTree(this._game.world.bounds.x, this._game.world.bounds.y, this._game.world.bounds.width, this._game.world.bounds.height); + + quadTree.load(object1, object2, notifyCallback, processCallback); + + var result = quadTree.execute(); + + quadTree.destroy(); + + quadTree = null; + + return result; + + }, + + /** + * The core Collision separation function used by Collision.overlap. + * @param object1 The first GameObject to separate + * @param object2 The second GameObject to separate + * @returns {boolean} Returns true if the objects were separated, otherwise false. + */ + separate: function (object1, object2) { + + var separatedX = this.separateX(object1, object2); + var separatedY = this.separateY(object1, object2); + + return separatedX || separatedY; + + }, + + /** + * Separates the two objects on their x axis + * @param object1 The first GameObject to separate + * @param object2 The second GameObject to separate + * @returns {boolean} Whether the objects in fact touched and were separated along the X axis. + */ + separateX: function (object1, object2) { + + // Can't separate two immovable objects + if (object1.immovable && object2.immovable) + { + return false; + } + + // First, get the two object deltas + var overlap = 0; + var obj1Delta = object1.x - object1.last.x; + var obj2Delta = object2.x - object2.last.x; + + if (obj1Delta != obj2Delta) + { + // Check if the X hulls actually overlap + var obj1DeltaAbs = (obj1Delta > 0) ? obj1Delta : -obj1Delta; + var obj2DeltaAbs = (obj2Delta > 0) ? obj2Delta : -obj2Delta; + var obj1Bounds = new Quad(object1.x - ((obj1Delta > 0) ? obj1Delta : 0), object1.last.y, object1.width + ((obj1Delta > 0) ? obj1Delta : -obj1Delta), object1.height); + var obj2Bounds = new Quad(object2.x - ((obj2Delta > 0) ? obj2Delta : 0), object2.last.y, object2.width + ((obj2Delta > 0) ? obj2Delta : -obj2Delta), object2.height); + + if ((obj1Bounds.x + obj1Bounds.width > obj2Bounds.x) && (obj1Bounds.x < obj2Bounds.x + obj2Bounds.width) && (obj1Bounds.y + obj1Bounds.height > obj2Bounds.y) && (obj1Bounds.y < obj2Bounds.y + obj2Bounds.height)) + { + var maxOverlap = obj1DeltaAbs + obj2DeltaAbs + Collision.OVERLAP_BIAS; + + // If they did overlap (and can), figure out by how much and flip the corresponding flags + if (obj1Delta > obj2Delta) + { + overlap = object1.x + object1.width - object2.x; + + if ((overlap > maxOverlap) || !(object1.allowCollisions & Collision.RIGHT) || !(object2.allowCollisions & Collision.LEFT)) + { + overlap = 0; + } + else + { + object1.touching |= Collision.RIGHT; + object2.touching |= Collision.LEFT; + } + } + else if (obj1Delta < obj2Delta) + { + overlap = object1.x - object2.width - object2.x; + + if ((-overlap > maxOverlap) || !(object1.allowCollisions & Collision.LEFT) || !(object2.allowCollisions & Collision.RIGHT)) + { + overlap = 0; + } + else + { + object1.touching |= Collision.LEFT; + object2.touching |= Collision.RIGHT; + } + + } + + } + } + + // Then adjust their positions and velocities accordingly (if there was any overlap) + if (overlap != 0) + { + var obj1Velocity = object1.velocity.x; + var obj2Velocity = object2.velocity.x; + + if (!object1.immovable && !object2.immovable) + { + overlap *= 0.5; + object1.x = object1.x - overlap; + object2.x += overlap; + + var obj1NewVelocity = Math.sqrt((obj2Velocity * obj2Velocity * object2.mass) / object1.mass) * ((obj2Velocity > 0) ? 1 : -1); + var obj2NewVelocity = Math.sqrt((obj1Velocity * obj1Velocity * object1.mass) / object2.mass) * ((obj1Velocity > 0) ? 1 : -1); + var average = (obj1NewVelocity + obj2NewVelocity) * 0.5; + obj1NewVelocity -= average; + obj2NewVelocity -= average; + object1.velocity.x = average + obj1NewVelocity * object1.elasticity; + object2.velocity.x = average + obj2NewVelocity * object2.elasticity; + } + else if (!object1.immovable) + { + object1.x = object1.x - overlap; + object1.velocity.x = obj2Velocity - obj1Velocity * object1.elasticity; + } + else if (!object2.immovable) + { + object2.x += overlap; + object2.velocity.x = obj1Velocity - obj2Velocity * object2.elasticity; + } + + return true; + } + else + { + return false; + } + + }, + + /** + * Separates the two objects on their y axis + * @param object1 The first GameObject to separate + * @param object2 The second GameObject to separate + * @returns {boolean} Whether the objects in fact touched and were separated along the Y axis. + */ + separateY: function (object1, object2) { + + // Can't separate two immovable objects + if (object1.immovable && object2.immovable) { + return false; + } + + // First, get the two object deltas + var overlap = 0; + var obj1Delta = object1.y - object1.last.y; + var obj2Delta = object2.y - object2.last.y; + + if (obj1Delta != obj2Delta) + { + // Check if the Y hulls actually overlap + var obj1DeltaAbs = (obj1Delta > 0) ? obj1Delta : -obj1Delta; + var obj2DeltaAbs = (obj2Delta > 0) ? obj2Delta : -obj2Delta; + var obj1Bounds: Quad = new Quad(object1.x, object1.y - ((obj1Delta > 0) ? obj1Delta : 0), object1.width, object1.height + obj1DeltaAbs); + var obj2Bounds: Quad = new Quad(object2.x, object2.y - ((obj2Delta > 0) ? obj2Delta : 0), object2.width, object2.height + obj2DeltaAbs); + + if ((obj1Bounds.x + obj1Bounds.width > obj2Bounds.x) && (obj1Bounds.x < obj2Bounds.x + obj2Bounds.width) && (obj1Bounds.y + obj1Bounds.height > obj2Bounds.y) && (obj1Bounds.y < obj2Bounds.y + obj2Bounds.height)) + { + var maxOverlap = obj1DeltaAbs + obj2DeltaAbs + Collision.OVERLAP_BIAS; + + // If they did overlap (and can), figure out by how much and flip the corresponding flags + if (obj1Delta > obj2Delta) + { + overlap = object1.y + object1.height - object2.y; + + if ((overlap > maxOverlap) || !(object1.allowCollisions & Collision.DOWN) || !(object2.allowCollisions & Collision.UP)) + { + overlap = 0; + } + else + { + object1.touching |= Collision.DOWN; + object2.touching |= Collision.UP; + } + } + else if (obj1Delta < obj2Delta) + { + overlap = object1.y - object2.height - object2.y; + + if ((-overlap > maxOverlap) || !(object1.allowCollisions & Collision.UP) || !(object2.allowCollisions & Collision.DOWN)) + { + overlap = 0; + } + else + { + object1.touching |= Collision.UP; + object2.touching |= Collision.DOWN; + } + } + } + } + + // Then adjust their positions and velocities accordingly (if there was any overlap) + if (overlap != 0) + { + var obj1Velocity = object1.velocity.y; + var obj2Velocity = object2.velocity.y; + + if (!object1.immovable && !object2.immovable) + { + overlap *= 0.5; + object1.y = object1.y - overlap; + object2.y += overlap; + + var obj1NewVelocity = Math.sqrt((obj2Velocity * obj2Velocity * object2.mass) / object1.mass) * ((obj2Velocity > 0) ? 1 : -1); + var obj2NewVelocity = Math.sqrt((obj1Velocity * obj1Velocity * object1.mass) / object2.mass) * ((obj1Velocity > 0) ? 1 : -1); + var average = (obj1NewVelocity + obj2NewVelocity) * 0.5; + obj1NewVelocity -= average; + obj2NewVelocity -= average; + object1.velocity.y = average + obj1NewVelocity * object1.elasticity; + object2.velocity.y = average + obj2NewVelocity * object2.elasticity; + } + else if (!object1.immovable) + { + object1.y = object1.y - overlap; + object1.velocity.y = obj2Velocity - obj1Velocity * object1.elasticity; + // This is special case code that handles things like horizontal moving platforms you can ride + if (object2.active && object2.moves && (obj1Delta > obj2Delta)) + { + object1.x += object2.x - object2.last.x; + } + } + else if (!object2.immovable) + { + object2.y += overlap; + object2.velocity.y = obj1Velocity - obj2Velocity * object2.elasticity; + // This is special case code that handles things like horizontal moving platforms you can ride + if (object1.active && object1.moves && (obj1Delta < obj2Delta)) + { + object2.x += object1.x - object1.last.x; + } + } + + return true; + } + else + { + return false; + } + }, + + + + }; Phaser.Physics.Arcade.prototype.OVERLAP_BIAS = 4; Phaser.Physics.Arcade.prototype.TILE_OVERLAP = false; + diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index 5778616d..7ad0df5a 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -24,6 +24,7 @@ Phaser.Physics.Arcade.Body = function (sprite) { this.maxAngular = 1000; this.mass = 1; + this.immovable = false; this.touching = 0; this.wasTouching = 0; this.allowCollisions = 1; @@ -54,9 +55,6 @@ Phaser.Physics.Arcade.Body.prototype = { this.hitArea.centerX = x; this.hitArea.centerY = y; - // this._ox = x; - // this._oy = y; - }, updateMotion: function () {