New split physics system is implemented. Still tidying-up, but ArcadePhysics, P2 and Ninja Physics are in and configured. Lots more examples required, and tilemap collision mostly broken in Arcade at the moment. Time to implement in Ninja.

This commit is contained in:
photonstorm
2014-03-06 06:29:19 +00:00
parent 2bab4fd2fb
commit 3e93f24583
63 changed files with 3177 additions and 1680 deletions
+20 -8
View File
@@ -180,14 +180,26 @@ module.exports = function (grunt) {
'src/utils/Debug.js',
'src/utils/Color.js',
'src/physics/World.js',
'src/physics/PointProxy.js',
'src/physics/InversePointProxy.js',
'src/physics/Body.js',
'src/physics/Spring.js',
'src/physics/Material.js',
'src/physics/ContactMaterial.js',
'src/physics/CollisionGroup.js',
'/src/physics/Physics.js',
'/src/physics/arcade/World.js',
'/src/physics/arcade/Body.js',
'/src/physics/arcade/QuadTree.js',
'/src/physics/ninja/World.js',
'/src/physics/ninja/Body.js',
'/src/physics/ninja/AABB.js',
'/src/physics/ninja/Tile.js',
'/src/physics/ninja/Circle.js',
'/src/physics/p2/World.js',
'/src/physics/p2/PointProxy.js',
'/src/physics/p2/InversePointProxy.js',
'/src/physics/p2/Body.js',
'/src/physics/p2/Spring.js',
'/src/physics/p2/Material.js',
'/src/physics/p2/ContactMaterial.js',
'/src/physics/p2/CollisionGroup.js',
'src/particles/Particles.js',
'src/particles/arcade/ArcadeParticles.js',
+1
View File
@@ -14,6 +14,7 @@ By Richard Davey, [Photon Storm](http://www.photonstorm.com)
* Join the [Forum](http://www.html5gamedevs.com/forum/14-phaser/)
* Try out 220+ [Phaser Examples](http://examples.phaser.io)
* Read the [documentation online](http://docs.phaser.io)
* Join our [#phaserio IRC channel](http://www.html5gamedevs.com/topic/4470-official-phaserio-irc-channel-phaserio-on-freenode/) on freenode
[Subscribe to our new Phaser Newsletter](https://confirmsubscription.com/h/r/369DE48E3E86AF1E). We'll email you when new versions are released as well as send you our regular Phaser game making magazine.
+6
View File
@@ -141,6 +141,12 @@
<script src="$path/src/physics/arcade/Body.js"></script>
<script src="$path/src/physics/arcade/QuadTree.js"></script>
<script src="$path/src/physics/ninja/World.js"></script>
<script src="$path/src/physics/ninja/Body.js"></script>
<script src="$path/src/physics/ninja/AABB.js"></script>
<script src="$path/src/physics/ninja/Tile.js"></script>
<script src="$path/src/physics/ninja/Circle.js"></script>
<script src="$path/src/physics/p2/World.js"></script>
<script src="$path/src/physics/p2/PointProxy.js"></script>
<script src="$path/src/physics/p2/InversePointProxy.js"></script>
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

+122
View File
@@ -0,0 +1,122 @@
// var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render });
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
function preload() {
game.load.spritesheet('ninja-tiles', 'assets/physics/ninja-tiles.png', 128, 128, 34);
game.load.image('a', 'assets/sprites/firstaid.png');
}
var sprite1;
var cursors;
var tile1;
var tile2;
var t;
var running = false;
function create() {
game.stage.smoothed = true;
// Activate the Ninja physics system
game.physics.startSystem(Phaser.Physics.NINJA);
// game.physics.ninja.gravity = 0.1;
sprite1 = game.add.sprite(500, 200, 'a');
// Enable the physics body for the Ninja physics system
// By default it will create an AABB body for the sprite
game.physics.ninja.enableAABB(sprite1);
// But you can change it to either a Tile or a Circle
tile1 = game.add.sprite(0, 550, 'ninja-tiles', 14);
tile1.width = 100;
tile1.height = 100;
game.physics.ninja.enableTile(tile1, 14);
// sprite1.body.aabb.friction = 0;
// tile1 = new Phaser.Physics.Ninja.Tile(game.physics.ninja, 100, 500, 100, 100, Phaser.Physics.Ninja.Tile.SLOPE_45DEGpn);
// tile1 = new Phaser.Physics.Ninja.Tile(game.physics.ninja, 100, 500, 100, 100, 15);
// tile2 = new Phaser.Physics.Ninja.Tile(game.physics.ninja, 300, 500, 100, 100, 7);
cursors = game.input.keyboard.createCursorKeys();
}
function collisionHandler() {
game.stage.backgroundColor = 0xff0000;
}
function update() {
game.physics.ninja.collide(sprite1, tile1, collisionHandler, null, this);
tile1.body.moveRight(1);
/*
if (cursors.up.isDown && !running)
{
running = true;
t = Date.now();
}
sprite1.body.setZeroVelocity();
if (running)
{
sprite1.body.moveRight(100);
if (sprite1.body.x >= 200)
{
var ms = Date.now() - t;
console.log('100px in ', ms);
running = false;
sprite1.body.setZeroVelocity();
}
}
*/
// sprite1.body.setZeroVelocity();
if (cursors.left.isDown)
{
sprite1.body.moveLeft(20);
}
else if (cursors.right.isDown)
{
sprite1.body.moveRight(20);
}
if (cursors.up.isDown)
{
sprite1.body.moveUp(20);
}
else if (cursors.down.isDown)
{
sprite1.body.moveUp(20);
}
}
function render() {
game.debug.text(sprite1.body.shape.velocity.x, 32, 32);
game.debug.text(sprite1.body.shape.velocity.y, 32, 64);
game.debug.text(game.math.radToDeg(sprite1.body.angle), 32, 96);
// tile1.render(game.context, 'ninja-tiles');
// tile2.render(game.context, 'ninja-tiles');
// game.debug.geom(sprite1.body, 'rgba(0,255,0,0.4)', true, 1);
// game.debug.geom(tile1, 'rgba(0,255,0,0.4)', true, 1);
// game.debug.geom(tile1, 'rgba(0,255,0,0.4)', true, 1);
}
+11 -2
View File
@@ -19,6 +19,7 @@ function create() {
sprite1 = game.add.sprite(50, 200, 'atari');
sprite1.name = 'atari';
// sprite1.anchor.set(0.5);
sprite2 = game.add.sprite(700, 220, 'mushroom');
sprite2.name = 'mushroom';
@@ -37,6 +38,9 @@ function update() {
// object1, object2, collideCallback, processCallback, callbackContext
game.physics.arcade.collide(sprite1, sprite2, collisionHandler, null, this);
// var b = sprite1.getBounds();
// console.log(b);
}
function collisionHandler (obj1, obj2) {
@@ -46,9 +50,14 @@ function collisionHandler (obj1, obj2) {
}
function render() {
// game.debug.physicsBody(sprite1.body);
// game.debug.physicsBody(sprite2.body);
// var b = sprite1.getBounds();
// game.debug.geom(b, 'rgba(255,0,0,0.8)', true, 1);
game.debug.geom(sprite1.body, 'rgba(0,255,0,0.4)', true, 1);
game.debug.geom(sprite2.body, 'rgba(0,255,0,0.4)', true, 1);
}
+3 -1
View File
@@ -52,7 +52,7 @@ function create() {
game.physics.enable(sprite);
sprite.body.setSize(14, 14, 2, 0);
// sprite.body.setSize(14, 14, 2, 0);
console.log(sprite.body);
@@ -107,6 +107,8 @@ function render() {
// game.debug.text(game.physics.arcade._intersection.width, 32, 32);
// game.debug.text(game.physics.arcade._intersection.height, 32, 64);
game.debug.geom(sprite.body, 'rgba(0,255,0,0.4)', true, 1);
game.debug.text(sprite.body.overlapX, 32, 32);
game.debug.text(sprite.body.overlapY, 32, 64);
+77
View File
@@ -0,0 +1,77 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
function preload() {
game.load.tilemap('map', 'assets/tilemaps/maps/collision_test.json', null, Phaser.Tilemap.TILED_JSON);
game.load.image('ground_1x1', 'assets/tilemaps/tiles/ground_1x1.png');
game.load.image('phaser', 'assets/sprites/phaser-dude.png');
// game.load.image('phaser', 'assets/sprites/phaser-ship.png');
}
var map;
var layer;
var cursors;
var sprite;
function create() {
map = game.add.tilemap('map');
map.addTilesetImage('ground_1x1');
layer = map.createLayer('Tile Layer 1');
layer.resizeWorld();
map.setCollisionBetween(1, 12);
layer.debug = true;
sprite = game.add.sprite(260, 70, 'phaser');
game.physics.enable(sprite);
game.camera.follow(sprite);
// game.physics.arcade.gravity.y = 500;
// sprite.body.velocity.x = 100;
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
game.physics.arcade.collide(sprite, layer);
sprite.body.velocity.x = 0;
sprite.body.velocity.y = 0;
if (cursors.up.isDown)
{
sprite.body.velocity.y = -100;
}
else if (cursors.down.isDown)
{
sprite.body.velocity.y = 100;
}
if (cursors.left.isDown)
{
sprite.body.velocity.x = -100;
}
else if (cursors.right.isDown)
{
sprite.body.velocity.x = 100;
}
}
function render() {
game.debug.text(sprite.body.velocity.x, 32, 32);
game.debug.text(sprite.body.velocity.y, 64, 32);
}
+3
View File
@@ -21,6 +21,7 @@ function create() {
// sprite = game.add.tileSprite(100, 100, 400, 300, 'starfield');
sprite = game.add.tileSprite(100, 100, 400, 300, 'mummy');
sprite.pivot.setTo(200, 200);
sprite.animations.add('walk');
@@ -32,6 +33,8 @@ function create() {
function update() {
sprite.rotation += 0.01;
if (cursors.left.isDown)
{
sprite.tilePosition.x += 8;
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+11 -43
View File
@@ -99,7 +99,15 @@ Phaser.Sprite = function (game, x, y, key, frame) {
this.input = null;
/**
* @property {Phaser.Physics.Arcade.Body|Phaser.Physics.P2.Body|null} body - The Sprites physics Body. Will be null unless physics has been enabled via `Sprite.physicsEnabled = true`.
* By default Sprites won't add themselves to any physics system and their physics body will be `null`.
* To enable them for physics you need to call `game.physics.enable(sprite, system)` where `sprite` is this object
* and `system` is the Physics system you want to use to manage this body. Once enabled you can access all physics related properties via `Sprite.body`.
*
* Important: Enabling a Sprite for P2 or Ninja physics will automatically set `Sprite.anchor` to 0.5 so the physics body is centered on the Sprite.
* If you need a different result then adjust or re-create the Body shape offsets manually, and/or reset the anchor after enabling physics.
*
* @property {Phaser.Physics.Arcade.Body|Phaser.Physics.P2.Body|Phaser.Physics.Ninja.Body|null} body
* @default
*/
this.body = null;
@@ -850,46 +858,6 @@ Object.defineProperty(Phaser.Sprite.prototype, "inputEnabled", {
});
/**
* By default Sprites won't add themselves to the physics simulation. By setting physicsEnabled to true a Rectangle physics body is
* attached to this Sprite matching its placement and dimensions, and will then start to process physics world updates.
* You can access all physics related properties via Sprite.body.
*
* Important: Enabling a Sprite for physics will automatically set `Sprite.anchor` to 0.5 so the physics body is centered on the Sprite.
* If you need a different result then adjust or re-create the Body shape offsets manually, and/or reset the anchor after enabling physics.
*
* @name Phaser.Sprite#physicsEnabled
* @property {boolean} physicsEnabled - Set to true to add this Sprite to the physics world. Set to false to destroy the body and remove it from the physics world.
Object.defineProperty(Phaser.Sprite.prototype, "physicsEnabled", {
get: function () {
return (this.body !== null);
},
set: function (value) {
if (value)
{
if (this.body === null)
{
this.body = new Phaser.Physics.Body(this.game, this, this.x, this.y, 1);
this.anchor.set(0.5);
}
}
else
{
if (this.body)
{
this.body.destroy();
}
}
}
});
*/
/**
* Sprite.exists controls if the core game loop and physics update this Sprite or not.
* When you set Sprite.exists to false it will remove its Body from the physics world (if it has one) and also set Sprite.visible to false.
@@ -913,7 +881,7 @@ Object.defineProperty(Phaser.Sprite.prototype, "exists", {
// exists = true
this._cache[6] = 1;
if (this.body)
if (this.body && this.body.type === Phaser.Physics.P2)
{
this.body.addToWorld();
}
@@ -925,7 +893,7 @@ Object.defineProperty(Phaser.Sprite.prototype, "exists", {
// exists = false
this._cache[6] = 0;
if (this.body)
if (this.body && this.body.type === Phaser.Physics.P2)
{
this.body.removeFromWorld();
}
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @author Antony Woods <antony@teamwoods.org>
* @copyright 2013 Photon Storm Ltd.
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
+91 -11
View File
@@ -5,12 +5,15 @@
*/
/**
* The Physics manager.
* The Physics Manager is responsible for looking after all of the running physics systems.
* Phaser supports 3 physics systems: Arcade Physics, P2 and Ninja Physics (with Box2D and Chipmunk in development)
* Game Objects can belong to only 1 physics system, but you can have multiple systems active in a single game.
*
* For example you could have P2 managing a polygon-built terrain landscape that an vehicle drives over, while it could be firing bullets that use the
* faster (due to being much simpler) Arcade Physics system.
*
* @class Phaser.Physics
*
* @classdesc todo
*
* @constructor
* @param {Phaser.Game} game - A reference to the currently running game.
* @param {object} [physicsConfig=null] - A physics configuration object to pass to the Physics world on creation.
@@ -22,14 +25,34 @@ Phaser.Physics = function (game, config) {
*/
this.game = game;
/**
* @property {object} config - The physics configuration object as passed to the game on creation.
*/
this.config = config;
/**
* @property {Phaser.Physics.Arcade} arcade - The Arcade Physics system.
*/
this.arcade = new Phaser.Physics.Arcade(game);
/**
* @property {Phaser.Physics.P2} p2 - The P2.JS Physics system.
*/
this.p2 = null;
/**
* @property {Phaser.Physics.Ninja} ninja - The N+ Ninja Physics System.
*/
this.ninja = null;
/**
* @property {Phaser.Physics.Box2D} box2d - The Box2D Physics system (to be done).
*/
this.box2d = null;
/**
* @property {Phaser.Physics.Chipmunk} chipmunk - The Chipmunk Physics system (to be done).
*/
this.chipmunk = null;
};
@@ -50,38 +73,72 @@ Phaser.Physics.P2 = 1;
* @const
* @type {number}
*/
Phaser.Physics.BOX2D = 2;
Phaser.Physics.NINJA = 2;
/**
* @const
* @type {number}
*/
Phaser.Physics.CHIPMUNK = 3;
Phaser.Physics.BOX2D = 3;
/**
* @const
* @type {number}
*/
Phaser.Physics.CHIPMUNK = 5;
Phaser.Physics.prototype = {
/**
* This will create an instance of the requested physics simulation.
* Phaser.Physics.Arcade is running by default, but all others need activating directly.
* You can start the following physics systems:
* Phaser.Physics.P2 - A full-body advanced physics system by Stefan Hedman.
* Phaser.Physics.NINJA - A port of the metanet N+ physics system.
* Phaser.Physics.BOX2D and Phaser.Physics.CHIPMUNK are still in development.
*
* @method Phaser.Physics#startSystem
* @param {number} The physics system to start.
*/
startSystem: function (system) {
if (system === Phaser.Physics.ARCADE)
if (system === Phaser.Physics.ARCADE && this.arcade === null)
{
this.arcade = new Phaser.Physics.Arcade(this.game);
}
else if (system === Phaser.Physics.P2)
else if (system === Phaser.Physics.P2 && this.p2 === null)
{
this.p2 = new Phaser.Physics.P2(this.game, this.config);
}
else if (system === Phaser.Physics.BOX2D)
if (system === Phaser.Physics.NINJA && this.ninja === null)
{
this.ninja = new Phaser.Physics.Ninja(this.game);
}
else if (system === Phaser.Physics.BOX2D && this.box2d === null)
{
// Coming soon
}
else if (system === Phaser.Physics.CHIPMUNK)
else if (system === Phaser.Physics.CHIPMUNK && this.chipmunk === null)
{
// Coming soon
}
},
// Enables a sprites physics body
/**
* This will create a physics body on the given game object.
* A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
* It can be for any of the physics systems that have been started:
*
* Phaser.Physics.Arcade - A light weight AABB based collision system with basic separation.
* Phaser.Physics.P2 - A full-body advanced physics system supporting multiple object shapes, polygon loading, contact materials, springs and constraints.
* Phaser.Physics.NINJA - A port of the metanet N+ physics system. Advanced AABB and Circle vs. Tile collision.
* Phaser.Physics.BOX2D and Phaser.Physics.CHIPMUNK are still in development.
*
* @method Phaser.Physics#enable
* @param {object|array} object - The game object to create the physics body on. Can also be an array of objects, a body will be created on every object in the array.
* @param {number} [system=0] - The physics system that will be used to create the body. Defaults to Arcade Physics.
*/
enable: function (object, system) {
if (typeof system === 'undefined') { system = Phaser.Physics.ARCADE; }
@@ -111,14 +168,25 @@ Phaser.Physics.prototype = {
object[i].body = new Phaser.Physics.P2.Body(this.game, object[i], object[i].x, object[i].y, 1);
object[i].anchor.set(0.5);
}
else if (system === Phaser.Physics.NINJA)
{
object[i].body = new Phaser.Physics.Ninja.Body(this.ninja, object[i]);
object[i].anchor.set(0.5);
}
}
}
},
/**
* Updates all running physics systems.
*
* @method Phaser.Physics#update
* @protected
*/
update: function () {
// ArcadePhysics doesn't have a core to update
// ArcadePhysics / Ninja don't have a core to update
if (this.p2)
{
@@ -127,10 +195,22 @@ Phaser.Physics.prototype = {
},
/**
* Updates the physics bounds to match the world dimensions.
*
* @method Phaser.Physics#setBoundsToWorld
* @protected
*/
setBoundsToWorld: function () {
},
/**
* Clears down all active physics systems. This doesn't destroy them, it just clears them of objects and is called when the State changes.
*
* @method Phaser.Physics#clear
* @protected
*/
clear: function () {
if (this.p2)
+189 -110
View File
@@ -1,6 +1,6 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013 Photon Storm Ltd.
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
@@ -25,34 +25,27 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/
this.game = sprite.game;
/**
* @property {number} type - The type of physics system this body belongs to.
*/
this.type = Phaser.Physics.ARCADE;
/**
* @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
*/
this.offset = new Phaser.Point();
this.offset = new Phaser.Point(-(sprite.anchor.x * sprite.width), -(sprite.anchor.y * sprite.height));
/**
* @property {number} x - The x position of the physics body.
* @property {Phaser.Point} position - The position of the physics body.
* @readonly
*/
this.x = sprite.x;
this.position = new Phaser.Point(sprite.x + this.offset.x, sprite.y + this.offset.y);
/**
* @property {number} y - The y position of the physics body.
* @property {Phaser.Point} prev - The previous position of the physics body.
* @readonly
*/
this.y = sprite.y;
/**
* @property {number} preX - The previous x position of the physics body.
* @readonly
*/
this.preX = sprite.x;
/**
* @property {number} preY - The previous y position of the physics body.
* @readonly
*/
this.preY = sprite.y;
this.prev = new Phaser.Point(this.position.x, this.position.y);
/**
* @property {number} preRotation - The previous rotation of the physics body.
@@ -60,18 +53,6 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/
this.preRotation = sprite.angle;
/**
* @property {number} screenX - The x position of the physics body translated to screen space.
* @readonly
*/
this.screenX = sprite.x;
/**
* @property {number} screenY - The y position of the physics body translated to screen space.
* @readonly
*/
this.screenY = sprite.y;
/**
* @property {number} sourceWidth - The un-scaled original size.
* @readonly
@@ -97,17 +78,17 @@ Phaser.Physics.Arcade.Body = function (sprite) {
/**
* @property {number} halfWidth - The calculated width / 2 of the physics body.
*/
this.halfWidth = Math.floor(sprite.width / 2);
this.halfWidth = Math.abs(sprite.width / 2);
/**
* @property {number} halfHeight - The calculated height / 2 of the physics body.
*/
this.halfHeight = Math.floor(sprite.height / 2);
this.halfHeight = Math.abs(sprite.height / 2);
/**
* @property {Phaser.Point} center - The center coordinate of the Physics Body.
*/
this.center = new Phaser.Point(this.x + this.halfWidth, this.y + this.halfHeight);
this.center = new Phaser.Point(sprite.x + this.halfWidth, sprite.y + this.halfHeight);
/**
* @property {number} _sx - Internal cache var.
@@ -126,6 +107,12 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/
this.velocity = new Phaser.Point();
/**
* @property {Phaser.Point} newVelocity - New velocity.
* @readonly
*/
this.newVelocity = new Phaser.Point(0, 0);
/**
* @property {Phaser.Point} acceleration - The velocity in pixels per second sq. of the Body.
*/
@@ -137,9 +124,9 @@ Phaser.Physics.Arcade.Body = function (sprite) {
this.drag = new Phaser.Point();
/**
* @property {Phaser.Point} gravity - A private Gravity setting for the Body.
* @property {Phaser.Point} gravityScale - Gravity scaling factor. If you want the body to ignore gravity, set this to zero. If you want to reverse gravity, set it to -1.
*/
this.gravity = new Phaser.Point();
this.gravityScale = new Phaser.Point(1, 1);
/**
* @property {Phaser.Point} bounce - The elasticitiy of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity.
@@ -218,12 +205,6 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/
this.allowRotation = true;
/**
* @property {boolean} allowGravity - Allow this Body to be influenced by the global Gravity?
* @default
*/
this.allowGravity = true;
/**
* This flag allows you to disable the custom x separation that takes place by Physics.Arcade.separate.
* Used in combination with your own collision processHandler you can create whatever type of collision response you need.
@@ -252,18 +233,6 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/
this.overlapY = 0;
this.hull = new Phaser.Rectangle();
/**
* @property {Phaser.Rectangle} hullX - The dynamically calculated hull used during collision.
*/
this.hullX = new Phaser.Rectangle();
/**
* @property {Phaser.Rectangle} hullY - The dynamically calculated hull used during collision.
*/
this.hullY = new Phaser.Rectangle();
/**
* If a body is overlapping with another body, but neither of them are moving (maybe they spawned on-top of each other?) this is set to true.
* @property {boolean} embedded - Body embed value.
@@ -303,10 +272,29 @@ Phaser.Physics.Arcade.Body = function (sprite) {
*/
this.blocked = { x: 0, y: 0, up: false, down: false, left: false, right: false };
/**
* This object is populated with boolean values when the Body collides with the World bounds or a Tile.
* For example if blocked.up is true then the Body cannot move up.
* @property {object} blocked - An object containing on which faces this Body is blocked from moving, if any.
*/
this.result = { x: 0, y: 0, px: 0, py: 0, tx: 0, ty: 0, slope: false };
};
Phaser.Physics.Arcade.Body.prototype = {
resetResult: function () {
this.result.x = false;
this.result.y = false;
this.result.slope = false;
this.result.px = this.position.x;
this.result.py = this.position.y;
this.result.tx = 0;
this.result.ty = 0;
},
/**
* Internal method.
*
@@ -336,6 +324,8 @@ Phaser.Physics.Arcade.Body.prototype = {
*/
preUpdate: function () {
this.resetResult();
// Store and reset collision flags
this.wasTouching.none = this.touching.none;
this.wasTouching.up = this.touching.up;
@@ -354,27 +344,41 @@ Phaser.Physics.Arcade.Body.prototype = {
// this.screenX = (this.sprite.worldTransform[2] - (this.sprite.anchor.x * this.width)) + this.offset.x;
// this.screenY = (this.sprite.worldTransform[5] - (this.sprite.anchor.y * this.height)) + this.offset.y;
this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;
this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;
// this is where the Sprite currently is, in world coordinates
// this.preX = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;
// this.preY = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;
// this.preRotation = this.sprite.angle;
this.preRotation = this.sprite.angle;
this.x = this.preX;
this.y = this.preY;
this.rotation = this.preRotation;
// this.x = this.preX;
// this.y = this.preY;
// this.rotation = this.preRotation;
// this.overlapX = 0;
// this.overlapY = 0;
this.blocked.up = false;
this.blocked.down = false;
this.blocked.left = false;
this.blocked.right = false;
this.prev.set(this.position.x, this.position.y);
// this.position.x = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;
// this.position.y = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;
// this.blocked.up = false;
// this.blocked.down = false;
// this.blocked.left = false;
// this.blocked.right = false;
if (this.moves)
{
this.game.physics.arcade.updateMotion(this);
this.newVelocity.set(this.velocity.x * this.game.time.physicsElapsed, this.velocity.y * this.game.time.physicsElapsed);
this.position.x += this.newVelocity.x;
this.position.y += this.newVelocity.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();
@@ -391,6 +395,56 @@ Phaser.Physics.Arcade.Body.prototype = {
*/
postUpdate: function () {
// if (this.result.x)
// {
// this.position.x = this.result.px;
// this.velocity.x = 0;
// }
// else
// {
// this.position.x += this.newVelocity.x;
// }
// this.position.y += this.newVelocity.y;
// this.position.add(this.newVelocity.x, this.newVelocity.y);
this.sprite.x = (this.position.x - this.offset.x);
this.sprite.y = (this.position.y - this.offset.y);
/* if (this.deltaX() < 0)
{
this.facing = Phaser.LEFT;
this.sprite.x += this.deltaX();
}
else if (this.deltaX() > 0)
{
this.facing = Phaser.RIGHT;
this.sprite.x += this.deltaX();
}
if (this.deltaY() < 0)
{
this.facing = Phaser.UP;
this.sprite.y += this.deltaY();
}
else if (this.deltaY() > 0)
{
this.facing = Phaser.DOWN;
this.sprite.y += this.deltaY();
}
*/
// this.sprite.x += this.overlapX;
// this.sprite.y += this.overlapY;
// this is where the Sprite currently is, in world coordinates
// this.sprite.x = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;
// this.sprite.y = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;
/*
if (this.deltaX() < 0 && this.blocked.left === false)
{
this.facing = Phaser.LEFT;
@@ -412,6 +466,7 @@ Phaser.Physics.Arcade.Body.prototype = {
this.facing = Phaser.DOWN;
this.sprite.y += this.deltaY();
}
*/
this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
@@ -533,7 +588,7 @@ Phaser.Physics.Arcade.Body.prototype = {
* @return {number} The delta value. Positive if the motion was to the right, negative if to the left.
*/
deltaX: function () {
return this.x - this.preX;
return this.position.x - this.prev.x;
},
/**
@@ -543,9 +598,15 @@ Phaser.Physics.Arcade.Body.prototype = {
* @return {number} The delta value. Positive if the motion was downwards, negative if upwards.
*/
deltaY: function () {
return this.y - this.preY;
return this.position.y - this.prev.y;
},
/**
* Returns the delta z value. The difference between Body.rotation now and in the previous step.
*
* @method Phaser.Physics.Arcade.Body#deltaZ
* @return {number} The delta value. Positive if the motion was clockwise, negative if anti-clockwise.
*/
deltaZ: function () {
return this.rotation - this.preRotation;
}
@@ -555,35 +616,18 @@ Phaser.Physics.Arcade.Body.prototype = {
/**
* @name Phaser.Physics.Arcade.Body#bottom
* @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height)
* @readonly
*/
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "bottom", {
/**
* The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property.
* The sum of the y and height properties.
* @method bottom
* @return {number}
* @readonly
*/
get: function () {
// return Math.floor(this.y + this.height);
return this.y + this.height;
},
/**
* The sum of the y and height properties. Changing the bottom property of a Rectangle object has no effect on the x, y and width properties, but does change the height property.
* @method bottom
* @param {number} value
*/
set: function (value) {
if (value <= this.y)
{
this.height = 0;
}
else
{
this.height = (this.y - value);
}
return this.position.y + this.height;
}
});
@@ -591,37 +635,72 @@ Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "bottom", {
/**
* @name Phaser.Physics.Arcade.Body#right
* @property {number} right - The right value of this Body (same as Body.x + Body.width)
* @readonly
*/
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "right", {
/**
* The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties.
* However it does affect the width property.
* The sum of the x and width properties.
* @method right
* @return {number}
* @readonly
*/
get: function () {
// return Math.floor(this.x + this.width);
return this.x + this.width;
},
/**
* The sum of the x and width properties. Changing the right property of a Rectangle object has no effect on the x, y and height properties.
* However it does affect the width property.
* @method right
* @param {number} value
*/
set: function (value) {
if (value <= this.x)
{
this.width = 0;
}
else
{
this.width = this.x + value;
}
return this.position.x + this.width;
}
});
/**
* @name Phaser.Physics.Arcade.Body#x
* @property {number} x - The x position.
*/
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "x", {
/**
* The x position.
* @method x
* @return {number}
*/
get: function () {
return this.position.x;
},
/**
* The x position.
* @method x
* @param {number} value
*/
set: function (value) {
this.position.x = value;
}
});
/**
* @name Phaser.Physics.Arcade.Body#y
* @property {number} y - The y position.
*/
Object.defineProperty(Phaser.Physics.Arcade.Body.prototype, "y", {
/**
* The y position.
* @method y
* @return {number}
*/
get: function () {
return this.position.y;
},
/**
* The y position.
* @method y
* @param {number} value
*/
set: function (value) {
this.position.y = value;
}
});
Phaser.Physics.Arcade.Body.prototype.constructor = Phaser.Physics.Arcade.Body;
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013 Photon Storm Ltd.
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
File diff suppressed because it is too large Load Diff
+143 -362
View File
@@ -1,6 +1,6 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013 Photon Storm Ltd.
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
@@ -161,6 +161,8 @@ Phaser.Physics.Arcade = function (game) {
};
Phaser.Physics.Arcade.prototype.constructor = Phaser.Physics.Arcade;
Phaser.Physics.Arcade.prototype = {
/**
@@ -172,56 +174,41 @@ Phaser.Physics.Arcade.prototype = {
updateMotion: function (body) {
// Rotation
this._velocityDelta = (this.computeVelocity(body, body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular, 0) - body.angularVelocity) * 0.5;
this._velocityDelta = (this.computeVelocity(body.angularVelocity, body.angularAcceleration, body.angularDrag, body.maxAngular, 0) - body.angularVelocity) * 0.5;
body.angularVelocity += this._velocityDelta;
body.rotation += (body.angularVelocity * this.game.time.physicsElapsed);
body.angularVelocity += this._velocityDelta;
if (body.allowGravity)
{
// Gravity was previously applied without taking physicsElapsed into account
// so it needs to be multiplied by 60 (fps) for compatibility with existing games
this._gravityX = (this.gravity.x + body.gravity.x) * 60;
this._gravityY = (this.gravity.y + body.gravity.y) * 60;
}
else
{
this._gravityX = this._gravityY = 0;
}
// Apply gravity using the p2 style gravityScale
body.velocity.x += this.gravity.x * this.game.time.physicsElapsed * body.gravityScale.x;
body.velocity.y += this.gravity.y * this.game.time.physicsElapsed * body.gravityScale.y;
// Horizontal
this._velocityDelta = (this.computeVelocity(body, body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x, this._gravityX) - body.velocity.x) * 0.5;
body.velocity.x += this._velocityDelta;
body.x += (body.velocity.x * this.game.time.physicsElapsed);
body.velocity.x += this._velocityDelta;
// Vertical
this._velocityDelta = (this.computeVelocity(body, body.velocity.y, body.acceleration.y, body.drag.y, body.maxVelocity.y, this._gravityY) - body.velocity.y) * 0.5;
body.velocity.y += this._velocityDelta;
body.y += (body.velocity.y * this.game.time.physicsElapsed);
body.velocity.y += this._velocityDelta;
// Apply velocity
body.velocity.x = this.computeVelocity(body.velocity.x, body.acceleration.x, body.drag.x, body.maxVelocity.x);
body.velocity.y = this.computeVelocity(body.velocity.y, body.acceleration.y, body.drag.y, body.maxVelocity.y);
},
/**
* A tween-like function that takes a starting velocity and some other factors and returns an altered velocity.
* Based on a function in Flixel by @ADAMATOMIC
*
* @method Phaser.Physics.Arcade#computeVelocity
* @param {Phaser.Physics.Arcade.Body} body - The Body object to be updated.
* @param {number} velocity - Any component of velocity (e.g. 20).
* @param {number} acceleration - Rate at which the velocity is changing.
* @param {number} drag - Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set.
* @param {number} [max=10000] - An absolute value cap for the velocity.
* @param {number} gravity - The acceleration due to gravity. Gravity will not induce drag.
* @return {number} The altered Velocity value.
*/
computeVelocity: function (body, velocity, acceleration, drag, max, gravity) {
computeVelocity: function (velocity, acceleration, drag, max) {
max = max || 10000;
velocity += (acceleration + gravity) * this.game.time.physicsElapsed;
if (acceleration === 0 && drag !== 0)
if (acceleration)
{
velocity + acceleration * this.game.time.physicsElapsed;
}
else if (drag)
{
this._drag = drag * this.game.time.physicsElapsed;
@@ -537,17 +524,30 @@ Phaser.Physics.Arcade.prototype = {
collideSpriteVsTilemapLayer: function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext) {
// this._mapData = tilemapLayer.getTiles(sprite.body.left, sprite.body.top, sprite.body.width, sprite.body.height, true);
this._mapData = tilemapLayer.getTiles(sprite.body.x, sprite.body.y, sprite.body.width, sprite.body.height, true);
// this._mapData = tilemapLayer.getTiles(sprite.body.x, sprite.body.y, sprite.body.width, sprite.body.height, true);
this._mapData = tilemapLayer.getIntersectingTiles(sprite.body.position.x, sprite.body.position.y, sprite.body.width, sprite.body.height, true);
// var vx = sprite.body.x;
// var vy = sprite.body.y;
// vx += sprite.body.newVelocity.x;
// vy += sprite.body.newVelocity.y;
// this._mapData = tilemapLayer.getIntersectingTiles(vx, vy, sprite.body.width, sprite.body.height, true);
if (this._mapData.length === 0)
{
return;
}
if (this._mapData.length > 1)
{
// if (this._mapData.length > 1)
// {
// Needs process callback added
this.separateTiles(sprite.body, this._mapData);
}
// }
/*
else
{
var i = 0;
@@ -578,6 +578,7 @@ Phaser.Physics.Arcade.prototype = {
}
}
}
*/
},
@@ -870,62 +871,15 @@ Phaser.Physics.Arcade.prototype = {
},
/**
* Performs a rect intersection test against the two objects.
* Objects must expose properties: width, height, left, right, top, bottom.
* @method Phaser.Physics.Arcade#tileIntersects
* @param {object} body - The Body to test.
* @param {object} tile - The Tile to test.
* @returns {boolean} Returns true if the objects intersect, otherwise false.
*/
tileIntersects: function (body, tile) {
this._intersection[0] = 0;
this._intersection[1] = 0;
this._intersection[2] = 0;
this._intersection[3] = 0;
this._intersection[4] = 0;
if (body.width <= 0 || body.height <= 0 || tile.width <= 0 || tile.height <= 0)
{
this._intersection[4] = 0;
return this._intersection;
}
if (!(body.right < tile.x || body.bottom < tile.y || body.x > tile.right || body.y > tile.bottom))
{
this._intersection[0] = Math.max(body.x, tile.x); // x
this._intersection[1] = Math.max(body.y, tile.y); // y
this._intersection[2] = Math.min(body.right, tile.right) - this._intersection[0]; // width
this._intersection[3] = Math.min(body.bottom, tile.bottom) - this._intersection[1]; // height
this._intersection[4] = 1;
return this._intersection;
}
this._intersection[4] = 0;
return this._intersection;
},
/**
* The core separation function to separate a physics body and an array of tiles.
* @method Phaser.Physics.Arcade#separateTiles
* @param {Phaser.Physics.Arcade.Body} body - The Body object to separate.
* @param {array<Phaser.Tile>} tiles - The array of tiles to collide against.
* @returns {boolean} Returns true if the body was separated, otherwise false.
*/
separateTiles: function (body, tiles) {
var tile;
body.resetResult();
var result = false;
for (var i = 0; i < tiles.length; i++)
{
tile = tiles[i];
if (this.separateTile(body, tile))
if (this.separateTile(i, body, tiles[i]))
{
result = true;
}
@@ -935,6 +889,86 @@ Phaser.Physics.Arcade.prototype = {
},
separateTile: function (i, body, tile) {
// we re-check for collision in case body was separated in a previous step
if (i > 0 && !tile.intersects(body.position.x, body.position.y, body.right, body.bottom))
{
// no collision so bail out (separted in a previous step)
console.log('no collision so bail out (separted in a previous step');
return false;
}
// console.log('body intersecting tile');
// console.log('x', body.position.x, 'y', body.position.y, 'r', body.right, 'b', body.bottom, 'wh', body.width, body.height);
// console.log('x', tile.x, 'y', tile.y, 'r', tile.right, 'b', tile.bottom);
if (body.newVelocity.x && (tile.faceLeft || tile.faceRight))
{
var px = 0;
var tx = 0;
if (body.newVelocity.x > 0 && tile.faceLeft)
{
px = body.width;
}
else if (body.newVelocity.x < 0 && tile.faceRight)
{
tx = tile.width;
}
body.position.x = tile.worldX - px + tx;
body.velocity.x = 0; // rebound check
// body.newVelocity.x = 0; // rebound check
}
// Vertical only if still colliding
// if (tile.intersects(body.position.x, body.position.y, body.right, body.bottom))
// if (body.newVelocity.y && tile.intersects(body.position.x, body.position.y, body.right, body.bottom))
if (body.newVelocity.y && (tile.faceTop || tile.faceBottom))
{
var py = 0;
var ty = 0;
if (body.newVelocity.y > 0 && tile.faceBottom)
{
py = body.height;
}
else if (body.newVelocity.y < 0 && tile.faceTop)
{
ty = tile.height;
}
// console.log('cy', body.newVelocity.y, py, ty);
body.position.y = tile.worldY - py + ty;
body.velocity.y = 0; // rebound check
// body.newVelocity.y = 0; // rebound check
}
// var pxOffsetX = (body.newVelocity.x > 0 ? body.width : 0);
// var tileOffsetX = (body.newVelocity.x < 0 ? tile.width : 0);
// var pxOffsetY = (body.newVelocity.y > 0 ? body.height : 0);
// var tileOffsetY = (body.newVelocity.y < 0 ? tile.height : 0);
// Assume fully solid for now
// body.result.x = true;
// body.result.tile = tile;
// body.result.px = tile.x - pxOffsetX + tileOffsetX;
// body.position.x = tile.x - pxOffsetX + tileOffsetX;
// res.pos.y = tileY * this.tilesize - pxOffsetY + tileOffsetY;
// console.log('nv', body.newVelocity.x, 'tile.xy', tile.x, tile.y, 'p', pxOffsetX, 't', tileOffsetX, 'body xy', body.position.x, body.position.y);
},
/**
* The core separation function to separate a physics body and a tile.
* @method Phaser.Physics.Arcade#separateTile
@@ -942,7 +976,7 @@ Phaser.Physics.Arcade.prototype = {
* @param {Phaser.Tile} tile - The tile to collide against.
* @returns {boolean} Returns true if the body was separated, otherwise false.
*/
separateTile: function (body, tile) {
XXXseparateTile: function (body, tile) {
/*
this._intersection = this.tileIntersects(body, tile);
@@ -952,7 +986,6 @@ Phaser.Physics.Arcade.prototype = {
{
return false;
}
*/
Phaser.Rectangle.intersection(body, tile, this._intersection);
@@ -960,6 +993,7 @@ Phaser.Physics.Arcade.prototype = {
{
return false;
}
*/
// console.log(this._intersection);
// console.log(tile, body.x, body.y);
@@ -982,6 +1016,16 @@ Phaser.Physics.Arcade.prototype = {
body.overlapX = 0;
if (body.deltaX() < 0 && body.checkCollision.left)
{
// Body is moving LEFT
if (tile.tile.faceRight && body.x < tile.right)
{
}
}
var process = false;
if (this._intersection.width > 0)
@@ -989,18 +1033,21 @@ Phaser.Physics.Arcade.prototype = {
// Tile is blocking to the right and body is moving left
if (body.deltaX() < 0 && body.checkCollision.left && tile.tile.faceRight)
{
process = true;
body.overlapX = -this._intersection.width;
body.x = tile.right;
// process = true;
// body.overlapX = -this._intersection.width;
}
// Tile is blocking to the left and body is moving right
if (body.deltaX() > 0 && body.checkCollision.right && tile.tile.faceLeft)
{
process = true;
body.overlapX = this._intersection.width;
body.right = tile.x;
// process = true;
// body.overlapX = this._intersection.width;
}
}
/*
if (body.overlapX !== 0)
{
if (body.overlapX < 0)
@@ -1013,7 +1060,7 @@ Phaser.Physics.Arcade.prototype = {
}
body.x -= body.overlapX;
body.preX -= body.overlapX;
// body.preX -= body.overlapX;
body.blocked.x = Math.floor(body.x);
body.blocked.y = Math.floor(body.y);
@@ -1026,6 +1073,7 @@ Phaser.Physics.Arcade.prototype = {
body.velocity.x = -body.velocity.x * body.bounce.x;
}
}
*/
Phaser.Rectangle.intersection(body, tile, this._intersection);
@@ -1043,8 +1091,9 @@ Phaser.Physics.Arcade.prototype = {
// Tile is blocking to the bottom and body is moving up
if (body.deltaY() < 0 && body.checkCollision.up && tile.tile.faceBottom)
{
process = true;
body.overlapY = -this._intersection.height;
// process = true;
// body.overlapY = -this._intersection.height;
}
// Tile is blocking to the top and body is moving down
@@ -1067,7 +1116,7 @@ Phaser.Physics.Arcade.prototype = {
}
body.y -= body.overlapY;
body.preY -= body.overlapY;
// body.preY -= body.overlapY;
body.blocked.x = Math.floor(body.x);
body.blocked.y = Math.floor(body.y);
@@ -1240,274 +1289,6 @@ Phaser.Physics.Arcade.prototype = {
},
/**
* The core separation function to separate a physics body and an array of tiles.
* @method Phaser.Physics.Arcade#separateTiles
* @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate.
* @param {Phaser.Tile} tile - The tile to collide against.
* @returns {boolean} Returns true if the bodies were separated, otherwise false.
*/
OLDseparateTiles: function (body, tiles) {
// Can't separate two immovable objects (tiles are always immovable)
// if (body.immovable)
// {
// return false;
// }
body.overlapX = 0;
body.overlapY = 0;
var tile;
var localOverlapX = 0;
var localOverlapY = 0;
for (var i = 0; i < tiles.length; i++)
{
tile = tiles[i];
if (Phaser.Rectangle.intersects(body, tile))
{
if (body.deltaX() < 0 && body.checkCollision.left && tile.tile.faceRight)
{
// LEFT
localOverlapX = body.x - tile.right;
if (localOverlapX >= body.deltaX())
{
// console.log('m left overlapX', localOverlapX, body.deltaX());
// use touching instead of blocked?
body.blocked.left = true;
body.touching.left = true;
body.touching.none = false;
}
}
else if (body.deltaX() > 0 && body.checkCollision.right && tile.tile.faceLeft)
{
// RIGHT
localOverlapX = body.right - tile.x;
// Distance check
if (localOverlapX <= body.deltaX())
{
// console.log('m right overlapX', localOverlapX, body.deltaX());
body.blocked.right = true;
body.touching.right = true;
body.touching.none = false;
}
}
if (body.deltaY() < 0 && body.checkCollision.up && tile.tile.faceBottom)
{
// UP
localOverlapY = body.y - tile.bottom;
// Distance check
if (localOverlapY >= body.deltaY())
{
// console.log('m up overlapY', localOverlapY, body.deltaY());
body.blocked.up = true;
body.touching.up = true;
body.touching.none = false;
}
}
else if (body.deltaY() > 0 && body.checkCollision.down && tile.tile.faceTop)
{
// DOWN
localOverlapY = body.bottom - tile.y;
if (localOverlapY <= body.deltaY())
{
// console.log('m down overlapY', localOverlapY, body.deltaY());
body.blocked.down = true;
body.touching.down = true;
body.touching.none = false;
}
}
}
}
if (localOverlapX !== 0)
{
body.overlapX = localOverlapX;
}
if (localOverlapY !== 0)
{
body.overlapY = localOverlapY;
}
if (body.touching.none)
{
return false;
}
// if (body.overlapX !== 0)
if (body.touching.left || body.touching.right)
{
body.x -= body.overlapX;
body.preX -= body.overlapX;
if (body.bounce.x === 0)
{
body.velocity.x = 0;
}
else
{
body.velocity.x = -body.velocity.x * body.bounce.x;
}
}
// if (body.overlapY !== 0)
if (body.touching.up || body.touching.down)
{
body.y -= body.overlapY;
body.preY -= body.overlapY;
if (body.bounce.y === 0)
{
body.velocity.y = 0;
}
else
{
body.velocity.y = -body.velocity.y * body.bounce.y;
}
}
return true;
},
/**
* The core separation function to separate a physics body and a tile.
* @method Phaser.Physics.Arcade#separateTile
* @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate.
* @param {Phaser.Tile} tile - The tile to collide against.
* @returns {boolean} Returns true if the bodies were separated, otherwise false.
*/
OLDseparateTile: function (body, tile) {
// Can't separate two immovable objects (tiles are always immovable)
// if (body.immovable || Phaser.Rectangle.intersects(body, tile) === false)
if (Phaser.Rectangle.intersects(body, tile) === false)
{
// console.log('no intersects');
// console.log('tx', tile.x, 'ty', tile.y, 'tw', tile.width, 'th', tile.height, 'tr', tile.right, 'tb', tile.bottom);
// console.log('bx', body.x, 'by', body.y, 'bw', body.width, 'bh', body.height, 'br', body.right, 'bb', body.bottom);
return false;
}
// use body var instead
body.overlapX = 0;
body.overlapY = 0;
// Remember - this happens AFTER the body has been moved by the motion update, so it needs moving back again
// console.log('---------------------------------------------------------------------------------------------');
// console.log('tx', tile.x, 'ty', tile.y, 'tw', tile.width, 'th', tile.height, 'tr', tile.right, 'tb', tile.bottom);
// console.log('bx', body.x, 'by', body.y, 'bw', body.width, 'bh', body.height, 'br', body.right, 'bb', body.bottom);
// console.log(Phaser.Rectangle.intersects(body, tile));
// console.log('dx', body.deltaX(), 'dy', body.deltaY(), 'dax', body.deltaAbsX(), 'day', body.deltaAbsY(), 'cax', Math.ceil(body.deltaAbsX()), 'cay', Math.ceil(body.deltaAbsY()));
if (body.deltaX() < 0 && body.checkCollision.left && tile.tile.faceRight)
{
// LEFT
body.overlapX = body.x - tile.right;
if (body.overlapX >= body.deltaX())
{
// console.log('left overlapX', body.overlapX, body.deltaX());
// use touching instead of blocked?
body.blocked.left = true;
body.touching.left = true;
body.touching.none = false;
}
}
else if (body.deltaX() > 0 && body.checkCollision.right && tile.tile.faceLeft)
{
// RIGHT
body.overlapX = body.right - tile.x;
// Distance check
if (body.overlapX <= body.deltaX())
{
// console.log('right overlapX', body.overlapX, body.deltaX());
body.blocked.right = true;
body.touching.right = true;
body.touching.none = false;
}
}
if (body.deltaY() < 0 && body.checkCollision.up && tile.tile.faceBottom)
{
// UP
body.overlapY = body.y - tile.bottom;
// Distance check
if (body.overlapY >= body.deltaY())
{
// console.log('up overlapY', body.overlapY, body.deltaY());
body.blocked.up = true;
body.touching.up = true;
body.touching.none = false;
}
}
else if (body.deltaY() > 0 && body.checkCollision.down && tile.tile.faceTop)
{
// DOWN
body.overlapY = body.bottom - tile.y;
if (body.overlapY <= body.deltaY())
{
// console.log('down overlapY', body.overlapY, body.deltaY());
body.blocked.down = true;
body.touching.down = true;
body.touching.none = false;
}
}
// Separate in a single sweep
if (body.touching.none)
{
return false;
}
// if (body.overlapX !== 0)
if (body.touching.left || body.touching.right)
{
body.x -= body.overlapX;
body.preX -= body.overlapX;
if (body.bounce.x === 0)
{
body.velocity.x = 0;
}
else
{
body.velocity.x = -body.velocity.x * body.bounce.x;
}
}
// if (body.overlapY !== 0)
if (body.touching.up || body.touching.down)
{
body.y -= body.overlapY;
body.preY -= body.overlapY;
if (body.bounce.y === 0)
{
body.velocity.y = 0;
}
else
{
body.velocity.y = -body.velocity.y * body.bounce.y;
}
}
return true;
},
/**
* Move the given display object towards the destination object at a steady velocity.
* If you specify a maxTime then it will adjust the speed (overwriting what you set) so it arrives at the destination in that number of seconds.
+842
View File
@@ -0,0 +1,842 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Ninja Physics AABB constructor.
*
* @class Phaser.Physics.Ninja.AABB
* @classdesc Arcade Physics Constructor
* @constructor
* @param {Phaser.Game} game reference to the current game instance.
*/
Phaser.Physics.Ninja.AABB = function (system, x, y, width, height) {
this.system = system;
this.pos = new Phaser.Point(x, y);
this.oldpos = new Phaser.Point(x, y);
this.xw = Math.abs(width / 2);
this.yw = Math.abs(height / 2);
this.width = width;
this.height = height;
this.oH = 0;
this.oV = 0;
// Setting drag to 0 and friction to 0 means you get a normalised speed (px psec)
this.drag = 1;
this.friction = 0.05;
this.gravityScale = 1;
this.bounce = 0.3;
this.velocity = new Phaser.Point();
// temp collision values
this.px = 0;
this.py = 0;
// collision mappings
this.aabbTileProjections = {};
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_FULL] = this.projAABB_Full;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_45DEG] = this.projAABB_45Deg;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_CONCAVE] = this.projAABB_Concave;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_CONVEX] = this.projAABB_Convex;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_22DEGs] = this.projAABB_22DegS;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_22DEGb] = this.projAABB_22DegB;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_67DEGs] = this.projAABB_67DegS;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_67DEGb] = this.projAABB_67DegB;
this.aabbTileProjections[Phaser.Physics.Ninja.Tile.TYPE_HALF] = this.projAABB_Half;
};
Phaser.Physics.Ninja.AABB.prototype.constructor = Phaser.Physics.Ninja.AABB;
Phaser.Physics.Ninja.AABB.COL_NONE = 0;
Phaser.Physics.Ninja.AABB.COL_AXIS = 1;
Phaser.Physics.Ninja.AABB.COL_OTHER = 2;
Phaser.Physics.Ninja.AABB.prototype = {
/**
* Updates this AABBs position.
*
* @method Phaser.Physics.Ninja.AABB#integrate
*/
integrate: function () {
var px = this.pos.x;
var py = this.pos.y;
// integrate
this.pos.x += (this.drag * this.pos.x) - (this.drag * this.oldpos.x);
this.pos.y += (this.drag * this.pos.y) - (this.drag * this.oldpos.y) + (this.system.gravity * this.gravityScale);
// store
this.velocity.set(this.pos.x - px, this.pos.y - py);
this.oldpos.set(px, py);
},
/**
* Process a world collision and apply the resulting forces.
*
* @method Phaser.Physics.Ninja.AABB#reportCollisionVsWorld
* @param {number} px - The tangent velocity
* @param {number} py - The tangent velocity
* @param {number} dx - Collision normal
* @param {number} dy - Collision normal
* @param {number} obj - Object this AABB collided with
*/
reportCollisionVsWorld: function (px, py, dx, dy, obj) {
var p = this.pos;
var o = this.oldpos;
//calc velocity
var vx = p.x - o.x;
var vy = p.y - o.y;
//find component of velocity parallel to collision normal
var dp = (vx * dx + vy * dy);
var nx = dp * dx;//project velocity onto collision normal
var ny = dp * dy;//nx,ny is normal velocity
var tx = vx - nx;//px,py is tangent velocity
var ty = vy - ny;
//we only want to apply collision response forces if the object is travelling into, and not out of, the collision
var b, bx, by, f, fx, fy;
if (dp < 0)
{
//f = FRICTION;
fx = tx * this.friction;
fy = ty * this.friction;
b = 1 + this.bounce;
bx = (nx * b);
by = (ny * b);
}
else
{
//moving out of collision, do not apply forces
bx = by = fx = fy = 0;
}
p.x += px;//project object out of collision
p.y += py;
o.x += px + bx + fx;//apply bounce+friction impulses which alter velocity
o.y += py + by + fy;
},
/**
* Collides this AABB against a Tile.
*
* @method Phaser.Physics.Ninja.AABB#collideAABBVsTile
* @param {Phaser.Physics.Ninja.Tile} tile - The Tile to collide against.
*/
collideAABBVsTile: function (tile) {
var pos = this.pos;
var c = tile;
var tx = c.pos.x;
var ty = c.pos.y;
var txw = c.xw;
var tyw = c.yw;
var dx = pos.x - tx;//tile->obj delta
var px = (txw + this.xw) - Math.abs(dx);//penetration depth in x
if (0 < px)
{
var dy = pos.y - ty;//tile->obj delta
var py = (tyw + this.yw) - Math.abs(dy);//pen depth in y
if (0 < py)
{
//object may be colliding with tile; call tile-specific collision function
//calculate projection vectors
if (px < py)
{
//project in x
if (dx < 0)
{
//project to the left
px *= -1;
py = 0;
}
else
{
//proj to right
py = 0;
}
}
else
{
//project in y
if (dy < 0)
{
//project up
px = 0;
py *= -1;
}
else
{
//project down
px = 0;
}
}
return this.resolveTile(px, py, this, c);
}
}
return false;
},
/**
* Collides this AABB against the world bounds.
*
* @method Phaser.Physics.Ninja.AABB#collideWorldBounds
*/
collideWorldBounds: function () {
var p = this.pos;
var xw = this.xw;
var yw = this.yw;
var XMIN = this.system.bounds.x;
var XMAX = this.system.bounds.width;
var YMIN = this.system.bounds.y;
var YMAX = this.system.bounds.height;
var dx = this.system.bounds.x - (this.pos.x - this.xw);
if (0 < dx)
{
this.reportCollisionVsWorld(dx, 0, 1, 0, null);
}
else
{
dx = (this.pos.x + this.xw) - this.system.bounds.width;
if (0 < dx)
{
this.reportCollisionVsWorld(-dx, 0, -1, 0, null);
}
}
var dy = this.system.bounds.y - (this.pos.y - this.yw);
if (0 < dy)
{
this.reportCollisionVsWorld(0, dy, 0, 1, null);
}
else
{
dy = (this.pos.y + this.yw) - this.system.bounds.height;
if (0 < dy)
{
this.reportCollisionVsWorld(0, -dy, 0, -1, null);
}
}
},
/**
* Renders this AABB to the context.
*
* @method Phaser.Physics.Ninja.AABB#render
*/
render: function (context) {
context.beginPath();
context.strokeStyle = 'rgb(0,255,0)';
context.strokeRect(this.pos.x - this.xw, this.pos.y - this.yw, this.xw * 2, this.yw * 2);
context.stroke();
context.closePath();
context.fillStyle = 'rgb(0,255,0)';
context.fillRect(this.pos.x, this.pos.y, 2, 2);
/*
if (this.oH == 1)
{
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius);
context.lineTo(this.pos.x - this.radius, this.pos.y + this.radius);
context.stroke();
context.closePath();
}
else if (this.oH == -1)
{
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.pos.x + this.radius, this.pos.y - this.radius);
context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius);
context.stroke();
context.closePath();
}
if (this.oV == 1)
{
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius);
context.lineTo(this.pos.x + this.radius, this.pos.y - this.radius);
context.stroke();
context.closePath();
}
else if (this.oV == -1)
{
context.beginPath();
context.strokeStyle = 'rgb(255,0,0)';
context.moveTo(this.pos.x - this.radius, this.pos.y + this.radius);
context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius);
context.stroke();
context.closePath();
}
*/
},
/**
* Resolves tile collision.
*
* @method Phaser.Physics.Ninja.AABB#resolveTile
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} body - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} tile - The Tile involved in the collision.
* @return {boolean} True if the collision was processed, otherwise false.
*/
resolveTile: function (x, y, body, tile) {
if (0 < tile.id)
{
return this.aabbTileProjections[tile.type](x, y, body, tile);
}
else
{
console.warn("Ninja.AABB.resolveTile was called with an empty (or unknown) tile!: id=" + tile.id + ")");
return false;
}
},
/**
* Resolves Full tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_Full
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_Full: function (x, y, obj, t) {
var l = Math.sqrt(x * x + y * y);
obj.reportCollisionVsWorld(x, y, x / l, y / l, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
},
/**
* Resolves Half tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_Half
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_Half: function (x, y, obj, t) {
//signx or signy must be 0; the other must be -1 or 1
//calculate the projection vector for the half-edge, and then
//(if collision is occuring) pick the minimum
var sx = t.signx;
var sy = t.signy;
var ox = (obj.pos.x - (sx*obj.xw)) - t.pos.x;//this gives is the coordinates of the innermost
var oy = (obj.pos.y - (sy*obj.yw)) - t.pos.y;//point on the AABB, relative to the tile center
//we perform operations analogous to the 45deg tile, except we're using
//an axis-aligned slope instead of an angled one..
//if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope
//and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy)
var dp = (ox*sx) + (oy*sy);
if (dp < 0)
{
//collision; project delta onto slope and use this to displace the object
sx *= -dp;//(sx,sy) is now the projection vector
sy *= -dp;
var lenN = Math.sqrt(sx*sx + sy*sy);
var lenP = Math.sqrt(x*x + y*y);
if (lenP < lenN)
{
//project along axis; note that we're assuming that this tile is horizontal OR vertical
//relative to the AABB's current tile, and not diagonal OR the current tile.
obj.reportCollisionVsWorld(x,y,x/lenP, y/lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
else
{
//note that we could use -= instead of -dp
obj.reportCollisionVsWorld(sx,sy,t.signx, t.signy, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves 45 Degree tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_45Deg
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_45Deg: function (x, y, obj, t) {
var signx = t.signx;
var signy = t.signy;
var ox = (obj.pos.x - (signx*obj.xw)) - t.pos.x;//this gives is the coordinates of the innermost
var oy = (obj.pos.y - (signy*obj.yw)) - t.pos.y;//point on the AABB, relative to the tile center
var sx = t.sx;
var sy = t.sy;
//if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope
//and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy)
var dp = (ox*sx) + (oy*sy);
if (dp < 0)
{
//collision; project delta onto slope and use this to displace the object
sx *= -dp;//(sx,sy) is now the projection vector
sy *= -dp;
var lenN = Math.sqrt(sx*sx + sy*sy);
var lenP = Math.sqrt(x*x + y*y);
if (lenP < lenN)
{
//project along axis
obj.reportCollisionVsWorld(x,y,x/lenP, y/lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
else
{
//project along slope
obj.reportCollisionVsWorld(sx,sy,t.sx,t.sy);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves 22 Degree tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_22DegS
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_22DegS: function (x, y, obj, t) {
var signx = t.signx;
var signy = t.signy;
//first we need to check to make sure we're colliding with the slope at all
var py = obj.pos.y - (signy*obj.yw);
var penY = t.pos.y - py;//this is the vector from the innermost point on the box to the highest point on
//the tile; if it is positive, this means the box is above the tile and
//no collision is occuring
if (0 < (penY*signy))
{
var ox = (obj.pos.x - (signx*obj.xw)) - (t.pos.x + (signx*t.xw));//this gives is the coordinates of the innermost
var oy = (obj.pos.y - (signy*obj.yw)) - (t.pos.y - (signy*t.yw));//point on the AABB, relative to a point on the slope
var sx = t.sx;//get slope unit normal
var sy = t.sy;
//if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope
//and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy)
var dp = (ox*sx) + (oy*sy);
if (dp < 0)
{
//collision; project delta onto slope and use this to displace the object
sx *= -dp;//(sx,sy) is now the projection vector
sy *= -dp;
var lenN = Math.sqrt(sx*sx + sy*sy);
var lenP = Math.sqrt(x*x + y*y);
var aY = Math.abs(penY);
if (lenP < lenN)
{
if (aY < lenP)
{
obj.reportCollisionVsWorld(0, penY, 0, penY/aY, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
else
{
obj.reportCollisionVsWorld(x,y,x/lenP, y/lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
}
else
{
if (aY < lenN)
{
obj.reportCollisionVsWorld(0, penY, 0, penY/aY, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
else
{
obj.reportCollisionVsWorld(sx,sy,t.sx,t.sy,t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
}
}
//if we've reached this point, no collision has occured
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves 22 Degree tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_22DegB
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_22DegB: function (x, y, obj, t) {
var signx = t.signx;
var signy = t.signy;
var ox = (obj.pos.x - (signx*obj.xw)) - (t.pos.x - (signx*t.xw));//this gives is the coordinates of the innermost
var oy = (obj.pos.y - (signy*obj.yw)) - (t.pos.y + (signy*t.yw));//point on the AABB, relative to a point on the slope
var sx = t.sx;//get slope unit normal
var sy = t.sy;
//if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope
//and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy)
var dp = (ox*sx) + (oy*sy);
if (dp < 0)
{
//collision; project delta onto slope and use this to displace the object
sx *= -dp;//(sx,sy) is now the projection vector
sy *= -dp;
var lenN = Math.sqrt(sx*sx + sy*sy);
var lenP = Math.sqrt(x*x + y*y);
if (lenP < lenN)
{
obj.reportCollisionVsWorld(x,y,x/lenP, y/lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
else
{
obj.reportCollisionVsWorld(sx,sy,t.sx,t.sy,t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves 67 Degree tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_67DegS
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_67DegS: function (x, y, obj, t) {
var signx = t.signx;
var signy = t.signy;
var px = obj.pos.x - (signx*obj.xw);
var penX = t.pos.x - px;
if (0 < (penX*signx))
{
var ox = (obj.pos.x - (signx*obj.xw)) - (t.pos.x - (signx*t.xw));//this gives is the coordinates of the innermost
var oy = (obj.pos.y - (signy*obj.yw)) - (t.pos.y + (signy*t.yw));//point on the AABB, relative to a point on the slope
var sx = t.sx;//get slope unit normal
var sy = t.sy;
//if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope
//and we need to project it out by the magnitude of the projection of (ox,oy) onto (sx,sy)
var dp = (ox*sx) + (oy*sy);
if (dp < 0)
{
//collision; project delta onto slope and use this to displace the object
sx *= -dp;//(sx,sy) is now the projection vector
sy *= -dp;
var lenN = Math.sqrt(sx*sx + sy*sy);
var lenP = Math.sqrt(x*x + y*y);
var aX = Math.abs(penX);
if (lenP < lenN)
{
if (aX < lenP)
{
obj.reportCollisionVsWorld(penX, 0, penX/aX, 0, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
else
{
obj.reportCollisionVsWorld(x,y,x/lenP, y/lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
}
else
{
if (aX < lenN)
{
obj.reportCollisionVsWorld(penX, 0, penX/aX, 0, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
else
{
obj.reportCollisionVsWorld(sx,sy,t.sx,t.sy,t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
}
}
//if we've reached this point, no collision has occured
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves 67 Degree tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_67DegB
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_67DegB: function (x, y, obj, t) {
var signx = t.signx;
var signy = t.signy;
var ox = (obj.pos.x - (signx*obj.xw)) - (t.pos.x + (signx*t.xw));//this gives is the coordinates of the innermost
var oy = (obj.pos.y - (signy*obj.yw)) - (t.pos.y - (signy*t.yw));//point on the AABB, relative to a point on the slope
var sx = t.sx;//get slope unit normal
var sy = t.sy;
//if the dotprod of (ox,oy) and (sx,sy) is negative, the corner is in the slope
//and we need toproject it out by the magnitude of the projection of (ox,oy) onto (sx,sy)
var dp = (ox*sx) + (oy*sy);
if (dp < 0)
{
//collision; project delta onto slope and use this to displace the object
sx *= -dp;//(sx,sy) is now the projection vector
sy *= -dp;
var lenN = Math.sqrt(sx*sx + sy*sy);
var lenP = Math.sqrt(x*x + y*y);
if (lenP < lenN)
{
obj.reportCollisionVsWorld(x,y,x/lenP, y/lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
else
{
obj.reportCollisionVsWorld(sx,sy,t.sx,t.sy,t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves Convex tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_Convex
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_Convex: function (x, y, obj, t) {
//if distance from "innermost" corner of AABB is less than than tile radius,
//collision is occuring and we need to project
var signx = t.signx;
var signy = t.signy;
var ox = (obj.pos.x - (signx * obj.xw)) - (t.pos.x - (signx * t.xw));//(ox,oy) is the vector from the circle center to
var oy = (obj.pos.y - (signy * obj.yw)) - (t.pos.y - (signy * t.yw));//the AABB
var len = Math.sqrt(ox * ox + oy * oy);
var twid = t.xw * 2;
var rad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
//note that this should be precomputed at compile-time since it's constant
var pen = rad - len;
if (((signx * ox) < 0) || ((signy * oy) < 0))
{
//the test corner is "outside" the 1/4 of the circle we're interested in
var lenP = Math.sqrt(x * x + y * y);
obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;//we need to report
}
else if (0 < pen)
{
//project along corner->circle vector
ox /= len;
oy /= len;
obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
return Phaser.Physics.Ninja.AABB.COL_NONE;
},
/**
* Resolves Concave tile collision.
*
* @method Phaser.Physics.Ninja.AABB#projAABB_Concave
* @param {number} x - Penetration depth on the x axis.
* @param {number} y - Penetration depth on the y axis.
* @param {Phaser.Physics.Ninja.AABB} obj - The AABB involved in the collision.
* @param {Phaser.Physics.Ninja.Tile} t - The Tile involved in the collision.
* @return {number} The result of the collision.
*/
projAABB_Concave: function (x, y, obj, t) {
//if distance from "innermost" corner of AABB is further than tile radius,
//collision is occuring and we need to project
var signx = t.signx;
var signy = t.signy;
var ox = (t.pos.x + (signx * t.xw)) - (obj.pos.x - (signx * obj.xw));//(ox,oy) is the vector form the innermost AABB corner to the
var oy = (t.pos.y + (signy * t.yw)) - (obj.pos.y - (signy * obj.yw));//circle's center
var twid = t.xw * 2;
var rad = Math.sqrt(twid * twid + 0);//this gives us the radius of a circle centered on the tile's corner and extending to the opposite edge of the tile;
//note that this should be precomputed at compile-time since it's constant
var len = Math.sqrt(ox * ox + oy * oy);
var pen = len - rad;
if (0 < pen)
{
//collision; we need to either project along the axes, or project along corner->circlecenter vector
var lenP = Math.sqrt(x * x + y * y);
if (lenP < pen)
{
//it's shorter to move along axis directions
obj.reportCollisionVsWorld(x, y, x / lenP, y / lenP, t);
return Phaser.Physics.Ninja.AABB.COL_AXIS;
}
else
{
//project along corner->circle vector
ox /= len;//len should never be 0, since if it IS 0, rad should be > than len
oy /= len;//and we should never reach here
obj.reportCollisionVsWorld(ox * pen, oy * pen, ox, oy, t);
return Phaser.Physics.Ninja.AABB.COL_OTHER;
}
}
return Phaser.Physics.Ninja.AABB.COL_NONE;
}
}
+411
View File
@@ -0,0 +1,411 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* The Physics Body is linked to a single Sprite. All physics operations should be performed against the body rather than
* the Sprite itself. For example you can set the velocity, bounce values etc all on the Body.
*
* @class Phaser.Physics.Ninja.Body
* @classdesc Ninja Physics Body Constructor
* @constructor
* @param {Phaser.Physics.Ninja} system - The physics system this Body belongs to.
* @param {Phaser.Sprite} sprite - The Sprite object this physics body belongs to.
* @param {number} [type=1] - The type of Ninja shape to create. 1 = AABB, 2 = Circle or 3 = Tile.
* @param {number} [id=1] - If this body is using a Tile shape, you can set the Tile id here, i.e. Phaser.Physics.Ninja.Tile.SLOPE_45DEGpn, Phaser.Physics.Ninja.Tile.CONVEXpp, etc.
*/
Phaser.Physics.Ninja.Body = function (system, sprite, type, id) {
if (typeof type === 'undefined') { type = 1; }
if (typeof id === 'undefined') { id = 1; }
/**
* @property {Phaser.Sprite} sprite - Reference to the parent Sprite.
*/
this.sprite = sprite;
/**
* @property {Phaser.Game} game - Local reference to game.
*/
this.game = sprite.game;
/**
* @property {number} type - The type of physics system this body belongs to.
*/
this.type = Phaser.Physics.NINJA;
/**
* @property {Phaser.Physics.Ninja} system - The parent physics system.
*/
this.system = system;
/**
* @property {Phaser.Physics.Ninja.AABB} aabb - The AABB object this body is using for collision.
*/
this.aabb = null;
/**
* @property {Phaser.Physics.Ninja.Tile} tile - The Tile object this body is using for collision.
*/
this.tile = null;
/**
* @property {Phaser.Physics.Ninja.Circle} circle - The Circle object this body is using for collision.
*/
this.circle = null;
/**
* @property {object} shape - A local reference to the body shape.
*/
this.shape = null;
if (type === 1)
{
this.aabb = new Phaser.Physics.Ninja.AABB(system, sprite.x, sprite.y, sprite.width, sprite.height);
this.shape = this.aabb;
}
else if (type === 2)
{
this.circle = new Phaser.Physics.Ninja.Circle(system, sprite.x, sprite.y, sprite.width, sprite.height);
this.shape = this.circle;
}
else if (type === 3)
{
this.tile = new Phaser.Physics.Ninja.Tile(system, sprite.x, sprite.y, sprite.width, sprite.height, id);
this.shape = this.tile;
}
/**
* @property {Phaser.Point} velocity - The velocity in pixels per second sq. of the Body.
*/
this.velocity = new Phaser.Point();
/**
* @property {Phaser.Point} drag - The drag applied to the motion of the Body.
*/
this.drag = new Phaser.Point();
/**
* @property {Phaser.Point} bounce - The elasticitiy of the Body when colliding. bounce.x/y = 1 means full rebound, bounce.x/y = 0.5 means 50% rebound velocity.
*/
this.bounce = new Phaser.Point();
/**
* @property {boolean} skipQuadTree - If the Body is an irregular shape you can set this to true to avoid it being added to any QuadTrees.
* @default
*/
this.skipQuadTree = false;
/**
* @property {number} facing - A const reference to the direction the Body is traveling or facing.
* @default
*/
this.facing = Phaser.NONE;
/**
* @property {boolean} immovable - An immovable Body will not receive any impacts from other bodies.
* @default
*/
this.immovable = false;
/**
* A Body can be set to collide against the World bounds automatically and rebound back into the World if this is set to true. Otherwise it will leave the World.
* @property {boolean} collideWorldBounds - Should the Body collide with the World bounds?
*/
this.collideWorldBounds = true;
/**
* This object is populated with boolean values when the Body collides with another.
* touching.up = true means the collision happened to the top of this Body for example.
* @property {object} touching - An object containing touching results.
*/
this.touching = { none: true, up: false, down: false, left: false, right: false };
/**
* This object is populated with previous touching values from the bodies previous collision.
* @property {object} wasTouching - An object containing previous touching results.
*/
this.wasTouching = { none: true, up: false, down: false, left: false, right: false };
this.maxSpeed = 8;
};
Phaser.Physics.Ninja.Body.prototype = {
/**
* Internal method.
*
* @method Phaser.Physics.Ninja.Body#updateBounds
* @protected
*/
updateBounds: function (centerX, centerY, scaleX, scaleY) {
if (scaleX != this._sx || scaleY != this._sy)
{
// this.width = this.sourceWidth * scaleX;
// this.height = this.sourceHeight * scaleY;
// this.halfWidth = Math.floor(this.width / 2);
// this.halfHeight = Math.floor(this.height / 2);
// this._sx = scaleX;
// this._sy = scaleY;
// this.center.setTo(this.x + this.halfWidth, this.y + this.halfHeight);
}
},
/**
* Internal method.
*
* @method Phaser.Physics.Ninja.Body#preUpdate
* @protected
*/
preUpdate: function () {
// Store and reset collision flags
this.wasTouching.none = this.touching.none;
this.wasTouching.up = this.touching.up;
this.wasTouching.down = this.touching.down;
this.wasTouching.left = this.touching.left;
this.wasTouching.right = this.touching.right;
this.touching.none = true;
this.touching.up = false;
this.touching.down = false;
this.touching.left = false;
this.touching.right = false;
this.shape.integrate();
if (this.collideWorldBounds)
{
this.shape.collideWorldBounds();
}
this.speed = Math.sqrt(this.shape.velocity.x * this.shape.velocity.x + this.shape.velocity.y * this.shape.velocity.y);
this.angle = Math.atan2(this.shape.velocity.y, this.shape.velocity.x);
},
/**
* Internal method.
*
* @method Phaser.Physics.Ninja.Body#postUpdate
* @protected
*/
postUpdate: function () {
this.sprite.x = this.shape.pos.x;
this.sprite.y = this.shape.pos.y;
},
/**
* Stops all movement of this body.
*
* @method Phaser.Physics.Ninja.Body#setZeroVelocity
*/
setZeroVelocity: function () {
this.shape.oldpos.x = this.shape.pos.x;
this.shape.oldpos.y = this.shape.pos.y;
},
/**
* Moves the Body forwards based on its current angle and the given speed.
* The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
*
* @method Phaser.Physics.Body#moveTo
* @param {number} speed - The speed at which it should move forwards.
* @param {number} angle - The angle in which it should move, given in degrees.
*/
moveTo: function (speed, angle) {
var magnitude = speed * this.game.time.physicsElapsed;
var angle = this.game.math.degToRad(angle);
this.shape.pos.x = this.shape.oldpos.x + (magnitude * Math.cos(angle));
this.shape.pos.y = this.shape.oldpos.y + (magnitude * Math.sin(angle));
},
/**
* Moves the Body backwards based on its current angle and the given speed.
* The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
*
* @method Phaser.Physics.Body#moveBackward
* @param {number} speed - The speed at which it should move backwards.
* @param {number} angle - The angle in which it should move, given in degrees.
*/
moveFrom: function (speed, angle) {
var magnitude = -speed * this.game.time.physicsElapsed;
var angle = this.game.math.degToRad(angle);
this.shape.pos.x = this.shape.oldpos.x + (magnitude * Math.cos(angle));
this.shape.pos.y = this.shape.oldpos.y + (magnitude * Math.sin(angle));
},
/**
* If this Body is dynamic then this will move it to the left by setting its x velocity to the given speed.
* The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
*
* @method Phaser.Physics.Body#moveLeft
* @param {number} speed - The speed at which it should move to the left, in pixels per second.
*/
moveLeft: function (speed) {
var fx = -speed * this.game.time.physicsElapsed;
this.shape.pos.x = this.shape.oldpos.x + Math.min(this.maxSpeed, Math.max(-this.maxSpeed, this.shape.pos.x - this.shape.oldpos.x + fx));
},
/**
* If this Body is dynamic then this will move it to the right by setting its x velocity to the given speed.
* The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
*
* @method Phaser.Physics.Body#moveRight
* @param {number} speed - The speed at which it should move to the right, in pixels per second.
*/
moveRight: function (speed) {
var fx = speed * this.game.time.physicsElapsed;
this.shape.pos.x = this.shape.oldpos.x + Math.min(this.maxSpeed, Math.max(-this.maxSpeed, this.shape.pos.x - this.shape.oldpos.x + fx));
},
/**
* If this Body is dynamic then this will move it up by setting its y velocity to the given speed.
* The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
*
* @method Phaser.Physics.Body#moveUp
* @param {number} speed - The speed at which it should move up, in pixels per second.
*/
moveUp: function (speed) {
var fx = -speed * this.game.time.physicsElapsed;
this.shape.pos.y = this.shape.oldpos.y + Math.min(this.maxSpeed, Math.max(-this.maxSpeed, this.shape.pos.y - this.shape.oldpos.y + fx));
},
/**
* If this Body is dynamic then this will move it down by setting its y velocity to the given speed.
* The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second (1000ms).
*
* @method Phaser.Physics.Body#moveDown
* @param {number} speed - The speed at which it should move down, in pixels per second.
*/
moveDown: function (speed) {
var fx = speed * this.game.time.physicsElapsed;
this.shape.pos.y = this.shape.oldpos.y + Math.min(this.maxSpeed, Math.max(-this.maxSpeed, this.shape.pos.y - this.shape.oldpos.y + fx));
},
/**
* Resets all Body values (velocity, acceleration, rotation, etc)
*
* @method Phaser.Physics.Ninja.Body#reset
*/
reset: function () {
},
};
/**
* @name Phaser.Physics.Ninja.Body#x
* @property {number} x - The x position.
*/
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "x", {
/**
* The x position.
* @method x
* @return {number}
*/
get: function () {
return this.shape.pos.x;
},
/**
* The x position.
* @method x
* @param {number} value
*/
set: function (value) {
this.shape.pos.x = value;
}
});
/**
* @name Phaser.Physics.Ninja.Body#y
* @property {number} y - The y position.
*/
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "y", {
/**
* The y position.
* @method y
* @return {number}
*/
get: function () {
return this.shape.pos.y;
},
/**
* The y position.
* @method y
* @param {number} value
*/
set: function (value) {
this.shape.pos.y = value;
}
});
/**
* @name Phaser.Physics.Ninja.Body#bottom
* @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height)
* @readonly
*/
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "bottom", {
/**
* The sum of the y and height properties.
* @method bottom
* @return {number}
* @readonly
*/
get: function () {
return this.shape.pos.y + this.shape.height;
}
});
/**
* @name Phaser.Physics.Ninja.Body#right
* @property {number} right - The right value of this Body (same as Body.x + Body.width)
* @readonly
*/
Object.defineProperty(Phaser.Physics.Ninja.Body.prototype, "right", {
/**
* The sum of the x and width properties.
* @method right
* @return {number}
* @readonly
*/
get: function () {
return this.shape.pos.x + this.shape.width;
}
});
+17
View File
@@ -0,0 +1,17 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Ninja Physics Circle constructor.
*
* @class Phaser.Physics.Ninja.Circle
* @classdesc Arcade Physics Constructor
* @constructor
* @param {Phaser.Game} game reference to the current game instance.
*/
Phaser.Physics.Ninja.Circle = function (system, x, y, width, height) {
}
+616
View File
@@ -0,0 +1,616 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Ninja Physics Tile constructor.
*
* @class Phaser.Physics.Ninja.Tile
* @classdesc Arcade Physics Constructor
* @constructor
* @param {Phaser.Game} game reference to the current game instance.
*/
Phaser.Physics.Ninja.Tile = function (system, x, y, width, height, type) {
if (typeof type === 'undefined') { type = Phaser.Physics.Ninja.Tile.EMPTY; }
this.system = system;
this.id = type;
this.type = Phaser.Physics.Ninja.Tile.TYPE_EMPTY;
this.pos = new Phaser.Point(x, y);
this.oldpos = new Phaser.Point(x, y);
if (this.id > 1 && this.id < 30)
{
// Tile Types 2 to 29 require square tile dimensions, so use the width as the base
height = width;
}
this.xw = Math.abs(width / 2);
this.yw = Math.abs(height / 2);
this.width = width;
this.height = height;
this.drag = 1;
this.friction = 0.05;
this.gravityScale = 1;
this.bounce = 0.3;
this.velocity = new Phaser.Point();
// This stores tile-specific collision information
this.signx = 0;
this.signy = 0;
this.sx = 0;
this.sy = 0;
if (this.id > 0)
{
this.setType(this.id);
}
};
Phaser.Physics.Ninja.Tile.prototype.constructor = Phaser.Physics.Ninja.Tile;
Phaser.Physics.Ninja.Tile.prototype = {
/**
* Updates this AABBs position.
*
* @method Phaser.Physics.Ninja.AABB#integrate
*/
integrate: function () {
var px = this.pos.x;
var py = this.pos.y;
this.pos.x += (this.drag * this.pos.x) - (this.drag * this.oldpos.x);
this.pos.y += (this.drag * this.pos.y) - (this.drag * this.oldpos.y);
this.velocity.set(this.pos.x - px, this.pos.y - py);
this.oldpos.set(px, py);
},
collideWorldBounds: function () {
},
//these functions are used to update the cell
//note: id is assumed to NOT be "empty" state..
//if it IS the empty state, the tile clears itself
setType: function (id) {
if (id === Phaser.Physics.Ninja.Tile.EMPTY)
{
this.clear();
}
else
{
//set tile state to a non-emtpy value, and update it's edges and those of the neighbors
this.id = id;
this.updateType();
}
return this;
},
clear: function () {
this.id = Phaser.Physics.Ninja.Tile.EMPTY;
this.updateType();
},
render: function (context, key) {
if (this.id === 0)
{
return;
}
var image = this.system.game.cache.getImage(key);
var data = this.system.game.cache.getFrameData(key);
var frame = data._frames[this.id - 1];
context.drawImage(image, frame.x, frame.y, frame.width, frame.height, this.x, this.y, this.width, this.height);
// context.beginPath();
// context.strokeStyle = 'rgb(255,255,0)';
// context.strokeRect(this.x, this.y, this.width, this.height);
// context.strokeRect(this.pos.x, this.pos.y, 2, 2); // center point
// context.closePath();
},
//this converts a tile from implicitly-defined (via id), to explicit (via properties)
updateType: function () {
if (this.id === 0)
{
//EMPTY
this.type = Phaser.Physics.Ninja.Tile.TYPE_EMPTY;
this.signx = 0;
this.signy = 0;
this.sx = 0;
this.sy = 0;
return true;
}
//tile is non-empty; collide
if (this.id < Phaser.Physics.Ninja.Tile.TYPE_45DEG)
{
//FULL
this.type = Phaser.Physics.Ninja.Tile.TYPE_FULL;
this.signx = 0;
this.signy = 0;
this.sx = 0;
this.sy = 0;
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_CONCAVE)
{
// 45deg
this.type = Phaser.Physics.Ninja.Tile.TYPE_45DEG;
if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_45DEGpn)
{
this.signx = 1;
this.signy = -1;
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_45DEGnn)
{
this.signx = -1;
this.signy = -1;
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_45DEGnp)
{
this.signx = -1;
this.signy = 1;
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_45DEGpp)
{
this.signx = 1;
this.signy = 1;
this.sx = this.signx / Math.SQRT2;//get slope _unit_ normal
this.sy = this.signy / Math.SQRT2;//since normal is (1,-1), length is sqrt(1*1 + -1*-1) = sqrt(2)
}
else
{
return false;
}
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_CONVEX)
{
// Concave
this.type = Phaser.Physics.Ninja.Tile.TYPE_CONCAVE;
if (this.id == Phaser.Physics.Ninja.Tile.CONCAVEpn)
{
this.signx = 1;
this.signy = -1;
this.sx = 0;
this.sy = 0;
}
else if (this.id == Phaser.Physics.Ninja.Tile.CONCAVEnn)
{
this.signx = -1;
this.signy = -1;
this.sx = 0;
this.sy = 0;
}
else if (this.id == Phaser.Physics.Ninja.Tile.CONCAVEnp)
{
this.signx = -1;
this.signy = 1;
this.sx = 0;
this.sy = 0;
}
else if (this.id == Phaser.Physics.Ninja.Tile.CONCAVEpp)
{
this.signx = 1;
this.signy = 1;
this.sx = 0;
this.sy = 0;
}
else
{
return false;
}
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_22DEGs)
{
// Convex
this.type = Phaser.Physics.Ninja.Tile.TYPE_CONVEX;
if (this.id == Phaser.Physics.Ninja.Tile.CONVEXpn)
{
this.signx = 1;
this.signy = -1;
this.sx = 0;
this.sy = 0;
}
else if (this.id == Phaser.Physics.Ninja.Tile.CONVEXnn)
{
this.signx = -1;
this.signy = -1;
this.sx = 0;
this.sy = 0;
}
else if (this.id == Phaser.Physics.Ninja.Tile.CONVEXnp)
{
this.signx = -1;
this.signy = 1;
this.sx = 0;
this.sy = 0;
}
else if (this.id == Phaser.Physics.Ninja.Tile.CONVEXpp)
{
this.signx = 1;
this.signy = 1;
this.sx = 0;
this.sy = 0;
}
else
{
return false;
}
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_22DEGb)
{
// 22deg small
this.type = Phaser.Physics.Ninja.Tile.TYPE_22DEGs;
if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGpnS)
{
this.signx = 1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGnnS)
{
this.signx = -1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGnpS)
{
this.signx = -1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGppS)
{
this.signx = 1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else
{
return false;
}
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_67DEGs)
{
// 22deg big
this.type = Phaser.Physics.Ninja.Tile.TYPE_22DEGb;
if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGpnB)
{
this.signx = 1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGnnB)
{
this.signx = -1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGnpB)
{
this.signx = -1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_22DEGppB)
{
this.signx = 1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 1) / slen;
this.sy = (this.signy * 2) / slen;
}
else
{
return false;
}
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_67DEGb)
{
// 67deg small
this.type = Phaser.Physics.Ninja.Tile.TYPE_67DEGs;
if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGpnS)
{
this.signx = 1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGnnS)
{
this.signx = -1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGnpS)
{
this.signx = -1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGppS)
{
this.signx = 1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else
{
return false;
}
}
else if (this.id < Phaser.Physics.Ninja.Tile.TYPE_HALF)
{
// 67deg big
this.type = Phaser.Physics.Ninja.Tile.TYPE_67DEGb;
if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGpnB)
{
this.signx = 1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGnnB)
{
this.signx = -1;
this.signy = -1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGnpB)
{
this.signx = -1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else if (this.id == Phaser.Physics.Ninja.Tile.SLOPE_67DEGppB)
{
this.signx = 1;
this.signy = 1;
var slen = Math.sqrt(2 * 2 + 1 * 1);
this.sx = (this.signx * 2) / slen;
this.sy = (this.signy * 1) / slen;
}
else
{
return false;
}
}
else
{
// Half-full tile
this.type = Phaser.Physics.Ninja.Tile.TYPE_HALF;
if (this.id == Phaser.Physics.Ninja.Tile.HALFd)
{
this.signx = 0;
this.signy = -1;
this.sx = this.signx;
this.sy = this.signy;
}
else if (this.id == Phaser.Physics.Ninja.Tile.HALFu)
{
this.signx = 0;
this.signy = 1;
this.sx = this.signx;
this.sy = this.signy;
}
else if (this.id == Phaser.Physics.Ninja.Tile.HALFl)
{
this.signx = 1;
this.signy = 0;
this.sx = this.signx;
this.sy = this.signy;
}
else if (this.id == Phaser.Physics.Ninja.Tile.HALFr)
{
this.signx = -1;
this.signy = 0;
this.sx = this.signx;
this.sy = this.signy;
}
else
{
return false;
}
}
}
}
/**
* @name Phaser.Physics.Ninja.Tile#x
* @property {number} x - The x position.
*/
Object.defineProperty(Phaser.Physics.Ninja.Tile.prototype, "x", {
/**
* The x position.
* @method x
* @return {number}
*/
get: function () {
return this.pos.x - this.xw;
},
/**
* The x position.
* @method x
* @param {number} value
*/
set: function (value) {
this.pos.x = value;
}
});
/**
* @name Phaser.Physics.Ninja.Tile#y
* @property {number} y - The y position.
*/
Object.defineProperty(Phaser.Physics.Ninja.Tile.prototype, "y", {
/**
* The y position.
* @method y
* @return {number}
*/
get: function () {
return this.pos.y - this.yw;
},
/**
* The y position.
* @method y
* @param {number} value
*/
set: function (value) {
this.pos.y = value;
}
});
/**
* @name Phaser.Physics.Ninja.Tile#bottom
* @property {number} bottom - The bottom value of this Body (same as Body.y + Body.height)
* @readonly
*/
Object.defineProperty(Phaser.Physics.Ninja.Tile.prototype, "bottom", {
/**
* The sum of the y and height properties.
* @method bottom
* @return {number}
* @readonly
*/
get: function () {
return this.pos.y + this.yw;
}
});
/**
* @name Phaser.Physics.Ninja.Tile#right
* @property {number} right - The right value of this Body (same as Body.x + Body.width)
* @readonly
*/
Object.defineProperty(Phaser.Physics.Ninja.Tile.prototype, "right", {
/**
* The sum of the x and width properties.
* @method right
* @return {number}
* @readonly
*/
get: function () {
return this.pos.x + this.xw;
}
});
// TILETYPE ENUMERATION
Phaser.Physics.Ninja.Tile.EMPTY = 0;
Phaser.Physics.Ninja.Tile.FULL = 1;//fullAABB tile
Phaser.Physics.Ninja.Tile.SLOPE_45DEGpn = 2;//45-degree triangle, whose normal is (+ve,-ve)
Phaser.Physics.Ninja.Tile.SLOPE_45DEGnn = 3;//(+ve,+ve)
Phaser.Physics.Ninja.Tile.SLOPE_45DEGnp = 4;//(-ve,+ve)
Phaser.Physics.Ninja.Tile.SLOPE_45DEGpp = 5;//(-ve,-ve)
Phaser.Physics.Ninja.Tile.CONCAVEpn = 6;//1/4-circle cutout
Phaser.Physics.Ninja.Tile.CONCAVEnn = 7;
Phaser.Physics.Ninja.Tile.CONCAVEnp = 8;
Phaser.Physics.Ninja.Tile.CONCAVEpp = 9;
Phaser.Physics.Ninja.Tile.CONVEXpn = 10;//1/4/circle
Phaser.Physics.Ninja.Tile.CONVEXnn = 11;
Phaser.Physics.Ninja.Tile.CONVEXnp = 12;
Phaser.Physics.Ninja.Tile.CONVEXpp = 13;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGpnS = 14;//22.5 degree slope
Phaser.Physics.Ninja.Tile.SLOPE_22DEGnnS = 15;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGnpS = 16;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGppS = 17;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGpnB = 18;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGnnB = 19;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGnpB = 20;
Phaser.Physics.Ninja.Tile.SLOPE_22DEGppB = 21;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGpnS = 22;//67.5 degree slope
Phaser.Physics.Ninja.Tile.SLOPE_67DEGnnS = 23;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGnpS = 24;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGppS = 25;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGpnB = 26;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGnnB = 27;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGnpB = 28;
Phaser.Physics.Ninja.Tile.SLOPE_67DEGppB = 29;
Phaser.Physics.Ninja.Tile.HALFd = 30;//half-full tiles
Phaser.Physics.Ninja.Tile.HALFr = 31;
Phaser.Physics.Ninja.Tile.HALFu = 32;
Phaser.Physics.Ninja.Tile.HALFl = 33;
//collision shape "types"
Phaser.Physics.Ninja.Tile.TYPE_EMPTY = 0;
Phaser.Physics.Ninja.Tile.TYPE_FULL = 1;
Phaser.Physics.Ninja.Tile.TYPE_45DEG = 2;
Phaser.Physics.Ninja.Tile.TYPE_CONCAVE = 6;
Phaser.Physics.Ninja.Tile.TYPE_CONVEX = 10;
Phaser.Physics.Ninja.Tile.TYPE_22DEGs = 14;
Phaser.Physics.Ninja.Tile.TYPE_22DEGb = 18;
Phaser.Physics.Ninja.Tile.TYPE_67DEGs = 22;
Phaser.Physics.Ninja.Tile.TYPE_67DEGb = 26;
Phaser.Physics.Ninja.Tile.TYPE_HALF = 30;
+449
View File
@@ -0,0 +1,449 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2014 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* Ninja Physics constructor.
*
* @class Phaser.Physics.Ninja
* @classdesc Arcade Physics Constructor
* @constructor
* @param {Phaser.Game} game reference to the current game instance.
*/
Phaser.Physics.Ninja = function (game) {
/**
* @property {Phaser.Game} game - Local reference to game.
*/
this.game = game;
this.time = this.game.time;
/**
* @property {number} gravity - The World gravity setting.
*/
this.gravity = 0.2;
/**
* @property {Phaser.Rectangle} bounds - The bounds inside of which the physics world exists. Defaults to match the world bounds.
*/
this.bounds = new Phaser.Rectangle(0, 0, game.world.width, game.world.height);
/**
* @property {Phaser.QuadTree} quadTree - The world QuadTree.
*/
// this.quadTree = new Phaser.Physics.Ninja.QuadTree(this, this.game.world.bounds.x, this.game.world.bounds.y, this.game.world.bounds.width, this.game.world.bounds.height, this.maxObjects, this.maxLevels);
/**
* @property {Array} _mapData - Internal cache var.
* @private
*/
this._mapData = [];
};
Phaser.Physics.Ninja.prototype.constructor = Phaser.Physics.Ninja;
Phaser.Physics.Ninja.prototype = {
/**
* This will create a Ninja Physics AABB body on the given game object. Its dimensions will match the width and height of the object at the point it is created.
* A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
*
* @method Phaser.Physics.Ninja#enableAABB
* @param {object|array} object - The game object to create the physics body on. Can also be an array of objects, a body will be created on every object in the array.
*/
enableAABB: function (object) {
this.enable(object, 1);
},
/**
* This will create a Ninja Physics Circle body on the given game object.
* A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
*
* @method Phaser.Physics.Ninja#enableCircle
* @param {object|array} object - The game object to create the physics body on. Can also be an array of objects, a body will be created on every object in the array.
* @param {number} radius - The radius of the Circle.
*/
enableCircle: function (object, radius) {
this.enable(object, 2, 0, radius);
},
/**
* This will create a Ninja Physics Tile body on the given game object. There are 34 different types of tile you can create, including 45 degree slopes,
* convex and concave circles and more. The id parameter controls which Tile type is created, but you can also change it at run-time.
* Note that for all degree based tile types they need to have an equal width and height. If the given object doesn't have equal width and height it will use the width.
* A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
*
* @method Phaser.Physics.Ninja#enableTile
* @param {object|array} object - The game object to create the physics body on. Can also be an array of objects, a body will be created on every object in the array.
* @param {number} radius - The radius of the Circle.
*/
enableTile: function (object, id) {
this.enable(object, 3, id);
},
/**
* This will create a Ninja Physics Tile body on the given game object. There are 34 different types of tile you can create, including 45 degree slopes,
* convex and concave circles and more. The id parameter controls which Tile type is created, but you can also change it at run-time.
* Note that for all degree based tile types they need to have an equal width and height. If the given object doesn't have equal width and height it will use the width.
* A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
*
* @method Phaser.Physics.Ninja#enable
* @param {object|array} object - The game object to create the physics body on. Can also be an array of objects, a body will be created on every object in the array.
* @param {number} [type=1] - The type of Ninja shape to create. 1 = AABB, 2 = Circle or 3 = Tile.
* @param {number} [id=1] - If this body is using a Tile shape, you can set the Tile id here, i.e. Phaser.Physics.Ninja.Tile.SLOPE_45DEGpn, Phaser.Physics.Ninja.Tile.CONVEXpp, etc.
* @param {number} [radius=0] - If this body is using a Circle shape this controls the radius.
*/
enable: function (object, type, id, radius) {
if (typeof type === 'undefined') { type = 1; }
if (typeof id === 'undefined') { id = 1; }
var i = 1;
if (Array.isArray(object))
{
// Add to Group
i = object.length;
}
else
{
object = [object];
}
while (i--)
{
if (object[i].body === null)
{
object[i].body = new Phaser.Physics.Ninja.Body(this, object[i], type, id);
object[i].anchor.set(0.5);
}
}
},
/**
* Called automatically by a Physics body, it updates all motion related values on the Body.
*
* @method Phaser.Physics.Ninja#updateMotion
* @param {Phaser.Physics.Ninja.Body} The Body object to be updated.
*/
update: function () {
},
/**
* Checks for overlaps between two game objects. The objects can be Sprites, Groups or Emitters.
* You can perform Sprite vs. Sprite, Sprite vs. Group and Group vs. Group overlap checks.
* Unlike collide the objects are NOT automatically separated or have any physics applied, they merely test for overlap results.
* The second parameter can be an array of objects, of differing types.
*
* @method Phaser.Physics.Arcade#overlap
* @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter} object1 - The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter.
* @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|array} object2 - The second object or array of objects to check. Can be Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter.
* @param {function} [overlapCallback=null] - An optional 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 specified them.
* @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then overlapCallback will only be called if processCallback returns true.
* @param {object} [callbackContext] - The context in which to run the callbacks.
* @returns {boolean} True if an overlap occured otherwise false.
*/
overlap: function (object1, object2, overlapCallback, processCallback, callbackContext) {
overlapCallback = overlapCallback || null;
processCallback = processCallback || null;
callbackContext = callbackContext || overlapCallback;
this._result = false;
this._total = 0;
if (Array.isArray(object2))
{
for (var i = 0, len = object2.length; i < len; i++)
{
this.collideHandler(object1, object2[i], overlapCallback, processCallback, callbackContext, true);
}
}
else
{
this.collideHandler(object1, object2, overlapCallback, processCallback, callbackContext, true);
}
return (this._total > 0);
},
/**
* Checks for collision between two game objects. You can perform Sprite vs. Sprite, Sprite vs. Group, Group vs. Group, Sprite vs. Tilemap Layer or Group vs. Tilemap Layer collisions.
* The second parameter can be an array of objects, of differing types.
* The objects are also automatically separated. If you don't require separation then use ArcadePhysics.overlap instead.
* An optional processCallback can be provided. If given this function will be called when two sprites are found to be colliding. It is called before any separation takes place,
* giving you the chance to perform additional checks. If the function returns true then the collision and separation is carried out. If it returns false it is skipped.
* The collideCallback is an optional function that is only called if two sprites collide. If a processCallback has been set then it needs to return true for collideCallback to be called.
*
* @method Phaser.Physics.Ninja#collide
* @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.Tilemap} object1 - The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter, or Phaser.Tilemap.
* @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.Tilemap|array} object2 - The second object or array of objects to check. Can be Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.Tilemap.
* @param {function} [collideCallback=null] - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
* @param {function} [processCallback=null] - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
* @param {object} [callbackContext] - The context in which to run the callbacks.
* @returns {boolean} True if a collision occured otherwise false.
*/
collide: function (object1, object2, collideCallback, processCallback, callbackContext) {
collideCallback = collideCallback || null;
processCallback = processCallback || null;
callbackContext = callbackContext || collideCallback;
this._result = false;
this._total = 0;
if (Array.isArray(object2))
{
for (var i = 0, len = object2.length; i < len; i++)
{
this.collideHandler(object1, object2[i], collideCallback, processCallback, callbackContext, false);
}
}
else
{
this.collideHandler(object1, object2, collideCallback, processCallback, callbackContext, false);
}
return (this._total > 0);
},
/**
* Internal collision handler.
*
* @method Phaser.Physics.Arcade#collideHandler
* @private
* @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.Tilemap} object1 - The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter, or Phaser.Tilemap.
* @param {Phaser.Sprite|Phaser.Group|Phaser.Particles.Emitter|Phaser.Tilemap} object2 - The second object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.Tilemap. Can also be an array of objects to check.
* @param {function} collideCallback - An optional callback function that is called if the objects collide. The two objects will be passed to this function in the same order in which you specified them.
* @param {function} processCallback - A callback function that lets you perform additional checks against the two objects if they overlap. If this is set then collision will only happen if processCallback returns true. The two objects will be passed to this function in the same order in which you specified them.
* @param {object} callbackContext - The context in which to run the callbacks.
* @param {boolean} overlapOnly - Just run an overlap or a full collision.
*/
collideHandler: function (object1, object2, collideCallback, processCallback, callbackContext, overlapOnly) {
// Only collide valid objects
if (typeof object2 === 'undefined' && (object1.type === Phaser.GROUP || object1.type === Phaser.EMITTER))
{
this.collideGroupVsSelf(object1, collideCallback, processCallback, callbackContext, overlapOnly);
return;
}
if (object1 && object2 && object1.exists && object2.exists)
{
// SPRITES
if (object1.type == Phaser.SPRITE || object1.type == Phaser.TILESPRITE)
{
if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE)
{
this.collideSpriteVsSprite(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
}
else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER)
{
this.collideSpriteVsGroup(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
}
else if (object2.type == Phaser.TILEMAPLAYER)
{
this.collideSpriteVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext);
}
}
// GROUPS
else if (object1.type == Phaser.GROUP)
{
if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE)
{
this.collideSpriteVsGroup(object2, object1, collideCallback, processCallback, callbackContext, overlapOnly);
}
else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER)
{
this.collideGroupVsGroup(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
}
else if (object2.type == Phaser.TILEMAPLAYER)
{
this.collideGroupVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext);
}
}
// TILEMAP LAYERS
else if (object1.type == Phaser.TILEMAPLAYER)
{
if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE)
{
this.collideSpriteVsTilemapLayer(object2, object1, collideCallback, processCallback, callbackContext);
}
else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER)
{
this.collideGroupVsTilemapLayer(object2, object1, collideCallback, processCallback, callbackContext);
}
}
// EMITTER
else if (object1.type == Phaser.EMITTER)
{
if (object2.type == Phaser.SPRITE || object2.type == Phaser.TILESPRITE)
{
this.collideSpriteVsGroup(object2, object1, collideCallback, processCallback, callbackContext, overlapOnly);
}
else if (object2.type == Phaser.GROUP || object2.type == Phaser.EMITTER)
{
this.collideGroupVsGroup(object1, object2, collideCallback, processCallback, callbackContext, overlapOnly);
}
else if (object2.type == Phaser.TILEMAPLAYER)
{
this.collideGroupVsTilemapLayer(object1, object2, collideCallback, processCallback, callbackContext);
}
}
}
},
/**
* An internal function. Use Phaser.Physics.Arcade.collide instead.
*
* @method Phaser.Physics.Arcade#collideSpriteVsSprite
* @private
*/
collideSpriteVsSprite: function (sprite1, sprite2, collideCallback, processCallback, callbackContext, overlapOnly) {
if (this.separate(sprite1.body, sprite2.body, processCallback, callbackContext, overlapOnly))
{
if (collideCallback)
{
collideCallback.call(callbackContext, sprite1, sprite2);
}
this._total++;
}
},
/**
* An internal function. Use Phaser.Physics.Arcade.collide instead.
*
* @method Phaser.Physics.Arcade#collideSpriteVsGroup
* @private
*/
collideSpriteVsGroup: function (sprite, group, collideCallback, processCallback, callbackContext, overlapOnly) {
if (group.length === 0)
{
return;
}
// What is the sprite colliding with in the quadtree?
// this.quadTree.clear();
// 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.quadTree.populate(group);
// this._potentials = this.quadTree.retrieve(sprite);
for (var i = 0, len = group.children.length; i < len; i++)
{
// We have our potential suspects, are they in this group?
if (group.children[i].exists && group.children[i].body && this.separate(sprite.body, group.children[i].body, processCallback, callbackContext, overlapOnly))
{
if (collideCallback)
{
collideCallback.call(callbackContext, sprite, group.children[i]);
}
this._total++;
}
}
},
/**
* An internal function. Use Phaser.Physics.Arcade.collide instead.
*
* @method Phaser.Physics.Arcade#collideGroupVsSelf
* @private
*/
collideGroupVsSelf: function (group, collideCallback, processCallback, callbackContext, overlapOnly) {
if (group.length === 0)
{
return;
}
var len = group.children.length;
for (var i = 0; i < len; i++)
{
for (var j = i + 1; j <= len; j++)
{
if (group.children[i] && group.children[j] && group.children[i].exists && group.children[j].exists)
{
this.collideSpriteVsSprite(group.children[i], group.children[j], collideCallback, processCallback, callbackContext, overlapOnly);
}
}
}
},
/**
* An internal function. Use Phaser.Physics.Arcade.collide instead.
*
* @method Phaser.Physics.Arcade#collideGroupVsGroup
* @private
*/
collideGroupVsGroup: function (group1, group2, collideCallback, processCallback, callbackContext, overlapOnly) {
if (group1.length === 0 || group2.length === 0)
{
return;
}
for (var i = 0, len = group1.children.length; i < len; i++)
{
if (group1.children[i].exists)
{
this.collideSpriteVsGroup(group1.children[i], group2, collideCallback, processCallback, callbackContext, overlapOnly);
}
}
},
/**
* The core separation function to separate two physics bodies.
* @method Phaser.Physics.Arcade#separate
* @param {Phaser.Physics.Arcade.Body} body1 - The Body object to separate.
* @param {Phaser.Physics.Arcade.Body} body2 - The Body object to separate.
* @param {function} [processCallback=null] - UN-USED: A callback function that lets you perform additional checks against the two objects if they overlap. If this function is set then the sprites will only be collided if it returns true.
* @param {object} [callbackContext] - UN-USED: The context in which to run the process callback.
* @returns {boolean} Returns true if the bodies collided, otherwise false.
*/
separate: function (body1, body2, processCallback, callbackContext, overlapOnly) {
if (body1.type !== Phaser.Physics.NINJA || body2.type !== Phaser.Physics.NINJA)
{
return;
}
if (body1.aabb && body2.tile)
{
return body1.aabb.collideAABBVsTile(body2.tile);
}
if (body1.tile && body2.aabb)
{
return body2.aabb.collideAABBVsTile(body1.tile);
}
// circles next
}
};
+5
View File
@@ -37,6 +37,11 @@ Phaser.Physics.Body = function (game, sprite, x, y, mass) {
*/
this.sprite = sprite;
/**
* @property {number} type - The type of physics system this body belongs to.
*/
this.type = Phaser.Physics.P2;
/**
* @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
*/
+46
View File
@@ -39,6 +39,16 @@ Phaser.Tile = function (layer, index, x, y, width, height) {
*/
this.y = y;
/**
* @property {number} x - The x map coordinate of this tile.
*/
this.worldX = x * width;
/**
* @property {number} y - The y map coordinate of this tile.
*/
this.worldY = y * height;
/**
* @property {number} width - The width of the tile in pixels.
*/
@@ -49,6 +59,16 @@ Phaser.Tile = function (layer, index, x, y, width, height) {
*/
this.height = height;
/**
* @property {number} width - The width of the tile in pixels.
*/
this.centerX = Math.abs(width / 2);
/**
* @property {number} height - The height of the tile in pixels.
*/
this.centerY = Math.abs(height / 2);
/**
* @property {number} alpha - The alpha value at which this tile is drawn to the canvas.
*/
@@ -135,6 +155,32 @@ Phaser.Tile = function (layer, index, x, y, width, height) {
Phaser.Tile.prototype = {
intersects: function (x, y, right, bottom) {
if (right <= this.worldX)
{
return false;
}
if (bottom <= this.worldY)
{
return false;
}
if (x >= this.worldX + this.width)
{
return false;
}
if (y >= this.worldY + this.height)
{
return false;
}
return true;
},
/**
* Set a callback to be called when this tile is hit by an object.
* The callback must true true for collision processing to take place.
+97 -1
View File
@@ -454,6 +454,93 @@ Phaser.TilemapLayer.prototype.getTileXY = function (x, y, point) {
}
Phaser.TilemapLayer.prototype.getIntersectingTiles = function (x, y, width, height) {
// var tiles = this.getTiles(x, y, width,height, true);
var tiles = this.getTiles(x, y, width,height, false);
var right = x + width;
var bottom = y + height;
// We only want the ones that we actually intersect with
var i = tiles.length;
while (i--)
{
if (tiles[i].intersects(x, y, right, bottom))
{
// tiles[i].debug = true;
}
else
{
// console.log('sliced off tile', i);
// tiles.pop();
}
}
return tiles;
}
/*
Phaser.TilemapLayer.prototype.getTilesX = function (x, y, width, height, collides) {
// Should we only get tiles that have at least one of their collision flags set? (true = yes, false = no just get them all)
if (typeof collides === 'undefined') { collides = false; }
// adjust the x,y coordinates for scrollFactor
x = this._fixX(x);
y = this._fixY(y);
if (width > this.layer.widthInPixels)
{
width = this.layer.widthInPixels;
}
if (height > this.layer.heightInPixels)
{
height = this.layer.heightInPixels;
}
// Convert the pixel values into tile coordinates
// this._tx = this.game.math.snapToFloor(x, this._cw) / this._cw;
// this._ty = this.game.math.snapToFloor(y, this._ch) / this._ch;
// this._tw = (this.game.math.snapToCeil(width, this._cw) + this._cw) / this._cw;
// this._th = (this.game.math.snapToCeil(height, this._ch) + this._ch) / this._ch;
// var firstTileX = Math.max( Math.floor(res.pos.x / this.tilesize), 0 );
// var lastTileX = Math.min( Math.ceil((res.pos.x + width) / this.tilesize), this.width );
// var tileY = Math.floor( (res.pos.y + pxOffsetY) / this.tilesize );
this._tx = Math.max(Math.floor(x / this.tileWidth), 0);
this._tw = Math.min(Math.ceil((x + width) / this.tileWidth), this.width);
this._ty = Math.floor((y + px) / this.tileHeight);
this._results.length = 0;
for (var wy = this._ty; wy < this._ty + this._th; wy++)
{
for (var wx = this._tx; wx < this._tx + this._tw; wx++)
{
if (this.layer.data[wy] && this.layer.data[wy][wx])
{
if (collides === false || (collides && this.layer.data[wy][wx].canCollide))
{
this._results.push(this.layer.data[wy][wx]);
}
}
}
}
// DEBUG ONLY - REMOVE
this.layer.dirty = true;
return this._results;
}
*/
/**
* Get all tiles that exist within the given area, defined by the top-left corner, width and height. Values given are in pixels, not tiles.
* @method Phaser.TilemapLayer#getTiles
@@ -491,7 +578,8 @@ Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides
this._th = (this.game.math.snapToCeil(height, this._ch) + this._ch) / this._ch;
// This should apply the layer x/y here
this._results.length = 0;
// this._results.length = 0;
this._results = [];
for (var wy = this._ty; wy < this._ty + this._th; wy++)
{
@@ -501,6 +589,7 @@ Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides
{
if (collides === false || (collides && this.layer.data[wy][wx].canCollide))
{
/*
// Convert tile coordinates back to camera space for return
var _wx = this._unfixX(wx * this._cw) / this._cw;
var _wy = this._unfixY(wy * this._ch) / this._ch;
@@ -513,11 +602,18 @@ Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides
tile: this.layer.data[wy][wx],
layer: this.layer.data[wy][wx].layer
});
*/
this._results.push(this.layer.data[wy][wx]);
}
}
}
}
// DEBUG ONLY - REMOVE
this.layer.dirty = true;
return this._results;
}
+1 -2
View File
@@ -227,6 +227,7 @@ Phaser.Time.prototype = {
this.timeToCall = this.game.math.max(0, 16 - (time - this.lastTime));
this.elapsed = this.now - this.time;
this.physicsElapsed = this.elapsed / 1000;
if (this.advancedTiming)
{
@@ -248,8 +249,6 @@ Phaser.Time.prototype = {
this.time = this.now;
this.lastTime = time + this.timeToCall;
this.physicsElapsed = 1.0 * (this.elapsed / 1000);
// Paused but still running?
if (!this.game.paused)
{
+14 -12
View File
@@ -518,33 +518,35 @@ Phaser.Utils.Debug.prototype = {
* @param {Phaser.Rectangle|Phaser.Circle|Phaser.Point|Phaser.Line} object - The geometry object to render.
* @param {string} [color] - Color of the debug info to be rendered (format is css color string).
* @param {boolean} [filled=true] - Render the objected as a filled (default, true) or a stroked (false)
* @param {number} [forceType=0] - Force rendering of a specific type. If 0 no type will be forced, otherwise 1 = Rectangle, 2 = Circle, 3 = Point and 4 = Line.
*/
geom: function (object, color, filled) {
geom: function (object, color, filled, forceType) {
if (typeof filled === 'undefined') { filled = true; }
if (typeof forceType === 'undefined') { forceType = 0; }
color = color || 'rgba(0,255,0,0.3)';
color = color || 'rgba(0,255,0,0.4)';
this.start();
this.context.fillStyle = color;
this.context.strokeStyle = color;
if (object instanceof Phaser.Rectangle)
if (object instanceof Phaser.Rectangle || forceType === 1)
{
if (filled)
{
this.context.fillRect(object.x, object.y, object.width, object.height);
this.context.fillRect(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width, object.height);
}
else
{
this.context.strokeRect(object.x, object.y, object.width, object.height);
this.context.strokeRect(object.x - this.game.camera.x, object.y - this.game.camera.y, object.width, object.height);
}
}
else if (object instanceof Phaser.Circle)
else if (object instanceof Phaser.Circle || forceType === 2)
{
this.context.beginPath();
this.context.arc(object.x, object.y, object.radius, 0, Math.PI * 2, false);
this.context.arc(object.x - this.game.camera.x, object.y - this.game.camera.y, object.radius, 0, Math.PI * 2, false);
this.context.closePath();
if (filled)
@@ -556,16 +558,16 @@ Phaser.Utils.Debug.prototype = {
this.context.stroke();
}
}
else if (object instanceof Phaser.Point)
else if (object instanceof Phaser.Point || forceType === 3)
{
this.context.fillRect(object.x, object.y, 4, 4);
this.context.fillRect(object.x - this.game.camera.x, object.y - this.game.camera.y, 4, 4);
}
else if (object instanceof Phaser.Line)
else if (object instanceof Phaser.Line || forceType === 4)
{
this.context.lineWidth = 1;
this.context.beginPath();
this.context.moveTo(object.start.x + 0.5, object.start.y + 0.5);
this.context.lineTo(object.end.x + 0.5, object.end.y + 0.5);
this.context.moveTo((object.start.x + 0.5) - this.game.camera.x, (object.start.y + 0.5) - this.game.camera.y);
this.context.lineTo((object.end.x + 0.5) - this.game.camera.x, (object.end.y + 0.5) - this.game.camera.y);
this.context.closePath();
this.context.stroke();
}