mirror of
https://github.com/photonstorm/phaser
synced 2024-11-27 23:20:59 +00:00
Ported over Arcade Physics into V3 and started working through the classes and functions.
This commit is contained in:
parent
7cf82f320b
commit
9117b909a8
8 changed files with 1565 additions and 20 deletions
20
v3/src/physics/arcade/Arcade.js
Normal file
20
v3/src/physics/arcade/Arcade.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
var Class = require('../../utils/Class');
|
||||
var Factory = require('./Factory');
|
||||
var World = require('./World');
|
||||
|
||||
var Arcade = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function Arcade (physicsManager, config)
|
||||
{
|
||||
this.config = config;
|
||||
|
||||
physicsManager.world = new World(physicsManager.scene, config);
|
||||
|
||||
physicsManager.add = new Factory(physicsManager.world);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Arcade;
|
660
v3/src/physics/arcade/Body.js
Normal file
660
v3/src/physics/arcade/Body.js
Normal file
|
@ -0,0 +1,660 @@
|
|||
// Phaser.Physics.Arcade.Body
|
||||
|
||||
var CircleContains = require('../../geom/circle/Contains');
|
||||
var Class = require('../../utils/Class');
|
||||
var CONST = require('./const');
|
||||
// var DegToRad = require('../../math/DegToRad');
|
||||
// var RadToDeg = require('../../math/RadToDeg');
|
||||
var Rectangle = require('../../geom/rectangle/Rectangle');
|
||||
var RectangleContains = require('../../geom/rectangle/Contains');
|
||||
var Vector2 = require('../../math/Vector2');
|
||||
|
||||
var Body = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function Body (world, gameObject)
|
||||
{
|
||||
this.world = world;
|
||||
|
||||
this.gameObject = gameObject;
|
||||
|
||||
this.debugShowBody = world.defaults.debugShowBody;
|
||||
this.debugShowVelocity = world.defaults.debugShowVelocity;
|
||||
this.debugBodyColor = world.defaults.bodyDebugColor;
|
||||
|
||||
this.enable = true;
|
||||
|
||||
this.isCircle = false;
|
||||
|
||||
this.radius = 0;
|
||||
|
||||
this.offset = new Vector2();
|
||||
|
||||
this.position = new Vector2(gameObject.x, gameObject.y);
|
||||
|
||||
this.prev = new Vector2(this.position.x, this.position.y);
|
||||
|
||||
this.allowRotation = true;
|
||||
|
||||
this.rotation = gameObject.angle;
|
||||
|
||||
this.preRotation = gameObject.angle;
|
||||
|
||||
this.width = gameObject.width;
|
||||
|
||||
this.height = gameObject.height;
|
||||
|
||||
this.sourceWidth = gameObject.width;
|
||||
|
||||
this.sourceHeight = gameObject.height;
|
||||
|
||||
if (gameObject.frame)
|
||||
{
|
||||
this.sourceWidth = gameObject.frame.realWidth;
|
||||
this.sourceHeight = gameObject.frame.realHeight;
|
||||
}
|
||||
|
||||
this.halfWidth = Math.abs(gameObject.width / 2);
|
||||
|
||||
this.halfHeight = Math.abs(gameObject.height / 2);
|
||||
|
||||
this.center = new Vector2(gameObject.x + this.halfWidth, gameObject.y + this.halfHeight);
|
||||
|
||||
this.velocity = new Vector2();
|
||||
|
||||
this.newVelocity = new Vector2();
|
||||
|
||||
this.deltaMax = new Vector2();
|
||||
|
||||
this.acceleration = new Vector2();
|
||||
|
||||
this.allowDrag = true;
|
||||
|
||||
this.drag = new Vector2();
|
||||
|
||||
this.allowGravity = true;
|
||||
|
||||
this.gravity = new Vector2();
|
||||
|
||||
this.bounce = new Vector2();
|
||||
|
||||
this.worldBounce = null;
|
||||
|
||||
// this.onWorldBounds = null;
|
||||
// this.onCollide = null;
|
||||
// this.onOverlap = null;
|
||||
|
||||
this.maxVelocity = new Vector2(10000, 10000);
|
||||
|
||||
this.friction = new Vector2(1, 0);
|
||||
|
||||
this.angularVelocity = 0;
|
||||
|
||||
this.angularAcceleration = 0;
|
||||
|
||||
this.angularDrag = 0;
|
||||
|
||||
this.maxAngular = 1000;
|
||||
|
||||
this.mass = 1;
|
||||
|
||||
this.angle = 0;
|
||||
|
||||
this.speed = 0;
|
||||
|
||||
this.facing = CONST.FACING_NONE;
|
||||
|
||||
this.immovable = false;
|
||||
|
||||
this.moves = true;
|
||||
|
||||
this.customSeparateX = false;
|
||||
|
||||
this.customSeparateY = false;
|
||||
|
||||
this.overlapX = 0;
|
||||
|
||||
this.overlapY = 0;
|
||||
|
||||
this.overlapR = 0;
|
||||
|
||||
this.embedded = false;
|
||||
|
||||
this.collideWorldBounds = false;
|
||||
|
||||
this.checkCollision = { none: false, up: true, down: true, left: true, right: true };
|
||||
|
||||
this.touching = { none: true, up: false, down: false, left: false, right: false };
|
||||
|
||||
this.wasTouching = { none: true, up: false, down: false, left: false, right: false };
|
||||
|
||||
this.blocked = { none: true, up: false, down: false, left: false, right: false };
|
||||
|
||||
this.tilePadding = new Vector2();
|
||||
|
||||
this.dirty = false;
|
||||
|
||||
this.skipQuadTree = false;
|
||||
|
||||
this.syncBounds = false;
|
||||
|
||||
this.isMoving = false;
|
||||
|
||||
this.stopVelocityOnCollide = true;
|
||||
|
||||
// this.moveTimer = 0;
|
||||
// this.moveDistance = 0;
|
||||
// this.moveDuration = 0;
|
||||
// this.moveTarget = null;
|
||||
// this.moveEnd = null;
|
||||
// this.onMoveComplete = new Phaser.Signal();
|
||||
// this.movementCallback = null;
|
||||
// this.movementCallbackContext = null;
|
||||
|
||||
this._reset = true;
|
||||
|
||||
this._sx = gameObject.scaleX;
|
||||
this._sy = gameObject.scaleY;
|
||||
|
||||
this._dx = 0;
|
||||
this._dy = 0;
|
||||
|
||||
this._bounds = new Rectangle();
|
||||
},
|
||||
|
||||
updateBounds: function ()
|
||||
{
|
||||
var sprite = this.gameObject;
|
||||
|
||||
if (this.syncBounds)
|
||||
{
|
||||
var b = sprite.getBounds(this._bounds);
|
||||
|
||||
// b.ceilAll();
|
||||
|
||||
if (b.width !== this.width || b.height !== this.height)
|
||||
{
|
||||
this.width = b.width;
|
||||
this.height = b.height;
|
||||
this._reset = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var asx = Math.abs(sprite.scaleX);
|
||||
var asy = Math.abs(sprite.scaleY);
|
||||
|
||||
if (asx !== this._sx || asy !== this._sy)
|
||||
{
|
||||
this.width = this.sourceWidth * asx;
|
||||
this.height = this.sourceHeight * asy;
|
||||
this._sx = asx;
|
||||
this._sy = asy;
|
||||
this._reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._reset)
|
||||
{
|
||||
this.halfWidth = Math.floor(this.width / 2);
|
||||
this.halfHeight = Math.floor(this.height / 2);
|
||||
this.updateCenter();
|
||||
}
|
||||
},
|
||||
|
||||
updateCenter: function ()
|
||||
{
|
||||
this.center.set(this.position.x + this.halfWidth, this.position.y + this.halfHeight);
|
||||
},
|
||||
|
||||
update: function (delta)
|
||||
{
|
||||
this.dirty = true;
|
||||
|
||||
// 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.touching.none = true;
|
||||
this.touching.up = false;
|
||||
this.touching.down = false;
|
||||
this.touching.left = false;
|
||||
this.touching.right = false;
|
||||
|
||||
this.blocked.none = true;
|
||||
this.blocked.up = false;
|
||||
this.blocked.down = false;
|
||||
this.blocked.left = false;
|
||||
this.blocked.right = false;
|
||||
|
||||
this.overlapR = 0;
|
||||
this.overlapX = 0;
|
||||
this.overlapY = 0;
|
||||
|
||||
this.embedded = false;
|
||||
|
||||
this.updateBounds();
|
||||
|
||||
var sprite = this.gameObject;
|
||||
|
||||
this.position.x = sprite.x - sprite.displayOriginX + (sprite.scaleX * this.offset.x);
|
||||
this.position.y = sprite.y - sprite.displayOriginY + (sprite.scaleY * this.offset.y);
|
||||
|
||||
// this.position.x -= this.sprite.scale.x < 0 ? this.width : 0;
|
||||
// this.position.y -= this.sprite.scale.y < 0 ? this.height : 0;
|
||||
|
||||
// this.position.x = sprite.x + (sprite.scaleX * this.offset.x);
|
||||
// this.position.y = sprite.y + (sprite.scaleY * this.offset.y);
|
||||
|
||||
this.updateCenter();
|
||||
|
||||
this.rotation = sprite.angle;
|
||||
|
||||
this.preRotation = this.rotation;
|
||||
|
||||
if (this._reset)
|
||||
{
|
||||
this.prev.x = this.position.x;
|
||||
this.prev.y = this.position.y;
|
||||
}
|
||||
|
||||
if (this.moves)
|
||||
{
|
||||
this.world.updateMotion(this);
|
||||
|
||||
this.newVelocity.set(this.velocity.x * delta, this.velocity.y * delta);
|
||||
|
||||
this.position.x += this.newVelocity.x;
|
||||
this.position.y += this.newVelocity.y;
|
||||
|
||||
this.updateCenter();
|
||||
|
||||
if (this.position.x !== this.prev.x || this.position.y !== this.prev.y)
|
||||
{
|
||||
this.angle = Math.atan2(this.velocity.y, this.velocity.x);
|
||||
}
|
||||
|
||||
this.speed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y);
|
||||
|
||||
// Now the State update will throw collision checks at the Body
|
||||
// And finally we'll integrate the new position back to the Sprite in postUpdate
|
||||
|
||||
if (this.collideWorldBounds)
|
||||
{
|
||||
this.checkWorldBounds();
|
||||
|
||||
// if (this.checkWorldBounds() && this.onWorldBounds)
|
||||
// {
|
||||
// this.onWorldBounds.dispatch(this.sprite, this.blocked.up, this.blocked.down, this.blocked.left, this.blocked.right);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
this._dx = this.deltaX();
|
||||
this._dy = this.deltaY();
|
||||
|
||||
this._reset = false;
|
||||
},
|
||||
|
||||
// Feeds the body results back into the parent gameobject (if there is one)
|
||||
postUpdate: function ()
|
||||
{
|
||||
// Only allow postUpdate to be called once per frame
|
||||
if (!this.enable || !this.dirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirty = false;
|
||||
|
||||
if (this.deltaX() < 0)
|
||||
{
|
||||
this.facing = CONST.FACING_LEFT;
|
||||
}
|
||||
else if (this.deltaX() > 0)
|
||||
{
|
||||
this.facing = CONST.FACING_RIGHT;
|
||||
}
|
||||
|
||||
if (this.deltaY() < 0)
|
||||
{
|
||||
this.facing = CONST.FACING_UP;
|
||||
}
|
||||
else if (this.deltaY() > 0)
|
||||
{
|
||||
this.facing = CONST.FACING_DOWN;
|
||||
}
|
||||
|
||||
if (this.moves)
|
||||
{
|
||||
this._dx = this.deltaX();
|
||||
this._dy = this.deltaY();
|
||||
|
||||
if (this.deltaMax.x !== 0 && this._dx !== 0)
|
||||
{
|
||||
if (this._dx < 0 && this._dx < -this.deltaMax.x)
|
||||
{
|
||||
this._dx = -this.deltaMax.x;
|
||||
}
|
||||
else if (this._dx > 0 && this._dx > this.deltaMax.x)
|
||||
{
|
||||
this._dx = this.deltaMax.x;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.deltaMax.y !== 0 && this._dy !== 0)
|
||||
{
|
||||
if (this._dy < 0 && this._dy < -this.deltaMax.y)
|
||||
{
|
||||
this._dy = -this.deltaMax.y;
|
||||
}
|
||||
else if (this._dy > 0 && this._dy > this.deltaMax.y)
|
||||
{
|
||||
this._dy = this.deltaMax.y;
|
||||
}
|
||||
}
|
||||
|
||||
this.gameObject.x += this._dx;
|
||||
this.gameObject.y += this._dy;
|
||||
|
||||
this._reset = true;
|
||||
}
|
||||
|
||||
this.updateCenter();
|
||||
|
||||
if (this.allowRotation)
|
||||
{
|
||||
this.gameObject.angle += this.deltaZ();
|
||||
}
|
||||
|
||||
this.prev.x = this.position.x;
|
||||
this.prev.y = this.position.y;
|
||||
},
|
||||
|
||||
checkWorldBounds: function ()
|
||||
{
|
||||
var pos = this.position;
|
||||
var bounds = this.world.bounds;
|
||||
var check = this.world.checkCollision;
|
||||
|
||||
var bx = (this.worldBounce) ? -this.worldBounce.x : -this.bounce.x;
|
||||
var by = (this.worldBounce) ? -this.worldBounce.y : -this.bounce.y;
|
||||
|
||||
if (pos.x < bounds.x && check.left)
|
||||
{
|
||||
pos.x = bounds.x;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.left = true;
|
||||
this.blocked.none = false;
|
||||
}
|
||||
else if (this.right > bounds.right && check.right)
|
||||
{
|
||||
pos.x = bounds.right - this.width;
|
||||
this.velocity.x *= bx;
|
||||
this.blocked.right = true;
|
||||
this.blocked.none = false;
|
||||
}
|
||||
|
||||
if (pos.y < bounds.y && check.up)
|
||||
{
|
||||
pos.y = bounds.y;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.up = true;
|
||||
this.blocked.none = false;
|
||||
}
|
||||
else if (this.bottom > bounds.bottom && check.down)
|
||||
{
|
||||
pos.y = bounds.bottom - this.height;
|
||||
this.velocity.y *= by;
|
||||
this.blocked.down = true;
|
||||
this.blocked.none = false;
|
||||
}
|
||||
|
||||
return !this.blocked.none;
|
||||
},
|
||||
|
||||
setSize: function (width, height, offsetX, offsetY)
|
||||
{
|
||||
if (offsetX === undefined) { offsetX = this.offset.x; }
|
||||
if (offsetY === undefined) { 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.set(offsetX, offsetY);
|
||||
|
||||
this.updateCenter();
|
||||
|
||||
this.isCircle = false;
|
||||
this.radius = 0;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setCircle: function (radius, offsetX, offsetY)
|
||||
{
|
||||
if (offsetX === undefined) { offsetX = this.offset.x; }
|
||||
if (offsetY === undefined) { offsetY = this.offset.y; }
|
||||
|
||||
if (radius > 0)
|
||||
{
|
||||
this.isCircle = true;
|
||||
this.radius = radius;
|
||||
|
||||
this.sourceWidth = radius * 2;
|
||||
this.sourceHeight = radius * 2;
|
||||
|
||||
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.set(offsetX, offsetY);
|
||||
|
||||
this.updateCenter();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isCircle = false;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
reset: function (x, y)
|
||||
{
|
||||
this.stop();
|
||||
|
||||
var sprite = this.gameObject;
|
||||
|
||||
this.position.x = x + (sprite.scaleX * this.offset.x);
|
||||
this.position.y = y + (sprite.scaleY * this.offset.y);
|
||||
|
||||
// this.position.x = (x - (this.sprite.anchor.x * this.sprite.width)) + this.sprite.scale.x * this.offset.x;
|
||||
// this.position.x -= this.sprite.scale.x < 0 ? this.width : 0;
|
||||
|
||||
// this.position.y = (y - (this.sprite.anchor.y * this.sprite.height)) + this.sprite.scale.y * this.offset.y;
|
||||
// this.position.y -= this.sprite.scale.y < 0 ? this.height : 0;
|
||||
|
||||
this.prev.x = this.position.x;
|
||||
this.prev.y = this.position.y;
|
||||
|
||||
this.rotation = this.gameObject.angle;
|
||||
this.preRotation = this.rotation;
|
||||
|
||||
this.updateBounds();
|
||||
this.updateCenter();
|
||||
},
|
||||
|
||||
stop: function ()
|
||||
{
|
||||
this.velocity.set(0);
|
||||
this.acceleration.set(0);
|
||||
this.speed = 0;
|
||||
this.angularVelocity = 0;
|
||||
this.angularAcceleration = 0;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
getBounds: function (obj)
|
||||
{
|
||||
obj.x = this.x;
|
||||
obj.y = this.y;
|
||||
obj.right = this.right;
|
||||
obj.bottom = this.bottom;
|
||||
|
||||
return obj;
|
||||
},
|
||||
|
||||
hitTest: function (x, y)
|
||||
{
|
||||
return (this.isCircle) ? CircleContains(this, x, y) : RectangleContains(this, x, y);
|
||||
},
|
||||
|
||||
onFloor: function ()
|
||||
{
|
||||
return this.blocked.down;
|
||||
},
|
||||
|
||||
onCeiling: function ()
|
||||
{
|
||||
return this.blocked.up;
|
||||
},
|
||||
|
||||
onWall: function ()
|
||||
{
|
||||
return (this.blocked.left || this.blocked.right);
|
||||
},
|
||||
|
||||
deltaAbsX: function ()
|
||||
{
|
||||
return (this.deltaX() > 0) ? this.deltaX() : -this.deltaX();
|
||||
},
|
||||
|
||||
deltaAbsY: function ()
|
||||
{
|
||||
return (this.deltaY() > 0) ? this.deltaY() : -this.deltaY();
|
||||
},
|
||||
|
||||
deltaX: function ()
|
||||
{
|
||||
return this.position.x - this.prev.x;
|
||||
},
|
||||
|
||||
deltaY: function ()
|
||||
{
|
||||
return this.position.y - this.prev.y;
|
||||
},
|
||||
|
||||
deltaZ: function ()
|
||||
{
|
||||
return this.rotation - this.preRotation;
|
||||
},
|
||||
|
||||
destroy: function ()
|
||||
{
|
||||
this.gameObject.body = null;
|
||||
this.gameObject = null;
|
||||
},
|
||||
|
||||
drawDebug: function (graphic)
|
||||
{
|
||||
var pos = this.position;
|
||||
|
||||
if (this.debugShowBody)
|
||||
{
|
||||
graphic.lineStyle(1, this.debugBodyColor, 1);
|
||||
graphic.strokeRect(pos.x, pos.y, this.width, this.height);
|
||||
}
|
||||
|
||||
if (this.debugShowVelocity)
|
||||
{
|
||||
var x = pos.x + this.halfWidth;
|
||||
var y = pos.y + this.halfHeight;
|
||||
|
||||
graphic.lineStyle(1, this.world.defaults.velocityDebugColor, 1);
|
||||
graphic.lineBetween(x, y, x + this.velocity.x, y + this.velocity.y);
|
||||
}
|
||||
},
|
||||
|
||||
willDrawDebug: function ()
|
||||
{
|
||||
return (this.debugShowBody || this.debugShowVelocity);
|
||||
},
|
||||
|
||||
x: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.x = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
y: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.y = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
left: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.x;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
right: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.x + this.width;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
top: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.y;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
bottom: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.y + this.height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Body;
|
47
v3/src/physics/arcade/Factory.js
Normal file
47
v3/src/physics/arcade/Factory.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
var Body = require('./Body');
|
||||
var Class = require('../../utils/Class');
|
||||
|
||||
// var ImpactBody = require('./ImpactBody');
|
||||
// var ImpactImage = require('./ImpactImage');
|
||||
// var ImpactSprite = require('./ImpactSprite');
|
||||
|
||||
var Factory = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function Factory (world)
|
||||
{
|
||||
this.world = world;
|
||||
|
||||
this.sys = world.scene.sys;
|
||||
},
|
||||
|
||||
body: function (gameObject)
|
||||
{
|
||||
return new Body(this.world, gameObject);
|
||||
}
|
||||
|
||||
/*
|
||||
image: function (x, y, key, frame)
|
||||
{
|
||||
var image = new ImpactImage(this.world, x, y, key, frame);
|
||||
|
||||
this.sys.displayList.add(image);
|
||||
|
||||
return image;
|
||||
},
|
||||
|
||||
sprite: function (x, y, key, frame)
|
||||
{
|
||||
var sprite = new ImpactSprite(this.world, x, y, key, frame);
|
||||
|
||||
this.sys.displayList.add(sprite);
|
||||
this.sys.updateList.add(sprite);
|
||||
|
||||
return sprite;
|
||||
}
|
||||
*/
|
||||
|
||||
});
|
||||
|
||||
module.exports = Factory;
|
|
@ -1,41 +1,90 @@
|
|||
// Phaser.Physics.Arcade.World
|
||||
|
||||
var Body = require('./Body');
|
||||
var Class = require('../../utils/Class');
|
||||
var Rectangle = require('../../geom/rectangle/Rectangle');
|
||||
var Vector2 = require('../../math/Vector2');
|
||||
var DistanceBetween = require('../../math/distance/DistanceBetween');
|
||||
var Clamp = require('../../math/Clamp');
|
||||
var CONST = require('./const');
|
||||
var GetValue = require('../../utils/object/GetValue');
|
||||
var Set = require('../../structs/Set');
|
||||
|
||||
var World = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function World (width, height)
|
||||
function World (scene, config)
|
||||
{
|
||||
this.gravity = new Vector2();
|
||||
this.scene = scene;
|
||||
|
||||
this.bounds = new Rectangle(0, 0, width, height);
|
||||
this.events = scene.sys.events;
|
||||
|
||||
this.checkCollision = { up: true, down: true, left: true, right: true };
|
||||
this.bodies = new Set();
|
||||
|
||||
this.maxObjects = 10;
|
||||
this.gravity = new Vector2(GetValue(config, 'gravity.x', 0), GetValue(config, 'gravity.y', 0));
|
||||
|
||||
this.maxLevels = 4;
|
||||
this.bounds = new Rectangle(
|
||||
GetValue(config, 'x', 0),
|
||||
GetValue(config, 'y', 0),
|
||||
GetValue(config, 'width', scene.sys.game.config.width),
|
||||
GetValue(config, 'height', scene.sys.game.config.height)
|
||||
);
|
||||
|
||||
this.OVERLAP_BIAS = 4;
|
||||
this.checkCollision = {
|
||||
up: GetValue(config, 'checkCollision.up', true),
|
||||
down: GetValue(config, 'checkCollision.down', true),
|
||||
left: GetValue(config, 'checkCollision.left', true),
|
||||
right: GetValue(config, 'checkCollision.right', true)
|
||||
};
|
||||
|
||||
this.forceX = false;
|
||||
this.maxObjects = GetValue(config, 'maxObjects', 10);
|
||||
|
||||
this.maxLevels = GetValue(config, 'maxLevels',40);
|
||||
|
||||
this.OVERLAP_BIAS = GetValue(config, 'overlapBias', 4);
|
||||
|
||||
this.forceX = GetValue(config, 'forceX', false);
|
||||
|
||||
this.sortDirection = CONST.LEFT_RIGHT;
|
||||
|
||||
this.skipQuadTree = true;
|
||||
this.skipQuadTree = GetValue(config, 'skipQuadTree', true);
|
||||
|
||||
this.isPaused = false;
|
||||
this.isPaused = GetValue(config, 'isPaused', false);
|
||||
|
||||
// this.quadTree = new Phaser.QuadTree(this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels);
|
||||
|
||||
this._total = 0;
|
||||
|
||||
this.drawDebug = GetValue(config, 'debug', false);
|
||||
this.debugGraphic;
|
||||
|
||||
// this.setBoundsToWorld();
|
||||
|
||||
this.defaults = {
|
||||
debugShowBody: GetValue(config, 'debugShowBody', true),
|
||||
debugShowVelocity: GetValue(config, 'debugShowVelocity', true),
|
||||
bodyDebugColor: GetValue(config, 'debugBodyColor', 0xff00ff),
|
||||
velocityDebugColor: GetValue(config, 'debugVelocityColor', 0x00ff00)
|
||||
};
|
||||
|
||||
if (this.drawDebug)
|
||||
{
|
||||
this.createDebugGraphic();
|
||||
}
|
||||
},
|
||||
|
||||
createDebugGraphic: function ()
|
||||
{
|
||||
var graphic = this.scene.sys.add.graphics({ x: 0, y: 0 });
|
||||
|
||||
graphic.setZ(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
this.debugGraphic = graphic;
|
||||
|
||||
this.drawDebug = true;
|
||||
|
||||
return graphic;
|
||||
},
|
||||
|
||||
setBounds: function (x, y, width, height)
|
||||
|
@ -45,6 +94,85 @@ var World = new Class({
|
|||
return this;
|
||||
},
|
||||
|
||||
pause: function ()
|
||||
{
|
||||
this.isPaused = true;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
resume: function ()
|
||||
{
|
||||
this.isPaused = false;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
update: function (time, delta)
|
||||
{
|
||||
if (this.isPaused || this.bodies.size === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// this.delta = Math.min(delta / 1000, this.maxStep) * this.timeScale;
|
||||
delta /= 1000;
|
||||
|
||||
this.delta = delta;
|
||||
|
||||
// Update all active bodies
|
||||
|
||||
var i;
|
||||
var body;
|
||||
var bodies = this.bodies.entries;
|
||||
var len = bodies.length;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
body = bodies[i];
|
||||
|
||||
if (body.enable)
|
||||
{
|
||||
body.update(delta);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
postUpdate: function ()
|
||||
{
|
||||
var i;
|
||||
var body;
|
||||
var bodies = this.bodies.entries;
|
||||
var len = bodies.length;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
body = bodies[i];
|
||||
|
||||
if (body.enable)
|
||||
{
|
||||
body.postUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawDebug)
|
||||
{
|
||||
var graphics = this.debugGraphic;
|
||||
|
||||
graphics.clear();
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
body = bodies[i];
|
||||
|
||||
if (body.willDrawDebug())
|
||||
{
|
||||
body.drawDebug(graphics);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateMotion: function (body)
|
||||
{
|
||||
if (body.allowRotation)
|
||||
|
@ -52,7 +180,7 @@ var World = new Class({
|
|||
var velocityDelta = this.computeVelocity(0, body, body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular) - body.angularVelocity;
|
||||
|
||||
body.angularVelocity += velocityDelta;
|
||||
body.rotation += (body.angularVelocity * this.game.time.physicsElapsed);
|
||||
body.rotation += (body.angularVelocity * this.delta);
|
||||
}
|
||||
|
||||
body.velocity.x = this.computeVelocity(1, body, body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x);
|
||||
|
@ -65,20 +193,20 @@ var World = new Class({
|
|||
|
||||
if (axis === 1 && body.allowGravity)
|
||||
{
|
||||
velocity += (this.gravity.x + body.gravity.x) * this.game.time.physicsElapsed;
|
||||
velocity += (this.gravity.x + body.gravity.x) * this.delta;
|
||||
}
|
||||
else if (axis === 2 && body.allowGravity)
|
||||
{
|
||||
velocity += (this.gravity.y + body.gravity.y) * this.game.time.physicsElapsed;
|
||||
velocity += (this.gravity.y + body.gravity.y) * this.delta;
|
||||
}
|
||||
|
||||
if (acceleration)
|
||||
{
|
||||
velocity += acceleration * this.game.time.physicsElapsed;
|
||||
velocity += acceleration * this.delta;
|
||||
}
|
||||
else if (drag && body.allowDrag)
|
||||
{
|
||||
drag *= this.game.time.physicsElapsed;
|
||||
drag *= this.delta;
|
||||
|
||||
if (velocity - drag > 0)
|
||||
{
|
||||
|
@ -209,9 +337,11 @@ var World = new Class({
|
|||
|
||||
collideObjects: function (object1, object2, collideCallback, processCallback, callbackContext, overlapOnly)
|
||||
{
|
||||
var i;
|
||||
|
||||
if (!Array.isArray(object1) && Array.isArray(object2))
|
||||
{
|
||||
for (var i = 0; i < object2.length; i++)
|
||||
for (i = 0; i < object2.length; i++)
|
||||
{
|
||||
if (!object2[i]) { continue; }
|
||||
|
||||
|
@ -220,7 +350,7 @@ var World = new Class({
|
|||
}
|
||||
else if (Array.isArray(object1) && !Array.isArray(object2))
|
||||
{
|
||||
for (var i = 0; i < object1.length; i++)
|
||||
for (i = 0; i < object1.length; i++)
|
||||
{
|
||||
if (!object1[i]) { continue; }
|
||||
|
||||
|
@ -229,7 +359,7 @@ var World = new Class({
|
|||
}
|
||||
else if (Array.isArray(object1) && Array.isArray(object2))
|
||||
{
|
||||
for (var i = 0; i < object1.length; i++)
|
||||
for (i = 0; i < object1.length; i++)
|
||||
{
|
||||
if (!object1[i]) { continue; }
|
||||
|
||||
|
@ -247,6 +377,660 @@ var World = new Class({
|
|||
}
|
||||
},
|
||||
|
||||
collideHandler: function (object1, object2, collideCallback, processCallback, callbackContext, overlapOnly)
|
||||
{
|
||||
// Only collide valid objects
|
||||
// if (object2 === undefined && object1.physicsType === Phaser.GROUP)
|
||||
// {
|
||||
// this.sort(object1);
|
||||
// this.collideGroupVsSelf(object1, collideCallback, processCallback, callbackContext, overlapOnly);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// If neither of the objects are set or exist then bail out
|
||||
if (!object1 || !object2 || !object1.enable || !object2.enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.collideSpriteVsSprite(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
|
||||
},
|
||||
|
||||
collideSpriteVsSprite: function (sprite1, sprite2, collideCallback, processCallback, callbackContext, overlapOnly)
|
||||
{
|
||||
if (!sprite1.body || !sprite2.body)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.separate(sprite1.body, sprite2.body, processCallback, callbackContext, overlapOnly))
|
||||
{
|
||||
if (collideCallback)
|
||||
{
|
||||
collideCallback.call(callbackContext, sprite1, sprite2);
|
||||
}
|
||||
|
||||
this._total++;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
separate: function (body1, body2, processCallback, callbackContext, overlapOnly)
|
||||
{
|
||||
if (
|
||||
!body1.enable ||
|
||||
!body2.enable ||
|
||||
body1.checkCollision.none ||
|
||||
body2.checkCollision.none ||
|
||||
!this.intersects(body1, body2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// They overlap. Is there a custom process callback? If it returns true then we can carry on, otherwise we should abort.
|
||||
if (processCallback && processCallback.call(callbackContext, body1.gameObject, body2.gameObject) === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Circle vs. Circle quick bail out
|
||||
if (body1.isCircle && body2.isCircle)
|
||||
{
|
||||
return this.separateCircle(body1, body2, overlapOnly);
|
||||
}
|
||||
|
||||
// We define the behavior of bodies in a collision circle and rectangle
|
||||
// If a collision occurs in the corner points of the rectangle, the body behave like circles
|
||||
|
||||
// Either body1 or body2 is a circle
|
||||
if (body1.isCircle !== body2.isCircle)
|
||||
{
|
||||
var bodyRect = (body1.isCircle) ? body2 : body1;
|
||||
var bodyCircle = (body1.isCircle) ? body1 : body2;
|
||||
|
||||
var rect = {
|
||||
x: bodyRect.x,
|
||||
y: bodyRect.y,
|
||||
right: bodyRect.right,
|
||||
bottom: bodyRect.bottom
|
||||
};
|
||||
|
||||
var circle = bodyCircle.center;
|
||||
|
||||
if (circle.y < rect.y || circle.y > rect.bottom)
|
||||
{
|
||||
if (circle.x < rect.x || circle.x > rect.right)
|
||||
{
|
||||
return this.separateCircle(body1, body2, overlapOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var resultX = false;
|
||||
var resultY = false;
|
||||
|
||||
// Do we separate on x or y first?
|
||||
if (this.forceX || Math.abs(this.gravity.y + body1.gravity.y) < Math.abs(this.gravity.x + body1.gravity.x))
|
||||
{
|
||||
resultX = this.separateX(body1, body2, overlapOnly);
|
||||
|
||||
// Are they still intersecting? Let's do the other axis then
|
||||
if (this.intersects(body1, body2))
|
||||
{
|
||||
resultY = this.separateY(body1, body2, overlapOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultY = this.separateY(body1, body2, overlapOnly);
|
||||
|
||||
// Are they still intersecting? Let's do the other axis then
|
||||
if (this.intersects(body1, body2))
|
||||
{
|
||||
resultX = this.separateX(body1, body2, overlapOnly);
|
||||
}
|
||||
}
|
||||
|
||||
var result = (resultX || resultY);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (overlapOnly)
|
||||
{
|
||||
if (body1.onOverlap)
|
||||
{
|
||||
body1.onOverlap.dispatch(body1.sprite, body2.sprite);
|
||||
}
|
||||
|
||||
if (body2.onOverlap)
|
||||
{
|
||||
body2.onOverlap.dispatch(body2.sprite, body1.sprite);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (body1.onCollide)
|
||||
{
|
||||
body1.onCollide.dispatch(body1.sprite, body2.sprite);
|
||||
}
|
||||
|
||||
if (body2.onCollide)
|
||||
{
|
||||
body2.onCollide.dispatch(body2.sprite, body1.sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
intersects: function (body1, body2)
|
||||
{
|
||||
if (body1 === body2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.isCircle)
|
||||
{
|
||||
if (body2.isCircle)
|
||||
{
|
||||
// Circle vs. Circle
|
||||
return DistanceBetween(body1.center.x, body1.center.y, body2.center.x, body2.center.y) <= (body1.halfWidth + body2.halfWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Circle vs. Rect
|
||||
return this.circleBodyIntersects(body1, body2);
|
||||
}
|
||||
}
|
||||
else if (body2.isCircle)
|
||||
{
|
||||
// Rect vs. Circle
|
||||
return this.circleBodyIntersects(body2, body1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rect vs. Rect
|
||||
if (body1.right <= body2.position.x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.bottom <= body2.position.y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.position.x >= body2.right)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (body1.position.y >= body2.bottom)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
circleBodyIntersects: function (circle, body)
|
||||
{
|
||||
var x = Clamp(circle.center.x, body.left, body.right);
|
||||
var y = Clamp(circle.center.y, body.top, body.bottom);
|
||||
|
||||
var dx = (circle.center.x - x) * (circle.center.x - x);
|
||||
var dy = (circle.center.y - y) * (circle.center.y - y);
|
||||
|
||||
return (dx + dy) <= (circle.halfWidth * circle.halfWidth);
|
||||
},
|
||||
|
||||
separateCircle: function (body1, body2, overlapOnly)
|
||||
{
|
||||
// Set the bounding box overlap values
|
||||
this.getOverlapX(body1, body2);
|
||||
this.getOverlapY(body1, body2);
|
||||
|
||||
var dx = body2.center.x - body1.center.x;
|
||||
var dy = body2.center.y - body1.center.y;
|
||||
|
||||
var angleCollision = Math.atan2(dy, dx);
|
||||
|
||||
var overlap = 0;
|
||||
|
||||
if (body1.isCircle !== body2.isCircle)
|
||||
{
|
||||
var rect = {
|
||||
x: (body2.isCircle) ? body1.position.x : body2.position.x,
|
||||
y: (body2.isCircle) ? body1.position.y : body2.position.y,
|
||||
right: (body2.isCircle) ? body1.right : body2.right,
|
||||
bottom: (body2.isCircle) ? body1.bottom : body2.bottom
|
||||
};
|
||||
|
||||
var circle = {
|
||||
x: (body1.isCircle) ? body1.center.x : body2.center.x,
|
||||
y: (body1.isCircle) ? body1.center.y : body2.center.y,
|
||||
radius: (body1.isCircle) ? body1.halfWidth : body2.halfWidth
|
||||
};
|
||||
|
||||
if (circle.y < rect.y)
|
||||
{
|
||||
if (circle.x < rect.x)
|
||||
{
|
||||
overlap = DistanceBetween(circle.x, circle.y, rect.x, rect.y) - circle.radius;
|
||||
}
|
||||
else if (circle.x > rect.right)
|
||||
{
|
||||
overlap = DistanceBetween(circle.x, circle.y, rect.right, rect.y) - circle.radius;
|
||||
}
|
||||
}
|
||||
else if (circle.y > rect.bottom)
|
||||
{
|
||||
if (circle.x < rect.x)
|
||||
{
|
||||
overlap = DistanceBetween(circle.x, circle.y, rect.x, rect.bottom) - circle.radius;
|
||||
}
|
||||
else if (circle.x > rect.right)
|
||||
{
|
||||
overlap = DistanceBetween(circle.x, circle.y, rect.right, rect.bottom) - circle.radius;
|
||||
}
|
||||
}
|
||||
|
||||
overlap *= -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlap = (body1.halfWidth + body2.halfWidth) - DistanceBetween(body1.center.x, body1.center.y, body2.center.x, body2.center.y);
|
||||
}
|
||||
|
||||
// Can't separate two immovable bodies, or a body with its own custom separation logic
|
||||
if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateX || body2.customSeparateX)
|
||||
{
|
||||
if (overlap !== 0)
|
||||
{
|
||||
if (body1.onOverlap)
|
||||
{
|
||||
body1.onOverlap.dispatch(body1.sprite, body2.sprite);
|
||||
}
|
||||
|
||||
if (body2.onOverlap)
|
||||
{
|
||||
body2.onOverlap.dispatch(body2.sprite, body1.sprite);
|
||||
}
|
||||
}
|
||||
|
||||
// return true if there was some overlap, otherwise false
|
||||
return (overlap !== 0);
|
||||
}
|
||||
|
||||
// Transform the velocity vector to the coordinate system oriented along the direction of impact.
|
||||
// This is done to eliminate the vertical component of the velocity
|
||||
var v1 = {
|
||||
x: body1.velocity.x * Math.cos(angleCollision) + body1.velocity.y * Math.sin(angleCollision),
|
||||
y: body1.velocity.x * Math.sin(angleCollision) - body1.velocity.y * Math.cos(angleCollision)
|
||||
};
|
||||
|
||||
var v2 = {
|
||||
x: body2.velocity.x * Math.cos(angleCollision) + body2.velocity.y * Math.sin(angleCollision),
|
||||
y: body2.velocity.x * Math.sin(angleCollision) - body2.velocity.y * Math.cos(angleCollision)
|
||||
};
|
||||
|
||||
// We expect the new velocity after impact
|
||||
var tempVel1 = ((body1.mass - body2.mass) * v1.x + 2 * body2.mass * v2.x) / (body1.mass + body2.mass);
|
||||
var tempVel2 = (2 * body1.mass * v1.x + (body2.mass - body1.mass) * v2.x) / (body1.mass + body2.mass);
|
||||
|
||||
// We convert the vector to the original coordinate system and multiplied by factor of rebound
|
||||
if (!body1.immovable)
|
||||
{
|
||||
body1.velocity.x = (tempVel1 * Math.cos(angleCollision) - v1.y * Math.sin(angleCollision)) * body1.bounce.x;
|
||||
body1.velocity.y = (v1.y * Math.cos(angleCollision) + tempVel1 * Math.sin(angleCollision)) * body1.bounce.y;
|
||||
}
|
||||
|
||||
if (!body2.immovable)
|
||||
{
|
||||
body2.velocity.x = (tempVel2 * Math.cos(angleCollision) - v2.y * Math.sin(angleCollision)) * body2.bounce.x;
|
||||
body2.velocity.y = (v2.y * Math.cos(angleCollision) + tempVel2 * Math.sin(angleCollision)) * body2.bounce.y;
|
||||
}
|
||||
|
||||
// When the collision angle is almost perpendicular to the total initial velocity vector
|
||||
// (collision on a tangent) vector direction can be determined incorrectly.
|
||||
// This code fixes the problem
|
||||
|
||||
if (Math.abs(angleCollision) < Math.PI / 2)
|
||||
{
|
||||
if ((body1.velocity.x > 0) && !body1.immovable && (body2.velocity.x > body1.velocity.x))
|
||||
{
|
||||
body1.velocity.x *= -1;
|
||||
}
|
||||
else if ((body2.velocity.x < 0) && !body2.immovable && (body1.velocity.x < body2.velocity.x))
|
||||
{
|
||||
body2.velocity.x *= -1;
|
||||
}
|
||||
else if ((body1.velocity.y > 0) && !body1.immovable && (body2.velocity.y > body1.velocity.y))
|
||||
{
|
||||
body1.velocity.y *= -1;
|
||||
}
|
||||
else if ((body2.velocity.y < 0) && !body2.immovable && (body1.velocity.y < body2.velocity.y))
|
||||
{
|
||||
body2.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
else if (Math.abs(angleCollision) > Math.PI / 2)
|
||||
{
|
||||
if ((body1.velocity.x < 0) && !body1.immovable && (body2.velocity.x < body1.velocity.x))
|
||||
{
|
||||
body1.velocity.x *= -1;
|
||||
}
|
||||
else if ((body2.velocity.x > 0) && !body2.immovable && (body1.velocity.x > body2.velocity.x))
|
||||
{
|
||||
body2.velocity.x *= -1;
|
||||
}
|
||||
else if ((body1.velocity.y < 0) && !body1.immovable && (body2.velocity.y < body1.velocity.y))
|
||||
{
|
||||
body1.velocity.y *= -1;
|
||||
}
|
||||
else if ((body2.velocity.y > 0) && !body2.immovable && (body1.velocity.x > body2.velocity.y))
|
||||
{
|
||||
body2.velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!body1.immovable)
|
||||
{
|
||||
body1.x += (body1.velocity.x * this.game.time.physicsElapsed) - overlap * Math.cos(angleCollision);
|
||||
body1.y += (body1.velocity.y * this.game.time.physicsElapsed) - overlap * Math.sin(angleCollision);
|
||||
}
|
||||
|
||||
if (!body2.immovable)
|
||||
{
|
||||
body2.x += (body2.velocity.x * this.game.time.physicsElapsed) + overlap * Math.cos(angleCollision);
|
||||
body2.y += (body2.velocity.y * this.game.time.physicsElapsed) + overlap * Math.sin(angleCollision);
|
||||
}
|
||||
|
||||
if (body1.onCollide)
|
||||
{
|
||||
body1.onCollide.dispatch(body1.sprite, body2.sprite);
|
||||
}
|
||||
|
||||
if (body2.onCollide)
|
||||
{
|
||||
body2.onCollide.dispatch(body2.sprite, body1.sprite);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
getOverlapX: function (body1, body2, overlapOnly)
|
||||
{
|
||||
var overlap = 0;
|
||||
var 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
|
||||
overlap = body1.right - body2.x;
|
||||
|
||||
if ((overlap > maxOverlap && !overlapOnly) || body1.checkCollision.right === false || body2.checkCollision.left === false)
|
||||
{
|
||||
overlap = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
body1.touching.none = false;
|
||||
body1.touching.right = true;
|
||||
body2.touching.none = false;
|
||||
body2.touching.left = true;
|
||||
}
|
||||
}
|
||||
else if (body1.deltaX() < body2.deltaX())
|
||||
{
|
||||
// Body1 is moving left and/or Body2 is moving right
|
||||
overlap = body1.x - body2.width - body2.x;
|
||||
|
||||
if ((-overlap > maxOverlap && !overlapOnly) || body1.checkCollision.left === false || body2.checkCollision.right === false)
|
||||
{
|
||||
overlap = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
body1.touching.none = false;
|
||||
body1.touching.left = true;
|
||||
body2.touching.none = false;
|
||||
body2.touching.right = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Resets the overlapX to zero if there is no overlap, or to the actual pixel value if there is
|
||||
body1.overlapX = overlap;
|
||||
body2.overlapX = overlap;
|
||||
|
||||
return overlap;
|
||||
},
|
||||
|
||||
getOverlapY: function (body1, body2, overlapOnly)
|
||||
{
|
||||
var overlap = 0;
|
||||
var 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
|
||||
overlap = body1.bottom - body2.y;
|
||||
|
||||
if ((overlap > maxOverlap && !overlapOnly) || body1.checkCollision.down === false || body2.checkCollision.up === false)
|
||||
{
|
||||
overlap = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
body1.touching.none = false;
|
||||
body1.touching.down = true;
|
||||
body2.touching.none = false;
|
||||
body2.touching.up = true;
|
||||
}
|
||||
}
|
||||
else if (body1.deltaY() < body2.deltaY())
|
||||
{
|
||||
// Body1 is moving up and/or Body2 is moving down
|
||||
overlap = body1.y - body2.bottom;
|
||||
|
||||
if ((-overlap > maxOverlap && !overlapOnly) || body1.checkCollision.up === false || body2.checkCollision.down === false)
|
||||
{
|
||||
overlap = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
body1.touching.none = false;
|
||||
body1.touching.up = true;
|
||||
body2.touching.none = false;
|
||||
body2.touching.down = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Resets the overlapY to zero if there is no overlap, or to the actual pixel value if there is
|
||||
body1.overlapY = overlap;
|
||||
body2.overlapY = overlap;
|
||||
|
||||
return overlap;
|
||||
},
|
||||
|
||||
separateX: function (body1, body2, overlapOnly)
|
||||
{
|
||||
var overlap = this.getOverlapX(body1, body2, overlapOnly);
|
||||
|
||||
// Can't separate two immovable bodies, or a body with its own custom separation logic
|
||||
if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateX || body2.customSeparateX)
|
||||
{
|
||||
// return true if there was some overlap, otherwise false
|
||||
return (overlap !== 0) || (body1.embedded && body2.embedded);
|
||||
}
|
||||
|
||||
// Adjust their positions and velocities accordingly (if there was any overlap)
|
||||
var v1 = body1.velocity.x;
|
||||
var v2 = body2.velocity.x;
|
||||
|
||||
if (!body1.immovable && !body2.immovable)
|
||||
{
|
||||
overlap *= 0.5;
|
||||
|
||||
body1.x -= overlap;
|
||||
body2.x += overlap;
|
||||
|
||||
var nv1 = Math.sqrt((v2 * v2 * body2.mass) / body1.mass) * ((v2 > 0) ? 1 : -1);
|
||||
var nv2 = Math.sqrt((v1 * v1 * body1.mass) / body2.mass) * ((v1 > 0) ? 1 : -1);
|
||||
var avg = (nv1 + nv2) * 0.5;
|
||||
|
||||
nv1 -= avg;
|
||||
nv2 -= avg;
|
||||
|
||||
body1.velocity.x = avg + nv1 * body1.bounce.x;
|
||||
body2.velocity.x = avg + nv2 * body2.bounce.x;
|
||||
}
|
||||
else if (!body1.immovable)
|
||||
{
|
||||
body1.x -= overlap;
|
||||
body1.velocity.x = v2 - v1 * body1.bounce.x;
|
||||
|
||||
// This is special case code that handles things like vertically moving platforms you can ride
|
||||
if (body2.moves)
|
||||
{
|
||||
body1.y += (body2.y - body2.prev.y) * body2.friction.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
body2.x += overlap;
|
||||
body2.velocity.x = v1 - v2 * body2.bounce.x;
|
||||
|
||||
// This is special case code that handles things like vertically moving platforms you can ride
|
||||
if (body1.moves)
|
||||
{
|
||||
body2.y += (body1.y - body1.prev.y) * body1.friction.y;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far then there WAS overlap, and separation is complete, so return true
|
||||
return true;
|
||||
},
|
||||
|
||||
separateY: function (body1, body2, overlapOnly)
|
||||
{
|
||||
var overlap = this.getOverlapY(body1, body2, overlapOnly);
|
||||
|
||||
// Can't separate two immovable bodies, or a body with its own custom separation logic
|
||||
if (overlapOnly || overlap === 0 || (body1.immovable && body2.immovable) || body1.customSeparateY || body2.customSeparateY)
|
||||
{
|
||||
// return true if there was some overlap, otherwise false
|
||||
return (overlap !== 0) || (body1.embedded && body2.embedded);
|
||||
}
|
||||
|
||||
// Adjust their positions and velocities accordingly (if there was any overlap)
|
||||
var v1 = body1.velocity.y;
|
||||
var v2 = body2.velocity.y;
|
||||
|
||||
if (!body1.immovable && !body2.immovable)
|
||||
{
|
||||
overlap *= 0.5;
|
||||
|
||||
body1.y -= overlap;
|
||||
body2.y += overlap;
|
||||
|
||||
var nv1 = Math.sqrt((v2 * v2 * body2.mass) / body1.mass) * ((v2 > 0) ? 1 : -1);
|
||||
var nv2 = Math.sqrt((v1 * v1 * body1.mass) / body2.mass) * ((v1 > 0) ? 1 : -1);
|
||||
var avg = (nv1 + nv2) * 0.5;
|
||||
|
||||
nv1 -= avg;
|
||||
nv2 -= avg;
|
||||
|
||||
body1.velocity.y = avg + nv1 * body1.bounce.y;
|
||||
body2.velocity.y = avg + nv2 * body2.bounce.y;
|
||||
}
|
||||
else if (!body1.immovable)
|
||||
{
|
||||
body1.y -= overlap;
|
||||
body1.velocity.y = v2 - v1 * 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.prev.x) * body2.friction.x;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
body2.y += overlap;
|
||||
body2.velocity.y = v1 - v2 * 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.prev.x) * body1.friction.x;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far then there WAS overlap, and separation is complete, so return true
|
||||
return true;
|
||||
},
|
||||
|
||||
enable: function (object)
|
||||
{
|
||||
var i = 1;
|
||||
|
||||
if (Array.isArray(object))
|
||||
{
|
||||
i = object.length;
|
||||
|
||||
while (i--)
|
||||
{
|
||||
if (object[i].hasOwnProperty('children'))
|
||||
{
|
||||
// If it's a Group then we do it on the children regardless
|
||||
this.enable(object[i].children.entries);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.enableBody(object[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (object.hasOwnProperty('children'))
|
||||
{
|
||||
// If it's a Group then we do it on the children regardless
|
||||
this.enable(object.children.entries);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.enableBody(object);
|
||||
}
|
||||
},
|
||||
|
||||
enableBody: function (object)
|
||||
{
|
||||
if (object.body === null)
|
||||
{
|
||||
object.body = new Body(this, object);
|
||||
|
||||
this.bodies.set(object.body);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = World;
|
||||
|
|
|
@ -38,6 +38,12 @@ module.exports = {
|
|||
* @constant
|
||||
* @type {number}
|
||||
*/
|
||||
BOTTOM_TOP: 4
|
||||
BOTTOM_TOP: 4,
|
||||
|
||||
FACING_NONE: 5,
|
||||
FACING_UP: 6,
|
||||
FACING_DOWN: 7,
|
||||
FACING_LEFT: 8,
|
||||
FACING_RIGHT: 9
|
||||
|
||||
};
|
||||
|
|
17
v3/src/physics/arcade/index.js
Normal file
17
v3/src/physics/arcade/index.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Phaser.Physics.Arcade
|
||||
|
||||
// World updated to run off the Phaser main loop.
|
||||
// Body extended to support additional setter functions.
|
||||
|
||||
module.exports = {
|
||||
|
||||
Body: require('./Body'),
|
||||
|
||||
// COLLIDES: require('./COLLIDES'),
|
||||
// CollisionMap: require('./CollisionMap'),
|
||||
// TYPE: require('./TYPE'),
|
||||
|
||||
World: require('./World'),
|
||||
Factory: require('./Factory')
|
||||
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
// Phaser.Physics
|
||||
|
||||
module.exports = {
|
||||
Arcade: require('./arcade'),
|
||||
Impact: require('./impact'),
|
||||
PolyDecomp: require('./poly-decomp/')
|
||||
};
|
||||
|
|
|
@ -3,7 +3,8 @@ var GetValue = require('../../utils/object/GetValue');
|
|||
var Merge = require('../../utils/object/Merge');
|
||||
var NOOP = require('../../utils/NOOP');
|
||||
|
||||
// Physics Systems
|
||||
// Physics Systems (TODO: Remove from here)
|
||||
var Arcade = require('../../physics/arcade/Arcade');
|
||||
var Impact = require('../../physics/impact/Impact');
|
||||
|
||||
var PhysicsManager = new Class({
|
||||
|
@ -46,6 +47,10 @@ var PhysicsManager = new Class({
|
|||
|
||||
switch (system)
|
||||
{
|
||||
case 'arcade':
|
||||
this.system = new Arcade(this, config);
|
||||
break;
|
||||
|
||||
case 'impact':
|
||||
this.system = new Impact(this, config);
|
||||
break;
|
||||
|
@ -55,6 +60,11 @@ var PhysicsManager = new Class({
|
|||
update: function (time, delta)
|
||||
{
|
||||
this.world.update(time, delta);
|
||||
},
|
||||
|
||||
postUpdate: function ()
|
||||
{
|
||||
this.world.postUpdate();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue