Flixel physics optimised about as much as it can be. Also added world and local gravity support and flag to toggle it on / off.

This commit is contained in:
Richard Davey
2013-09-04 01:10:01 +01:00
parent 0f438d5221
commit 2a353a0327
3 changed files with 145 additions and 110 deletions
+17 -6
View File
@@ -26,27 +26,38 @@
function create() {
game.world._stage.backgroundColorString = '#182d3b';
// game.physics.gravity.y = 10;
bunny = game.add.sprite(200, 200, 'bunny');
bunny.body.bounce.x = 0.8;
bunny = game.add.sprite(200, 100, 'bunny');
bunny.body.bounce.y = 0.5;
// bunny.body.gravity.y = -10;
// bunny.body.setSize(20, 100);
// bunny.body.offset.setTo(25, -20);
// bunny.anchor.setTo(0.5, 0.5);
wall = game.add.sprite(700, 200, 'bunny');
wall = game.add.sprite(200, 450, 'bunny');
wall.body.immovable = true;
wall.body.allowGravity = false;
bunny.body.velocity.x = 180;
// bunny.body.angularVelocity = 1;
bunny.body.velocity.x = 30;
// bunny.body.velocity.y = 120;
// bunny.body.velocity.y = 50;
}
function update() {
game.physics.separateX(bunny.body, wall.body);
// bunny.rotation += 0.01;
game.physics.separate(bunny.body, wall.body);
}
function render() {
game.debug.renderSpriteCorners(bunny, true, true);
game.debug.renderRectangle(bunny.body.hitArea);
game.debug.renderRectangle(bunny.body.bounds);
game.debug.renderRectangle(wall.body.bounds);
}
+60 -73
View File
@@ -4,7 +4,8 @@ Phaser.Physics.Arcade = function (game) {
this.game = game;
this._length = 0;
this.gravity = new Phaser.Point;
this.bounds = new Phaser.Rectangle(0, 0, game.world.width, game.world.height);
/**
* @type {number}
@@ -20,11 +21,11 @@ Phaser.Physics.Arcade = function (game) {
this.FLOOR = this.DOWN;
this.WALL = this.LEFT | this.RIGHT;
this.ANY = this.LEFT | this.RIGHT | this.UP | this.DOWN;
// console.log('any', this.ANY);
this.OVERLAP_BIAS = 4;
this.TILE_OVERLAP = false;
// avoid creating these every frame, per collision
// avoid gc spikes by caching these values for re-use
this._obj1Bounds = new Phaser.Rectangle;
this._obj2Bounds = new Phaser.Rectangle;
this._overlap = 0;
@@ -35,14 +36,6 @@ Phaser.Physics.Arcade = function (game) {
this._obj2NewVelocity = 0;
this._average = 0;
// this.angularDrag = 0;
// this.gravity = new Phaser.Point;
// this.drag = new Phaser.Point;
// this.bounce = new Phaser.Point;
// this.bounds = new Phaser.Rectangle(0, 0, game.world.width, game.world.height);
// this._distance = new Phaser.Point;
// this._tangent = new Phaser.Point;
};
Phaser.Physics.Arcade.prototype = {
@@ -55,21 +48,21 @@ Phaser.Physics.Arcade.prototype = {
updateMotion: function (body) {
this._velocityDelta = (this.computeVelocity(body.angularVelocity, body.gravity.x, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity) / 2;
body.angularVelocity += this._velocityDelta;
body.sprite.rotation += body.angularVelocity * this.game.time.physicsElapsed;
// Rotation
this._velocityDelta = (this.computeVelocity(0, false, body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity) / 2;
body.angularVelocity += this._velocityDelta;
body.rotation += body.angularVelocity * this.game.time.physicsElapsed;
this._velocityDelta = (this.computeVelocity(body.velocity.x, body.gravity.x, body.acceleration.x, body.drag.x) - body.velocity.x) / 2;
body.velocity.x += this._velocityDelta;
this._delta = body.velocity.x * this.game.time.physicsElapsed;
// Horizontal
this._velocityDelta = (this.computeVelocity(1, body, body.velocity.x, body.acceleration.x, body.drag.x) - body.velocity.x) / 2;
body.velocity.x += this._velocityDelta;
this._delta = body.velocity.x * this.game.time.physicsElapsed;
body.x += this._delta;
this._velocityDelta = (this.computeVelocity(body.velocity.y, body.gravity.y, body.acceleration.y, body.drag.y) - body.velocity.y) / 2;
// Vertical
this._velocityDelta = (this.computeVelocity(2, body, body.velocity.y, body.acceleration.y, body.drag.y) - body.velocity.y) / 2;
body.velocity.y += this._velocityDelta;
this._delta = body.velocity.y * this.game.time.physicsElapsed;
body.velocity.y += this._velocityDelta;
body.y += this._delta;
},
@@ -84,16 +77,22 @@ Phaser.Physics.Arcade.prototype = {
*
* @return {number} The altered Velocity value.
*/
computeVelocity: function (velocity, gravity, acceleration, drag, max) {
computeVelocity: function (axis, body, velocity, acceleration, drag, max) {
gravity = gravity || 0;
acceleration = acceleration || 0;
drag = drag || 0;
max = max || 10000;
if (axis == 1 && body.allowGravity)
{
velocity += this.gravity.x + body.gravity.x;
}
else if (axis == 2 && body.allowGravity)
{
velocity += this.gravity.y + body.gravity.y;
}
if (acceleration !== 0)
{
velocity += (acceleration + gravity) * this.game.time.physicsElapsed;
velocity += acceleration * this.game.time.physicsElapsed;
}
else if (drag !== 0)
{
@@ -111,11 +110,9 @@ Phaser.Physics.Arcade.prototype = {
{
velocity = 0;
}
velocity += gravity;
}
if ((velocity != 0) && (max != 10000))
if (velocity != 0)
{
if (velocity > max)
{
@@ -176,10 +173,7 @@ Phaser.Physics.Arcade.prototype = {
*/
separate: function (object1, object2) {
var separatedX = this.separateX(object1, object2);
var separatedY = this.separateY(object1, object2);
return separatedX || separatedY;
return this.separateX(object1, object2) || this.separateY(object1, object2)
},
@@ -207,7 +201,7 @@ Phaser.Physics.Arcade.prototype = {
this._obj1Bounds.setTo(object1.x - ((object1.deltaX() > 0) ? object1.deltaX() : 0), object1.lastY, object1.width + ((object1.deltaX() > 0) ? object1.deltaX() : -object1.deltaX()), object1.height);
this._obj2Bounds.setTo(object2.x - ((object2.deltaX() > 0) ? object2.deltaX() : 0), object2.lastY, object2.width + ((object2.deltaX() > 0) ? object2.deltaX() : -object2.deltaX()), object2.height);
if ((this._obj1Bounds.x + this._obj1Bounds.width > this._obj2Bounds.x) && (this._obj1Bounds.x < this._obj2Bounds.x + this._obj2Bounds.width) && (this._obj1Bounds.y + this._obj1Bounds.height > this._obj2Bounds.y) && (this._obj1Bounds.y < this._obj2Bounds.y + this._obj2Bounds.height))
if ((this._obj1Bounds.right > this._obj2Bounds.x) && (this._obj1Bounds.x < this._obj2Bounds.right) && (this._obj1Bounds.bottom > this._obj2Bounds.y) && (this._obj1Bounds.y < this._obj2Bounds.bottom))
{
this._maxOverlap = object1.deltaAbsX() + object2.deltaAbsX() + this.OVERLAP_BIAS;
@@ -239,9 +233,7 @@ Phaser.Physics.Arcade.prototype = {
object1.touching |= this.LEFT;
object2.touching |= this.RIGHT;
}
}
}
}
@@ -275,7 +267,6 @@ Phaser.Physics.Arcade.prototype = {
object2.x += this._overlap;
object2.velocity.x = this._obj1Velocity - this._obj2Velocity * object2.bounce.x;
}
return true;
}
else
@@ -294,100 +285,96 @@ Phaser.Physics.Arcade.prototype = {
separateY: function (object1, object2) {
// Can't separate two immovable objects
if (object1.immovable && object2.immovable) {
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;
this._overlap = 0;
if (obj1Delta != obj2Delta)
if (object1.deltaY() != object2.deltaY())
{
// Check if the Y hulls actually overlap
var obj1DeltaAbs = (obj1Delta > 0) ? obj1Delta : -obj1Delta;
var obj2DeltaAbs = (obj2Delta > 0) ? obj2Delta : -obj2Delta;
this._obj1Bounds = new Phaser.Rectangle(object1.x, object1.y - ((obj1Delta > 0) ? obj1Delta : 0), object1.width, object1.height + obj1DeltaAbs);
this._obj2Bounds = new Phaser.Rectangle(object2.x, object2.y - ((obj2Delta > 0) ? obj2Delta : 0), object2.width, object2.height + obj2DeltaAbs);
this._obj1Bounds.setTo(object1.x, object1.y - ((object1.deltaY() > 0) ? object1.deltaY() : 0), object1.width, object1.height + object1.deltaAbsY());
this._obj2Bounds.setTo(object2.x, object2.y - ((object2.deltaY() > 0) ? object2.deltaY() : 0), object2.width, object2.height + object2.deltaAbsY());
if ((this._obj1Bounds.x + this._obj1Bounds.width > this._obj2Bounds.x) && (this._obj1Bounds.x < this._obj2Bounds.x + this._obj2Bounds.width) && (this._obj1Bounds.y + this._obj1Bounds.height > this._obj2Bounds.y) && (this._obj1Bounds.y < this._obj2Bounds.y + this._obj2Bounds.height))
if ((this._obj1Bounds.right > this._obj2Bounds.x) && (this._obj1Bounds.x < this._obj2Bounds.right) && (this._obj1Bounds.bottom > this._obj2Bounds.y) && (this._obj1Bounds.y < this._obj2Bounds.bottom))
{
var maxOverlap = obj1DeltaAbs + obj2DeltaAbs + Collision.OVERLAP_BIAS;
this._maxOverlap = object1.deltaAbsY() + object2.deltaAbsY() + this.OVERLAP_BIAS;
// If they did overlap (and can), figure out by how much and flip the corresponding flags
if (obj1Delta > obj2Delta)
if (object1.deltaY() > object2.deltaY())
{
overlap = object1.y + object1.height - object2.y;
this._overlap = object1.y + object1.height - object2.y;
if ((overlap > maxOverlap) || !(object1.allowCollisions & Collision.DOWN) || !(object2.allowCollisions & Collision.UP))
if ((this._overlap > this._maxOverlap) || !(object1.allowCollisions & this.DOWN) || !(object2.allowCollisions & this.UP))
{
overlap = 0;
this._overlap = 0;
}
else
{
object1.touching |= Collision.DOWN;
object2.touching |= Collision.UP;
object1.touching |= this.DOWN;
object2.touching |= this.UP;
}
}
else if (obj1Delta < obj2Delta)
else if (object1.deltaY() < object2.deltaY())
{
overlap = object1.y - object2.height - object2.y;
this._overlap = object1.y - object2.height - object2.y;
if ((-overlap > maxOverlap) || !(object1.allowCollisions & Collision.UP) || !(object2.allowCollisions & Collision.DOWN))
if ((-this._overlap > this._maxOverlap) || !(object1.allowCollisions & this.UP) || !(object2.allowCollisions & this.DOWN))
{
overlap = 0;
this._overlap = 0;
}
else
{
object1.touching |= Collision.UP;
object2.touching |= Collision.DOWN;
object1.touching |= this.UP;
object2.touching |= this.DOWN;
}
}
}
}
// Then adjust their positions and velocities accordingly (if there was any overlap)
if (overlap != 0)
if (this._overlap != 0)
{
this._obj1Velocity = object1.velocity.y;
this._obj2Velocity = object2.velocity.y;
if (!object1.immovable && !object2.immovable)
{
overlap *= 0.5;
object1.y = object1.y - overlap;
object2.y += overlap;
this._overlap *= 0.5;
object1.y = object1.y - this._overlap;
object2.y += this._overlap;
this._obj1NewVelocity = Math.sqrt((this._obj2Velocity * this._obj2Velocity * object2.mass) / object1.mass) * ((this._obj2Velocity > 0) ? 1 : -1);
this._obj2NewVelocity = Math.sqrt((this._obj1Velocity * this._obj1Velocity * object1.mass) / object2.mass) * ((this._obj1Velocity > 0) ? 1 : -1);
this._average = (this._obj1NewVelocity + this._obj2NewVelocity) * 0.5;
this._obj1NewVelocity -= this._average;
this._obj2NewVelocity -= this._average;
object1.velocity.y = this._average + this._obj1NewVelocity * object1.elasticity;
object2.velocity.y = this._average + this._obj2NewVelocity * object2.elasticity;
object1.velocity.y = this._average + this._obj1NewVelocity * object1.bounce.y;
object2.velocity.y = this._average + this._obj2NewVelocity * object2.bounce.y;
}
else if (!object1.immovable)
{
object1.y = object1.y - overlap;
object1.velocity.y = this._obj2Velocity - this._obj1Velocity * object1.elasticity;
object1.y = object1.y - this._overlap;
object1.velocity.y = this._obj2Velocity - this._obj1Velocity * object1.bounce.y;
// This is special case code that handles things like horizontal moving platforms you can ride
if (object2.active && object2.moves && (obj1Delta > obj2Delta))
if (object2.active && object2.moves && (object1.deltaY() > object2.deltaY()))
{
object1.x += object2.x - object2.last.x;
object1.x += object2.x - object2.lastX;
}
}
else if (!object2.immovable)
{
object2.y += overlap;
object2.velocity.y = this._obj1Velocity - this._obj2Velocity * object2.elasticity;
object2.y += this._overlap;
object2.velocity.y = this._obj1Velocity - this._obj2Velocity * object2.bounce.y;
// This is special case code that handles things like horizontal moving platforms you can ride
if (object1.active && object1.moves && (obj1Delta < obj2Delta))
if (object1.sprite.active && object1.moves && (object1.deltaY() < object2.deltaY()))
{
object2.x += object1.x - object1.last.x;
object2.x += object1.x - object1.lastX;
}
}
return true;
}
else
+68 -31
View File
@@ -3,11 +3,25 @@ Phaser.Physics.Arcade.Body = function (sprite) {
this.sprite = sprite;
this.game = sprite.game;
this.hitArea = new Phaser.Rectangle(sprite.x, sprite.y, sprite.currentFrame.sourceSizeW, sprite.currentFrame.sourceSizeH);
this.offset = new Phaser.Point;
this.width = this.hitArea.width;
this.height = this.hitArea.height;
// the top-left of the Body
this.x = sprite.x;
this.y = sprite.y;
// un-scaled original size
this.sourceWidth = sprite.currentFrame.sourceSizeW;
this.sourceHeight = sprite.currentFrame.sourceSizeH;
// calculated (scaled) size
this.width = sprite.currentFrame.sourceSizeW;
this.height = sprite.currentFrame.sourceSizeH;
this.halfWidth = Math.floor(sprite.currentFrame.sourceSizeW / 2);
this.halfHeight = Math.floor(sprite.currentFrame.sourceSizeH / 2);
this.bounds = new Phaser.Rectangle(sprite.x, sprite.y, this.width, this.height);
// Scale value cache
this._sx = sprite.scale.x;
this._sy = sprite.scale.y;
@@ -24,13 +38,26 @@ Phaser.Physics.Arcade.Body = function (sprite) {
this.maxAngular = 1000;
this.mass = 1;
// Handy consts
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.immovable = false;
this.moves = true;
this.touching = 0;
this.wasTouching = 0;
this.allowCollisions = 4369;
this.rotation = 0;
this.allowCollisions = this.ANY;
this.allowRotation = false;
this.allowGravity = true;
this.x = sprite.x;
this.y = sprite.y;
this.lastX = sprite.x;
this.lastY = sprite.y;
@@ -38,23 +65,20 @@ Phaser.Physics.Arcade.Body = function (sprite) {
Phaser.Physics.Arcade.Body.prototype = {
sprite: null,
game: null,
hitArea: null,
updateBounds: function (x, y, scaleX, scaleY) {
updateBounds: function (centerX, centerY, scaleX, scaleY) {
if (scaleX != this._sx || scaleY != this._sy)
{
this.hitArea.width = this.width * scaleX;
this.hitArea.height = this.height * scaleY;
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.bounds.width = this.width;
this.bounds.height = this.height;
this._sx = scaleX;
this._sy = scaleY;
}
this.hitArea.centerX = x;
this.hitArea.centerY = y;
},
update: function () {
@@ -64,49 +88,62 @@ Phaser.Physics.Arcade.Body.prototype = {
this.game.physics.updateMotion(this);
// delta force - _x and _y now contain the new positions, so work out the deltas
// separation and stuff happens here
this.bounds.x = this.x;
this.bounds.y = this.y;
},
postUpdate: function () {
this.sprite.x = this.x;
this.sprite.y = this.y;
this.sprite.x = this.x - this.offset.x + (this.sprite.anchor.x * this.width);
this.sprite.y = this.y - this.offset.y + (this.sprite.anchor.y * this.height);
if (this.allowRotation)
{
this.sprite.angle = this.rotation;
}
},
setSize: function (width, height) {
setSize: function (width, height, offsetX, offsetY) {
this.width = width;
this.height = height;
this.hitArea.width = this.width * scaleX;
this.hitArea.height = this.height * scaleY;
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.bounds.width = this.width;
this.bounds.height = this.height;
this.offset.setTo(offsetX, offsetY);
},
hullWidth: function () {
if (this.deltaX > 0)
if (this.deltaX() > 0)
{
return this.hitArea.width + this.deltaX;
return this.width + this.deltaX();
}
else
{
return this.hitArea.width - this.deltaX;
return this.width - this.deltaX();
}
},
hullHeight: function () {
if (this.deltaY > 0)
if (this.deltaY() > 0)
{
return this.hitArea.height + this.deltaY;
return this.height + this.deltaY();
}
else
{
return this.hitArea.height - this.deltaY;
return this.height - this.deltaY();
}
},