From 651737fdd02755d6d373298dd6934f104493c2ac Mon Sep 17 00:00:00 2001 From: photonstorm Date: Wed, 15 Jan 2014 03:17:26 +0000 Subject: [PATCH] More physics tweaks. --- examples/wip/blocked.js | 245 ++++++++++++++++++++++++++++ src/physics/arcade/ArcadePhysics.js | 192 ++++++++++++++++++---- src/physics/arcade/Body.js | 177 +++++++++++--------- src/utils/Debug.js | 13 +- 4 files changed, 520 insertions(+), 107 deletions(-) create mode 100644 examples/wip/blocked.js diff --git a/examples/wip/blocked.js b/examples/wip/blocked.js new file mode 100644 index 00000000..b04e4599 --- /dev/null +++ b/examples/wip/blocked.js @@ -0,0 +1,245 @@ + +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('chunk', 'assets/sprites/chunk.png'); + game.load.image('arrow', 'assets/sprites/asteroids_ship.png'); + game.load.image('p', 'assets/sprites/mushroom2.png'); + game.load.image('ball', 'assets/sprites/shinyball.png'); + +} + +var sprite; +var sprite2; + +var track; +var bmd; + +function create() { + + game.stage.backgroundColor = '#124184'; + + bmd = game.add.bitmapData(800, 600); + bmd.fillStyle('#ffffff'); + var bg = game.add.sprite(0, 0, bmd); + bg.body.moves = false; + + test8(); + +} + +// gravity into floor jiggle +function test8() { + + game.physics.gravity.y = 150; + + sprite = game.add.sprite(400, 600-100, 'ball'); + sprite.body.moves = false; + sprite.body.collideWorldBounds = true; + sprite.body.bounce.setTo(0.8, 0.8); + + sprite2 = game.add.sprite(500, 100, 'ball'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.5, 0.5); + // sprite2.body.friction = 0.1; + // sprite2.body.canSleep = true; + + track = sprite2; + + game.input.onDown.add(launch8, this); + +} + +function launch8() { + + sprite.body.velocity.y = -200; + // sprite2.body.velocity.y = 200; + +} + +// both sprites are shot into each other vertically +function test7() { + + // game.physics.gravity.y = 50; + + sprite = game.add.sprite(400, 600, 'ball'); + sprite.body.collideWorldBounds = true; + sprite.body.bounce.setTo(0.8, 0.8); + + sprite2 = game.add.sprite(400, 100, 'ball'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + + game.input.onDown.add(launch7, this); + +} + +function launch7() { + + sprite.body.velocity.y = -200; + // sprite2.body.velocity.y = 200; + +} + + +// sprite is on the bottom, blocked by the world bounds, sprite2 falls onto it via gravity only +function test6() { + + game.physics.gravity.y = 100; + + sprite = game.add.sprite(380, 600, 'p'); + sprite.body.collideWorldBounds = true; + + sprite2 = game.add.sprite(400, 100, 'ball'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + +} + +// sprite is on the bottom, blocked by the world bounds, sprite2 falls onto it +function test5() { + + game.physics.gravity.y = 50; + + sprite = game.add.sprite(400, 600, 'ball'); + sprite.body.collideWorldBounds = true; + + sprite2 = game.add.sprite(400, 100, 'ball'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + + game.input.onDown.add(launch5, this); + +} + +function launch5() { + + sprite2.body.velocity.y = 200; + +} + + +// bounce both sprites into each other, one with lots less velocity - checking newtons craddle approach +function test4() { + + game.physics.gravity.y = 100; + + sprite = game.add.sprite(780, 400, 'ball'); + sprite.body.collideWorldBounds = true; + sprite.body.bounce.setTo(0.8, 0.8); + + sprite2 = game.add.sprite(0, 400, 'ball'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + + game.input.onDown.add(launch4, this); + +} + +function launch4() { + + sprite.body.velocity.x = 70; + sprite2.body.velocity.x = -250; + +} + +// bounce both sprites into each other, identical bounce + velocity +function test3() { + + game.physics.gravity.y = 100; + + sprite = game.add.sprite(780, 400, 'p'); + sprite.body.collideWorldBounds = true; + sprite.body.bounce.setTo(0.8, 0.8); + + sprite2 = game.add.sprite(0, 400, 'p'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + + game.input.onDown.add(launch3, this); + +} + +function launch3() { + + sprite.body.velocity.x = 225; + sprite2.body.velocity.x = -225; + +} + +// sprite is on the right, blocked by the world bounds, sprite2 bounces into it +function test2() { + + game.physics.gravity.y = 100; + + sprite = game.add.sprite(780, 400, 'p'); + sprite.body.collideWorldBounds = true; + + sprite2 = game.add.sprite(0, 400, 'p'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + + game.input.onDown.add(launch2, this); + +} + +function launch2() { + + sprite2.body.velocity.x = -225; + +} + +// sprite is on the left, blocked by the world bounds, sprite2 bounces into it +function test1() { + + game.physics.gravity.y = 100; + + sprite = game.add.sprite(0, 400, 'p'); + sprite.body.collideWorldBounds = true; + + sprite2 = game.add.sprite(700, 400, 'p'); + sprite2.body.collideWorldBounds = true; + sprite2.body.bounce.setTo(0.8, 0.8); + + track = sprite2; + + game.input.onDown.add(launch1, this); + +} + +function launch1() { + + sprite2.body.velocity.x = -225; + +} + +function update() { + + game.physics.collide(sprite, sprite2); + + // sprite.rotation = sprite.body.angle; + + bmd.fillStyle('#ffff00'); + bmd.fillRect(track.body.center.x, track.body.center.y, 2, 2); + +} + +function render() { + + game.debug.renderBodyInfo(sprite, 16, 24); + game.debug.renderBodyInfo(sprite2, 16, 190); + +} diff --git a/src/physics/arcade/ArcadePhysics.js b/src/physics/arcade/ArcadePhysics.js index a626bfec..74a2c884 100644 --- a/src/physics/arcade/ArcadePhysics.js +++ b/src/physics/arcade/ArcadePhysics.js @@ -177,6 +177,7 @@ Phaser.Physics.Arcade.prototype = { // If you're wondering why the velocity is halved and applied twice, read this: http://www.niksula.hut.fi/~hkankaan/Homepages/gravity.html + // World gravity is allowed if (body.allowGravity) { this._gravityX = this.gravity.x + body.gravity.x; @@ -188,6 +189,17 @@ Phaser.Physics.Arcade.prototype = { this._gravityY = body.gravity.y; } + // Don't apply gravity to any body that is blocked + if ((this._gravityX < 0 && body.blocked.left) || (this._gravityX > 0 && body.blocked.right)) + { + this._gravityX = 0; + } + + if ((this._gravityY < 0 && body.blocked.up) || (this._gravityY > 0 && body.blocked.down)) + { + this._gravityY = 0; + } + // Rotation if (body.allowRotation) { @@ -638,30 +650,92 @@ Phaser.Physics.Arcade.prototype = { if (!body1.immovable && !body2.immovable) { - this._overlap *= 0.5; - body1.overlapX = this._overlap; - body2.overlapX = this._overlap; + // 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; - body1.x = body1.x - this._overlap; - body2.x += this._overlap; + this._newVelocity1 = Math.sqrt((this._velocity2 * this._velocity2 * body2.mass) / body1.mass) * ((this._velocity2 > 0) ? 1 : -1); + this._newVelocity2 = Math.sqrt((this._velocity1 * this._velocity1 * body1.mass) / body2.mass) * ((this._velocity1 > 0) ? 1 : -1); + this._average = (this._newVelocity1 + this._newVelocity2) * 0.5; + this._newVelocity1 -= this._average; + this._newVelocity2 -= this._average; - 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; + } - body1.velocity.x = this._average + this._newVelocity1 * body1.bounce.x; - body2.velocity.x = this._average + this._newVelocity2 * body2.bounce.x; + 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) { - body1.x = body1.x - this._overlap; + 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) { - body2.x += this._overlap; + if (body2.deltaX() < 0) + { + body2.x += this._overlap; + } + else + { + body2.x -= this._overlap; + } + body2.velocity.x = this._velocity1 - this._velocity2 * body2.bounce.x; } } @@ -722,25 +796,79 @@ Phaser.Physics.Arcade.prototype = { if (!body1.immovable && !body2.immovable) { - this._overlap *= 0.5; - body1.overlapY = this._overlap; - body2.overlapY = this._overlap; + // 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; - body1.y = body1.y - this._overlap; - body2.y += 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; - 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; + } - body1.velocity.y = this._average + this._newVelocity1 * body1.bounce.y; - body2.velocity.y = this._average + this._newVelocity2 * body2.bounce.y; + 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) { - body1.y -= this._overlap; + 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 @@ -751,7 +879,15 @@ Phaser.Physics.Arcade.prototype = { } else if (!body2.immovable) { - body2.y += this._overlap; + 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 diff --git a/src/physics/arcade/Body.js b/src/physics/arcade/Body.js index abaee275..242fd036 100644 --- a/src/physics/arcade/Body.js +++ b/src/physics/arcade/Body.js @@ -387,34 +387,42 @@ Phaser.Physics.Arcade.Body.prototype = { if (this.moves) { - this.game.physics.updateMotion(this); + if (this.collideWorldBounds) + { + this.checkWorldBounds(); + } - if (this.canSleep) - { - if (!this.sleeping) - { - if (this.velocity.x >= this.sleepMin.x && this.velocity.x <= this.sleepMax.x && this.velocity.y >= this.sleepMin.y && this.velocity.y <= this.sleepMax.y) - { - if (this._sleepTimer >= this.sleepDuration) - { - this.sleeping = true; - } - else - { - this._sleepTimer += this.game.time.elapsed; - this.applyMotion(); - } - } - else - { - this.applyMotion(); - } - } - } - else - { - this.applyMotion(); - } + // Apply world gravity, acceleration + rotation + this.game.physics.updateMotion(this); + + this.applyMotion(); + + // if (this.canSleep) + // { + // if (!this.sleeping) + // { + // if (this.velocity.x >= this.sleepMin.x && this.velocity.x <= this.sleepMax.x && this.velocity.y >= this.sleepMin.y && this.velocity.y <= this.sleepMax.y) + // { + // if (this._sleepTimer >= this.sleepDuration) + // { + // this.sleeping = true; + // } + // else + // { + // this._sleepTimer += this.game.time.elapsed; + // this.applyMotion(); + // } + // } + // else + // { + // this.applyMotion(); + // } + // } + // } + // else + // { + // this.applyMotion(); + // } } this.prevVelocity.copyFrom(this.velocity); @@ -444,12 +452,36 @@ Phaser.Physics.Arcade.Body.prototype = { this.velocity.y = Math.sin(this.angle) * this.speed; } - this.x += this.game.time.physicsElapsed * (this.velocity.x + this.motionVelocity.x / 2); - this.velocity.x += this.motionVelocity.x; + // overlapX/Y values at this point will be penetration into the bounds + if (this.blocked.down) + { + this.y -= this.overlapY; + } + else if (this.blocked.up) + { + this.y += this.overlapY; + } + this.x += this.game.time.physicsElapsed * (this.velocity.x + this.motionVelocity.x / 2); this.y += this.game.time.physicsElapsed * (this.velocity.y + this.motionVelocity.y / 2); + + this.velocity.x += this.motionVelocity.x; this.velocity.y += this.motionVelocity.y; + if (this.blocked.down && this.deltaY() > 0) + { + this.velocity.y *= -this.bounce.y; + } + else if (this.blocked.up && this.deltaY() < 0) + { + this.velocity.y *= -this.bounce.y; + } + + if (this.collideWorldBounds) + { + // this.checkWorldBounds(); + } + if (this.velocity.x > this.maxVelocity.x) { this.velocity.x = this.maxVelocity.x; @@ -468,21 +500,6 @@ Phaser.Physics.Arcade.Body.prototype = { this.velocity.y = -this.maxVelocity.y; } - if (this.collideWorldBounds) - { - this.checkWorldBounds(); - - if (this.blocked.left || this.blocked.right) - { - // this.preX = this.x; - } - - if (this.blocked.up || this.blocked.down) - { - // this.preX = this.x; - } - } - }, /** @@ -495,31 +512,42 @@ Phaser.Physics.Arcade.Body.prototype = { if (this.moves) { - if (this.deltaX() < 0 && this.blocked.left === false) + if (this.deltaX() < 0) { this.facing = Phaser.LEFT; - this.sprite.x += this.deltaX(); + + if (this.blocked.left === false) + { + this.sprite.x += this.deltaX(); + } } - else if (this.deltaX() > 0 && this.blocked.right === false) + else if (this.deltaX() > 0) { this.facing = Phaser.RIGHT; - this.sprite.x += this.deltaX(); + + if (this.blocked.right === false) + { + this.sprite.x += this.deltaX(); + } } - if (this.deltaY() < 0 && this.blocked.up === false) + if (this.deltaY() < 0) { this.facing = Phaser.UP; - this.sprite.y += this.deltaY(); + + if (this.blocked.up === false) + { + this.sprite.y += this.deltaY(); + } } - else if (this.deltaY() > 0 && this.blocked.down === false) + else if (this.deltaY() > 0) { this.facing = Phaser.DOWN; - this.sprite.y += this.deltaY(); - } - if (this.collideWorldBounds) - { - this.checkWorldBounds(); + if (this.blocked.down === false) + { + this.sprite.y += this.deltaY(); + } } this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight); @@ -540,39 +568,42 @@ Phaser.Physics.Arcade.Body.prototype = { */ checkWorldBounds: function () { - var vx = this.velocity.x; - var vy = this.velocity.y; - - if (this.x < this.game.world.bounds.x) + if (this.x <= this.game.world.bounds.x) { + this.overlapX = this.game.world.bounds.x - this.x; this.blocked.left = true; - this.x = this.game.world.bounds.x; - this.velocity.x *= -this.bounce.x; - // console.log(this._debug, 'hit left', vx,'to',this.velocity.x); + // this.x = this.game.world.bounds.x; + // this.preX = this.x; + // this.velocity.x *= -this.bounce.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.blocked.right = true; - this.x = this.game.world.bounds.right - this.width; - this.velocity.x *= -this.bounce.x; - // console.log(this._debug, 'hit right', vx,'to',this.velocity.x); + // this.x = this.game.world.bounds.right - this.width; + // this.preX = this.x; + // this.velocity.x *= -this.bounce.x; } if (this.y < this.game.world.bounds.y) { + this.overlapY = this.game.world.bounds.y - this.y; this.blocked.up = true; - this.y = this.game.world.bounds.y; - this.velocity.y *= -this.bounce.y; - // console.log(this._debug, 'hit top', vy,'to',this.velocity.y); + // this.y = this.game.world.bounds.y; + // this.preY = this.y; + // this.velocity.y *= -this.bounce.y; } else if (this.bottom > this.game.world.bounds.bottom) { + this.overlapY = this.bottom - this.game.world.bounds.bottom; this.blocked.down = true; - this.y = this.game.world.bounds.bottom - this.height; - this.velocity.y *= -this.bounce.y; - // console.log(this._debug, 'hit bottom', vy,'to',this.velocity.y); + // this.y = this.game.world.bounds.bottom - this.height; + // this.preY = this.y; + // this.velocity.y *= -this.bounce.y; } + console.log('checkWorldBounds', this.overlapX, this.overlapY); + }, /** diff --git a/src/utils/Debug.js b/src/utils/Debug.js index a77316c2..303d4a65 100644 --- a/src/utils/Debug.js +++ b/src/utils/Debug.js @@ -456,15 +456,16 @@ Phaser.Utils.Debug.prototype = { this.splitline('x: ' + sprite.body.x.toFixed(2), 'y: ' + sprite.body.y.toFixed(2), 'width: ' + sprite.width, 'height: ' + sprite.height); this.splitline('speed: ' + sprite.body.speed.toFixed(2), 'angle: ' + sprite.body.angle.toFixed(2), 'friction: ' + sprite.body.friction); - this.splitline('gravity x: ' + sprite.body.gravity.x, 'y: ' + sprite.body.gravity.y); - this.splitline('world gravity x: ' + this.game.physics.gravity.x, 'y: ' + this.game.physics.gravity.y); + this.splitline('blocked left: ' + sprite.body.blocked.left, 'right: ' + sprite.body.blocked.right, 'up: ' + sprite.body.blocked.up, 'down: ' + sprite.body.blocked.down); + this.splitline('touching left: ' + sprite.body.touching.left, 'right: ' + sprite.body.touching.right, 'up: ' + sprite.body.touching.up, 'down: ' + sprite.body.touching.down); + this.splitline('gravity x: ' + sprite.body.gravity.x, 'y: ' + sprite.body.gravity.y, 'world gravity x: ' + this.game.physics.gravity.x, 'y: ' + this.game.physics.gravity.y); this.splitline('acceleration x: ' + sprite.body.acceleration.x.toFixed(2), 'y: ' + sprite.body.acceleration.y.toFixed(2)); - this.splitline('velocity x: ' + sprite.body.velocity.x.toFixed(2), 'y: ' + sprite.body.velocity.y.toFixed(2)); + this.splitline('velocity x: ' + sprite.body.velocity.x.toFixed(2), 'y: ' + sprite.body.velocity.y.toFixed(2), 'deltaX: ' + sprite.body.deltaX().toFixed(2), 'deltaY: ' + sprite.body.deltaY().toFixed(2)); this.splitline('motion x: ' + sprite.body.motionVelocity.x.toFixed(2), 'y: ' + sprite.body.motionVelocity.y.toFixed(2)); this.splitline('bounce x: ' + sprite.body.bounce.x.toFixed(2), 'y: ' + sprite.body.bounce.y.toFixed(2)); - this.splitline('sleeping: ' + sprite.body.sleeping, 'sleepTimer: ' + sprite.body._sleepTimer.toFixed(2)); - this.splitline('sleepMin x: ' + sprite.body.sleepMin.x, 'y: ' + sprite.body.sleepMin.y); - this.splitline('sleepMax x: ' + sprite.body.sleepMax.x, 'y: ' + sprite.body.sleepMax.y); + // this.splitline('sleeping: ' + sprite.body.sleeping, 'sleepTimer: ' + sprite.body._sleepTimer.toFixed(2)); + // this.splitline('sleepMin x: ' + sprite.body.sleepMin.x, 'y: ' + sprite.body.sleepMin.y); + // this.splitline('sleepMax x: ' + sprite.body.sleepMax.x, 'y: ' + sprite.body.sleepMax.y); this.stop(); },