Source: physics/Body.js

/**
 * @class Phaser.Plugin.Isometric.Body
 *
 * @classdesc
 * The Physics Body is linked to a single IsoSprite. All physics operations should be performed against the body rather than
 * the IsoSprite itself. For example you can set the velocity, acceleration, bounce values etc all on the Body.
 *
 * @constructor
 * @param {Phaser.Plugin.Isometric.IsoSprite} sprite - The IsoSprite object this physics body belongs to.
 */
Phaser.Plugin.Isometric.Body = function (sprite) {

    /**
     * @property {Phaser.Plugin.Isometric.IsoSprite} sprite - Reference to the parent IsoSprite.
     */
    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.Plugin.Isometric.ISOARCADE;

    /**
     * @property {boolean} enable - A disabled body won't be checked for any form of collision or overlap or have its pre/post updates run.
     * @default
     */
    this.enable = true;

    /**
     * @property {Phaser.Point} offset - The offset of the Physics Body from the IsoSprite x/y/z position.
     */
    this.offset = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} position - The position of the physics body.
     * @readonly
     */
    this.position = new Phaser.Plugin.Isometric.Point3(sprite.isoX, sprite.isoY, sprite.isoZ);

    /**
     * @property {Phaser.Point} prev - The previous position of the physics body.
     * @readonly
     */
    this.prev = new Phaser.Plugin.Isometric.Point3(this.position.x, this.position.y, this.position.z);

    /**
     * @property {boolean} allowRotation - Allow this Body to be rotated? (via angularVelocity, etc)
     * @default
     */
    this.allowRotation = true;

    /**
     * @property {number} rotation - The amount the Body is rotated.
     */
    this.rotation = sprite.rotation;

    /**
     * @property {number} preRotation - The previous rotation of the physics body.
     * @readonly
     */
    this.preRotation = sprite.rotation;

    /**
     * @property {number} sourceWidthX - The un-scaled original size.
     * @readonly
     */
    this.sourceWidthX = sprite.texture.frame.width;

    /**
     * @property {number} sourceWidthY - The un-scaled original size.
     * @readonly
     */
    this.sourceWidthY = sprite.texture.frame.width;

    /**
     * @property {number} sourceHeight - The un-scaled original size.
     * @readonly
     */
    this.sourceHeight = sprite.texture.frame.height;

    /**
     * @property {number} widthX - The calculated X width (breadth) of the physics body.
     */
    this.widthX = Math.ceil(sprite.width * 0.5);

    /**
     * @property {number} widthY - The calculated Y width (depth) of the physics body.
     */
    this.widthY = Math.ceil(sprite.width * 0.5);

    /**
     * @property {number} height - The calculated height of the physics body.
     */
    this.height = sprite.height - Math.ceil(sprite.width * 0.5);

    /**
     * @property {number} halfWidthX - The calculated X width / 2 of the physics body.
     */
    this.halfWidthX = Math.abs(this.widthX * 0.5);

    /**
     * @property {number} halfWidthX - The calculated X width / 2 of the physics body.
     */
    this.halfWidthY = Math.abs(this.widthY * 0.5);

    /**
     * @property {number} halfHeight - The calculated height / 2 of the physics body.
     */
    this.halfHeight = Math.abs(this.height * 0.5);

    /**
     * @property {Phaser.Plugin.Isometric.Point3} center - The center coordinate of the physics body.
     */
    this.center = new Phaser.Plugin.Isometric.Point3(sprite.isoX + this.halfWidthX, sprite.isoY + this.halfWidthY, sprite.isoZ + this.halfHeight);

    /**
     * @property {Phaser.Plugin.Isometric.Point3} velocity - The velocity in pixels per second sq. of the Body.
     */
    this.velocity = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} newVelocity - New velocity.
     * @readonly
     */
    this.newVelocity = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} deltaMax - The Sprite position is updated based on the delta x/y values. You can set a cap on those (both +-) using deltaMax.
     */
    this.deltaMax = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} acceleration - The velocity in pixels per second sq. of the Body.
     */
    this.acceleration = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} drag - The drag applied to the motion of the Body.
     */
    this.drag = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {boolean} allowGravity - Allow this Body to be influenced by gravity? Either world or local.
     * @default
     */
    this.allowGravity = true;

    /**
     * @property {Phaser.Plugin.Isometric.Point3} gravity - A local gravity applied to this Body. If non-zero this over rides any world gravity, unless Body.allowGravity is set to false.
     */
    this.gravity = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} bounce - The elasticitiy of the Body when colliding. bounce.x/y/z = 1 means full rebound, bounce.x/y/z = 0.5 means 50% rebound velocity.
     */
    this.bounce = new Phaser.Plugin.Isometric.Point3();

    /**
     * @property {Phaser.Plugin.Isometric.Point3} maxVelocity - The maximum velocity in pixels per second sq. that the Body can reach.
     * @default
     */
    this.maxVelocity = new Phaser.Plugin.Isometric.Point3(10000, 10000, 10000);

    /**
     * @property {number} angularVelocity - The angular velocity in pixels per second sq. of the Body.
     * @default
     */
    this.angularVelocity = 0;

    /**
     * @property {number} angularAcceleration - The angular acceleration in pixels per second sq. of the Body.
     * @default
     */
    this.angularAcceleration = 0;

    /**
     * @property {number} angularDrag - The angular drag applied to the rotation of the Body.
     * @default
     */
    this.angularDrag = 0;

    /**
     * @property {number} maxAngular - The maximum angular velocity in pixels per second sq. that the Body can reach.
     * @default
     */
    this.maxAngular = 1000;

    /**
     * @property {number} mass - The mass of the Body.
     * @default
     */
    this.mass = 1;

    /**
     * @property {number} angle - The angle of the Body in radians as calculated by its velocity, rather than its visual angle.
     * @readonly
     */
    this.angle = 0;

    /**
     * @property {number} speed - The speed of the Body as calculated by its velocity.
     * @readonly
     */
    this.speed = 0;

    /**
     * @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;

    /**
     * If you have a Body that is being moved around the world via a tween or a Group motion, but its local x/y position never
     * actually changes, then you should set Body.moves = false. Otherwise it will most likely fly off the screen.
     * If you want the physics system to move the body around, then set moves to true.
     * @property {boolean} moves - Set to true to allow the Physics system to move this Body, other false to move it manually.
     * @default
     */
    this.moves = true;

    /**
     * This flag allows you to disable the custom x separation that takes place by Physics.IsoArcade.separate.
     * Used in combination with your own collision processHandler you can create whatever type of collision response you need.
     * @property {boolean} customSeparateX - Use a custom separation system or the built-in one?
     * @default
     */
    this.customSeparateX = false;

    /**
     * This flag allows you to disable the custom y separation that takes place by Physics.IsoArcade.separate.
     * Used in combination with your own collision processHandler you can create whatever type of collision response you need.
     * @property {boolean} customSeparateY - Use a custom separation system or the built-in one?
     * @default
     */
    this.customSeparateY = false;

    /**
     * This flag allows you to disable the custom z separation that takes place by Physics.IsoArcade.separate.
     * Used in combination with your own collision processHandler you can create whatever type of collision response you need.
     * @property {boolean} customSeparateZ - Use a custom separation system or the built-in one?
     * @default
     */
    this.customSeparateZ = false;

    /**
     * When this body collides with another, the amount of overlap is stored here.
     * @property {number} overlapX - The amount of horizontal overlap during the collision.
     */
    this.overlapX = 0;

    /**
     * When this body collides with another, the amount of overlap is stored here.
     * @property {number} overlapY - The amount of vertical overlap during the collision.
     */
    this.overlapY = 0;

    /**
     * When this body collides with another, the amount of overlap is stored here.
     * @property {number} overlapY - The amount of vertical overlap during the collision.
     */
    this.overlapZ = 0;

    /**
     * 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.
     */
    this.embedded = 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 = false;

    /**
     * Set the checkCollision properties to control which directions collision is processed for this Body.
     * For example checkCollision.up = false means it won't collide when the collision happened while moving up.
     * @property {object} checkCollision - An object containing allowed collision.
     */
    this.checkCollision = {
        none: false,
        any: true,
        up: true,
        down: true,
        frontX: true,
        frontY: true,
        backX: true,
        backY: 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,
        frontX: false,
        frontY: false,
        backX: false,
        backY: 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,
        frontX: false,
        frontY: false,
        backX: false,
        backY: 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.blocked = {
        up: false,
        down: false,
        frontX: false,
        frontY: false,
        backX: false,
        backY: false
    };

    /**
     * @property {number} phase - Is this Body in a preUpdate (1) or postUpdate (2) state?
     */
    this.phase = 0;

    /**
     * @property {boolean} skipTree - If true and you collide this IsoSprite against a Group, it will disable the collision check from using a QuadTree/Octree.
     */
    this.skipTree = false;

    /**
     * @property {boolean} _reset - Internal cache var.
     * @private
     */
    this._reset = true;

    /**
     * @property {number} _sx - Internal cache var.
     * @private
     */
    this._sx = sprite.scale.x;

    /**
     * @property {number} _sy - Internal cache var.
     * @private
     */
    this._sy = sprite.scale.y;

    /**
     * @property {number} _dx - Internal cache var.
     * @private
     */
    this._dx = 0;

    /**
     * @property {number} _dy - Internal cache var.
     * @private
     */
    this._dy = 0;

    /**
     * @property {number} _dz - Internal cache var.
     * @private
     */
    this._dz = 0;

    /**
     * @property {Array.<Phaser.Plugin.Isometric.Point3>} _corners - The 8 corners of the bounding cube.
     * @private
     */
    this._corners = [new Phaser.Plugin.Isometric.Point3(this.x, this.y, this.z),
        new Phaser.Plugin.Isometric.Point3(this.x, this.y, this.z + this.height),
        new Phaser.Plugin.Isometric.Point3(this.x, this.y + this.widthY, this.z),
        new Phaser.Plugin.Isometric.Point3(this.x, this.y + this.widthY, this.z + this.height),
        new Phaser.Plugin.Isometric.Point3(this.x + this.widthX, this.y, this.z),
        new Phaser.Plugin.Isometric.Point3(this.x + this.widthX, this.y, this.z + this.height),
        new Phaser.Plugin.Isometric.Point3(this.x + this.widthX, this.y + this.widthY, this.z),
        new Phaser.Plugin.Isometric.Point3(this.x + this.widthX, this.y + this.widthY, this.z + this.height)
    ];

};

Phaser.Plugin.Isometric.Body.prototype = {

    /**
     * Internal method.
     *
     * @method Phaser.Plugin.Isometric.Body#updateBounds
     * @protected
     */
    updateBounds: function () {

        var asx = Math.abs(this.sprite.scale.x);
        var asy = Math.abs(this.sprite.scale.y);

        if (asx !== this._sx || asy !== this._sy) {
            this.widthX = Math.ceil(this.sprite.width * 0.5);
            this.widthY = Math.ceil(this.sprite.width * 0.5);
            this.height = Math.ceil(this.sprite.height - (this.sprite.width * 0.5));
            this.halfWidthX = Math.floor(this.widthX * 2);
            this.halfWidthY = Math.floor(this.widthY * 2);
            this.halfHeight = Math.floor(this.height * 2);
            this._sx = asx;
            this._sy = asy;
            this.center.setTo(this.position.x + this.halfWidthX, this.position.y + this.halfWidthY, this.position.z + this.halfHeight);

            this._reset = true;
        }

    },

    /**
     * Internal method.
     *
     * @method Phaser.Plugin.Isometric.Body#preUpdate
     * @protected
     */
    preUpdate: function () {

        if (!this.enable) {
            return;
        }

        this.phase = 1;

        //  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.backX = this.touching.backX;
        this.wasTouching.backY = this.touching.backY;
        this.wasTouching.frontX = this.touching.frontX;
        this.wasTouching.frontY = this.touching.frontY;

        this.touching.none = true;
        this.touching.up = false;
        this.touching.down = false;
        this.touching.backX = false;
        this.touching.backY = false;
        this.touching.frontX = false;
        this.touching.frontY = false;

        this.blocked.up = false;
        this.blocked.down = false;
        this.blocked.backX = false;
        this.blocked.frontX = false;
        this.blocked.backY = false;
        this.blocked.backX = false;

        this.embedded = false;

        this.updateBounds();

        //  Working out how to incorporate anchors into this was... fun.
        this.position.x = this.sprite.isoX + ((this.widthX * -this.sprite.anchor.x) + this.widthX * 0.5) + this.offset.x;
        this.position.y = this.sprite.isoY + ((this.widthY * this.sprite.anchor.x) - this.widthY * 0.5) + this.offset.y;
        this.position.z = this.sprite.isoZ - (Math.abs(this.sprite.height) * (1 - this.sprite.anchor.y)) + (Math.abs(this.sprite.width * 0.5)) + this.offset.z;


        this.rotation = this.sprite.angle;

        this.preRotation = this.rotation;

        if (this._reset || this.sprite.fresh === true) {
            this.prev.x = this.position.x;
            this.prev.y = this.position.y;
            this.prev.z = this.position.z;
        }

        if (this.moves) {
            this.game.physics.isoArcade.updateMotion(this);

            this.newVelocity.set(this.velocity.x * this.game.time.physicsElapsed, this.velocity.y * this.game.time.physicsElapsed, this.velocity.z * this.game.time.physicsElapsed);

            this.position.x += this.newVelocity.x;
            this.position.y += this.newVelocity.y;
            this.position.z += this.newVelocity.z;

            if (this.position.x !== this.prev.x || this.position.y !== this.prev.y || this.position.z !== this.prev.z) {
                this.speed = Math.sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y + this.velocity.z * this.velocity.z);
                this.angle = Math.atan2(this.velocity.y, this.velocity.x);
            }

            //  Now the State update will throw collision checks at the Body
            //  And finally we'll integrate the new position back to the Sprite in postUpdate

            if (this.collideWorldBounds) {
                this.checkWorldBounds();
            }

            if (this.sprite.outOfBoundsKill && !this.game.physics.isoArcade.bounds.intersects(this.sprite.isoBounds)){
                this.sprite.kill();
            }
        }

        this._dx = this.deltaX();
        this._dy = this.deltaY();
        this._dz = this.deltaZ();

        this._reset = false;

    },

    /**
     * Internal method.
     *
     * @method Phaser.Plugin.Isometric.Body#postUpdate
     * @protected
     */
    postUpdate: function () {

        if (!this.enable) {
            return;
        }

        //  Only allow postUpdate to be called once per frame
        if (this.phase === 2) {
            return;
        }

        this.phase = 2;

        // stops sprites flying off if isoPosition is changed during update
        if (this._reset) {
            this.prev.x = this.position.x;
            this.prev.y = this.position.y;
            this.prev.z = this.position.z;
        }

        if (this.deltaAbsX() >= this.deltaAbsY() && this.deltaAbsX() >= this.deltaAbsZ()){
            if (this.deltaX() < 0) {
                this.facing = Phaser.Plugin.Isometric.BACKWARDX;
            } else if (this.deltaX() > 0) {
                this.facing = Phaser.Plugin.Isometric.FORWARDX;
            }
        } else if (this.deltaAbsY() >= this.deltaAbsX() && this.deltaAbsY() >= this.deltaAbsZ()){
            if (this.deltaY() < 0) {
                this.facing = Phaser.Plugin.Isometric.BACKWARDY;
            } else if (this.deltaY() > 0) {
                this.facing = Phaser.Plugin.Isometric.FORWARDY;
            }
        } else {
            if (this.deltaZ() < 0) {
                this.facing = Phaser.Plugin.Isometric.DOWN;
            } else if (this.deltaZ() > 0) {
                this.facing = Phaser.Plugin.Isometric.UP;
            }
        }

        if (this.moves) {
            this._dx = this.deltaX();
            this._dy = this.deltaY();
            this._dz = this.deltaZ();

            if (this.deltaMax.x !== 0 && this._dx !== 0) {
                if (this._dx < 0 && this._dx < -this.deltaMax.x) {
                    this._dx = -this.deltaMax.x;
                } else if (this._dx > 0 && this._dx > this.deltaMax.x) {
                    this._dx = this.deltaMax.x;
                }
            }

            if (this.deltaMax.y !== 0 && this._dy !== 0) {
                if (this._dy < 0 && this._dy < -this.deltaMax.y) {
                    this._dy = -this.deltaMax.y;
                } else if (this._dy > 0 && this._dy > this.deltaMax.y) {
                    this._dy = this.deltaMax.y;
                }
            }

            if (this.deltaMax.z !== 0 && this._dz !== 0) {
                if (this._dz < 0 && this._dz < -this.deltaMax.z) {
                    this._dz = -this.deltaMax.z;
                } else if (this._dz > 0 && this._dz > this.deltaMax.z) {
                    this._dz = this.deltaMax.z;
                }
            }

            this.sprite.isoX += this._dx;
            this.sprite.isoY += this._dy;
            this.sprite.isoZ += this._dz;
        }

        this.center.setTo(this.position.x + this.halfWidthX, this.position.y + this.halfWidthY, this.position.z + this.halfHeight);

        if (this.allowRotation) {
            this.sprite.angle += this.deltaR();
        }

        this.prev.x = this.position.x;
        this.prev.y = this.position.y;
        this.prev.z = this.position.z;

        this._reset = false;

    },

    /**
     * Removes this body's reference to its parent sprite, freeing it up for gc.
     *
     * @method Phaser.Plugin.Isometric.Body#destroy
     */
    destroy: function () {

        this.sprite = null;

    },

    /**
     * Internal method.
     *
     * @method Phaser.Plugin.Isometric.Body#checkWorldBounds
     * @protected
     */
    checkWorldBounds: function () {

        if (this.position.x < this.game.physics.isoArcade.bounds.x && this.game.physics.isoArcade.checkCollision.backX) {
            this.position.x = this.game.physics.isoArcade.bounds.x;
            this.velocity.x *= -this.bounce.x;
            this.blocked.backX = true;
        } else if (this.frontX > this.game.physics.isoArcade.bounds.frontX && this.game.physics.isoArcade.checkCollision.frontX) {
            this.position.x = this.game.physics.isoArcade.bounds.frontX - this.widthX;
            this.velocity.x *= -this.bounce.x;
            this.blocked.frontX = true;
        }

        if (this.position.y < this.game.physics.isoArcade.bounds.y && this.game.physics.isoArcade.checkCollision.backY) {
            this.position.y = this.game.physics.isoArcade.bounds.y;
            this.velocity.y *= -this.bounce.y;
            this.blocked.backY = true;
        } else if (this.frontY > this.game.physics.isoArcade.bounds.frontY && this.game.physics.isoArcade.checkCollision.frontY) {
            this.position.y = this.game.physics.isoArcade.bounds.frontY - this.widthY;
            this.velocity.y *= -this.bounce.y;
            this.blocked.frontY = true;
        }

        if (this.position.z < this.game.physics.isoArcade.bounds.z && this.game.physics.isoArcade.checkCollision.down) {
            this.position.z = this.game.physics.isoArcade.bounds.z;
            this.velocity.z *= -this.bounce.z;
            this.blocked.down = true;
        } else if (this.top > this.game.physics.isoArcade.bounds.top && this.game.physics.isoArcade.checkCollision.up) {
            this.position.z = this.game.physics.isoArcade.bounds.top - this.height;
            this.velocity.z *= -this.bounce.z;
            this.blocked.up = true;
        }

    },

    /**
     * You can modify the size of the physics Body to be any dimension you need.
     * So it could be smaller or larger than the parent Sprite. You can also control the x, y and z offset, which
     * is the position of the Body relative to the center of the Sprite.
     *
     * @method Phaser.Plugin.Isometric.Body#setSize
     * @param {number} widthX - The X width (breadth) of the Body.
     * @param {number} widthY - The Y width (depth) of the Body.
     * @param {number} height - The height of the Body.
     * @param {number} [offsetX] - The X offset of the Body from the Sprite position.
     * @param {number} [offsetY] - The Y offset of the Body from the Sprite position.
     * @param {number} [offsetY] - The Z offset of the Body from the Sprite position.
     */
    setSize: function (widthX, widthY, height, offsetX, offsetY, offsetZ) {

        if (typeof offsetX === 'undefined') {
            offsetX = this.offset.x;
        }
        if (typeof offsetY === 'undefined') {
            offsetY = this.offset.y;
        }
        if (typeof offsetZ === 'undefined') {
            offsetZ = this.offset.z;
        }

        this.sourceWidthX = widthX;
        this.sourceWidthY = widthY;
        this.sourceHeight = height;
        this.widthX = (this.sourceWidthX) * this._sx;
        this.widthY = (this.sourceWidthY) * this._sx;
        this.height = (this.sourceHeight) * this._sy;
        this.halfWidthX = Math.floor(this.widthX * 0.5);
        this.halfWidthY = Math.floor(this.widthY * 0.5);
        this.halfHeight = Math.floor(this.height * 0.5);
        this.offset.setTo(offsetX, offsetY, offsetZ);

        this.center.setTo(this.position.x + this.halfWidthX, this.position.y + this.halfWidthY, this.position.z + this.halfHeight);

    },

    /**
     * Resets all Body values (velocity, acceleration, rotation, etc)
     *
     * @method Phaser.Plugin.Isometric.Body#reset
     * @param {number} x - The new x position of the Body.
     * @param {number} y - The new y position of the Body.
     * @param {number} z - The new z position of the Body.
     */
    reset: function (x, y, z) {

        this.velocity.set(0);
        this.acceleration.set(0);

        this.angularVelocity = 0;
        this.angularAcceleration = 0;

        this.position.x = x + ((this.widthX * -this.sprite.anchor.x) + this.widthX * 0.5) + this.offset.x;
        this.position.y = y + ((this.widthY * this.sprite.anchor.x) - this.widthY * 0.5) + this.offset.y;
        this.position.z = z - (Math.abs(this.sprite.height) * (1 - this.sprite.anchor.y)) + (Math.abs(this.sprite.width * 0.5)) + this.offset.z;

        this.prev.x = this.position.x;
        this.prev.y = this.position.y;
        this.prev.z = this.position.z;

        this.rotation = this.sprite.angle;
        this.preRotation = this.rotation;

        this._sx = this.sprite.scale.x;
        this._sy = this.sprite.scale.y;

        this.center.setTo(this.position.x + this.halfWidthX, this.position.y + this.halfWidthY, this.position.z + this.halfHeight);

        this.sprite._isoPositionChanged = true;

    },

    /**
     * Tests if a world point lies within this Body.
     *
     * @method Phaser.Plugin.Isometric.Body#hitTest
     * @param {number} x - The world x coordinate to test.
     * @param {number} y - The world y coordinate to test.
     * @param {number} z - The world z coordinate to test.
     * @return {boolean} True if the given coordinates are inside this Body, otherwise false.
     */
    hitTest: function (x, y, z) {

        return Phaser.Plugin.Isometric.Cube.contains(this, x, y, z);

    },

    /**
     * Returns true if the bottom of this Body is in contact with either the world bounds.
     *
     * @method Phaser.Plugin.Isometric.Body#onFloor
     * @return {boolean} True if in contact with either the world bounds.
     */
    onFloor: function () {

        return this.blocked.down;

    },

    /**
     * Returns true if either side of this Body is in contact with either the world bounds.
     *
     * @method Phaser.Plugin.Isometric.Body#onWall
     * @return {boolean} True if in contact with world bounds.
     */
    onWall: function () {

        return (this.blocked.frontX || this.blocked.frontY || this.blocked.backX || this.blocked.backY);

    },

    /**
     * Returns the absolute delta x value.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaAbsX
     * @return {number} The absolute delta value.
     */
    deltaAbsX: function () {

        return (this.deltaX() > 0 ? this.deltaX() : -this.deltaX());

    },

    /**
     * Returns the absolute delta y value.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaAbsY
     * @return {number} The absolute delta value.
     */
    deltaAbsY: function () {

        return (this.deltaY() > 0 ? this.deltaY() : -this.deltaY());

    },

    /**
     * Returns the absolute delta z value.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaAbsZ
     * @return {number} The absolute delta value.
     */
    deltaAbsZ: function () {

        return (this.deltaZ() > 0 ? this.deltaZ() : -this.deltaZ());

    },

    /**
     * Returns the delta x value. The difference between Body.x now and in the previous step.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaX
     * @return {number} The delta value. Positive if the motion was to the right, negative if to the left.
     */
    deltaX: function () {

        return this.position.x - this.prev.x;

    },

    /**
     * Returns the delta y value. The difference between Body.y now and in the previous step.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaY
     * @return {number} The delta value. Positive if the motion was downwards, negative if upwards.
     */
    deltaY: function () {

        return this.position.y - this.prev.y;

    },

    /**
     * Returns the delta z value. The difference between Body.z now and in the previous step.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaZ
     * @return {number} The delta value. Positive if the motion was downwards, negative if upwards.
     */
    deltaZ: function () {

        return this.position.z - this.prev.z;

    },

    /**
     * Returns the delta r value. The difference between Body.rotation now and in the previous step.
     *
     * @method Phaser.Plugin.Isometric.Body#deltaR
     * @return {number} The delta value. Positive if the motion was clockwise, negative if anti-clockwise.
     */
    deltaR: function () {

        return this.rotation - this.preRotation;

    },

    /**
     * Returns the 8 corners that make up the body's bounding cube.
     *
     * @method Phaser.Plugin.Isometric.Body#getCorners
     * @return {Array.<Phaser.Plugin.Isometric.Point3>} An array of Phaser.Plugin.Isometric.Point3 values specifying each corner co-ordinate.
     */
    getCorners: function () {

        this._corners[0].setTo(this.x, this.y, this.z);
        this._corners[1].setTo(this.x, this.y, this.z + this.height);
        this._corners[2].setTo(this.x, this.y + this.widthY, this.z);
        this._corners[3].setTo(this.x, this.y + this.widthY, this.z + this.height);
        this._corners[4].setTo(this.x + this.widthX, this.y, this.z);
        this._corners[5].setTo(this.x + this.widthX, this.y, this.z + this.height);
        this._corners[6].setTo(this.x + this.widthX, this.y + this.widthY, this.z);
        this._corners[7].setTo(this.x + this.widthX, this.y + this.widthY, this.z + this.height);

        return this._corners;

    }
};

/**
 * @name Phaser.Plugin.Isometric.Body#top
 * @property {number} bottom - The top value of this Body (same as Body.z + Body.height)
 * @readonly
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "top", {

    get: function () {
        return this.position.z + this.height;
    }

});

/**
 * @name Phaser.Plugin.Isometric.Body#frontX
 * @property {number} right - The front X value of this Body (same as Body.x + Body.widthX)
 * @readonly
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "frontX", {

    get: function () {
        return this.position.x + this.widthX;
    }

});

/**
 * @name Phaser.Plugin.Isometric.Body#right
 * @property {number} right - The front X value of this Body (same as Body.x + Body.widthX) - alias used for QuadTree
 * @readonly
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "right", {

    get: function () {
        return this.position.x + this.widthX;
    }

});

/**
 * @name Phaser.Plugin.Isometric.Body#frontY
 * @property {number} right - The front Y value of this Body (same as Body.y + Body.widthY)
 * @readonly
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "frontY", {

    get: function () {
        return this.position.y + this.widthY;
    }

});

/**
 * @name Phaser.Plugin.Isometric.Body#bottom
 * @property {number} right - The front Y value of this Body (same as Body.y + Body.widthY) - alias used for QuadTree
 * @readonly
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "bottom", {

    get: function () {
        return this.position.y + this.widthY;
    }

});


/**
 * @name Phaser.Plugin.Isometric.Body#x
 * @property {number} x - The x position.
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "x", {

    get: function () {
        return this.position.x;
    },

    set: function (value) {

        this.position.x = value;
    }

});

/**
 * @name Phaser.Plugin.Isometric.Body#y
 * @property {number} y - The y position.
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "y", {

    get: function () {
        return this.position.y;
    },

    set: function (value) {

        this.position.y = value;

    }

});

/**
 * @name Phaser.Plugin.Isometric.Body#z
 * @property {number} z - The z position.
 */
Object.defineProperty(Phaser.Plugin.Isometric.Body.prototype, "z", {

    get: function () {
        return this.position.z;
    },

    set: function (value) {

        this.position.z = value;

    }

});

/**
 * Render IsoSprite Body.
 *
 * @method Phaser.Plugin.Isometric.Body#render
 * @param {object} context - The context to render to.
 * @param {Phaser.Plugin.Isometric.Body} body - The Body to render the info of.
 * @param {string} [color='rgba(0,255,0,0.4)'] - 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)
 */
Phaser.Plugin.Isometric.Body.render = function (context, body, color, filled) {

    if (typeof filled === 'undefined') {
        filled = true;
    }

    color = color || 'rgba(0,255,0,0.4)';

    var points = [],
        corners = body.getCorners();

    var posX = -body.sprite.game.camera.x;
    var posY = -body.sprite.game.camera.y;

    if (filled) {
        points = [corners[1], corners[3], corners[2], corners[6], corners[4], corners[5], corners[1]];

        points = points.map(function (p) {
            var newPos = body.sprite.game.iso.project(p);
            newPos.x += posX;
            newPos.y += posY;
            return newPos;
        });
        context.beginPath();
        context.fillStyle = color;
        context.moveTo(points[0].x, points[0].y);

        for (var i = 1; i < points.length; i++) {
            context.lineTo(points[i].x, points[i].y);
        }
        context.fill();
    } else {
        points = corners.slice(0, corners.length);
        points = points.map(function (p) {
            var newPos = body.sprite.game.iso.project(p);
            newPos.x += posX;
            newPos.y += posY;
            return newPos;
        });

        context.moveTo(points[0].x, points[0].y);
        context.beginPath();
        context.strokeStyle = color;

        context.lineTo(points[1].x, points[1].y);
        context.lineTo(points[3].x, points[3].y);
        context.lineTo(points[2].x, points[2].y);
        context.lineTo(points[6].x, points[6].y);
        context.lineTo(points[4].x, points[4].y);
        context.lineTo(points[5].x, points[5].y);
        context.lineTo(points[1].x, points[1].y);
        context.lineTo(points[0].x, points[0].y);
        context.lineTo(points[4].x, points[4].y);
        context.moveTo(points[0].x, points[0].y);
        context.lineTo(points[2].x, points[2].y);
        context.moveTo(points[3].x, points[3].y);
        context.lineTo(points[7].x, points[7].y);
        context.lineTo(points[6].x, points[6].y);
        context.moveTo(points[7].x, points[7].y);
        context.lineTo(points[5].x, points[5].y);
        context.stroke();
        context.closePath();
    }

};

/**
 * Render IsoSprite Body Physics Data as text.
 *
 * @method Phaser.Plugin.Isometric.Body#renderBodyInfo
 * @param {Phaser.Plugin.Isometric.Body} body - The Body to render the info of.
 * @param {number} x - X position of the debug info to be rendered.
 * @param {number} y - Y position of the debug info to be rendered.
 * @param {string} [color='rgb(255,255,255)'] - color of the debug info to be rendered. (format is css color string).
 */
Phaser.Plugin.Isometric.Body.renderBodyInfo = function (debug, body) {

    debug.line('x: ' + body.x.toFixed(2), 'y: ' + body.y.toFixed(2), 'z: ' + body.z.toFixed(2), 'widthX: ' + body.widthX, 'widthY: ' + body.widthY, 'height: ' + body.height);
    debug.line('velocity x: ' + body.velocity.x.toFixed(2), 'y: ' + body.velocity.y.toFixed(2), 'z: ' + body.velocity.z.toFixed(2), 'deltaX: ' + body._dx.toFixed(2), 'deltaY: ' + body._dy.toFixed(2), 'deltaZ: ' + body._dz.toFixed(2));
    debug.line('acceleration x: ' + body.acceleration.x.toFixed(2), 'y: ' + body.acceleration.y.toFixed(2), 'z: ' + body.acceleration.z.toFixed(2), 'speed: ' + body.speed.toFixed(2), 'angle: ' + body.angle.toFixed(2));
    debug.line('gravity x: ' + body.gravity.x, 'y: ' + body.gravity.y, 'z: ' + body.gravity.z);
    debug.line('bounce x: ' + body.bounce.x.toFixed(2), 'y: ' + body.bounce.y.toFixed(2), 'z: ' + body.bounce.z.toFixed(2));
    debug.line('touching: ', 'frontX: ' + (body.touching.frontX ? 1 : 0) + ' frontY: ' + (body.touching.frontY ? 1 : 0) + ' backX: ' + (body.touching.backX ? 1 : 0) + ' backY: ' + (body.touching.backY ? 1 : 0) + ' up: ' + (body.touching.up ? 1 : 0) + ' down: ' + (body.touching.down ? 1 : 0));
    debug.line('blocked: ', 'frontX: ' + (body.blocked.frontX ? 1 : 0) + ' frontY: ' + (body.blocked.frontY ? 1 : 0) + ' backX: ' + (body.blocked.backX ? 1 : 0) + ' backY: ' + (body.blocked.backY ? 1 : 0) + ' up: ' + (body.blocked.up ? 1 : 0) + ' down: ' + (body.blocked.down ? 1 : 0));

};

Phaser.Plugin.Isometric.Body.prototype.constructor = Phaser.Plugin.Isometric.Body;

Phaser.Utils.Debug.prototype.body = (function (_super) {

    return function (sprite, color, filled, depth) {
        if (sprite.body && sprite.body.type === Phaser.Plugin.Isometric.ISOARCADE) {
            this.start();
            Phaser.Plugin.Isometric.Body.render(this.context, sprite.body, color, filled);
            if (depth) {
                this.text(sprite.depth.toFixed(2), sprite.x, sprite.y, color, '12px Courier');
            }
            this.stop();
        }

        return _super.call(this, sprite, color, filled);
    };

})(Phaser.Utils.Debug.prototype.body);

Phaser.Utils.Debug.prototype.bodyInfo = (function (_super) {

    return function (sprite, x, y, color) {
        if (sprite.body && sprite.body.type === Phaser.Plugin.Isometric.ISOARCADE) {
            this.start(x, y, color, 210);
            Phaser.Plugin.Isometric.Body.renderBodyInfo(this, sprite.body);
            this.stop();
        }

        return _super.call(this, sprite, x, y, color);
    };

})(Phaser.Utils.Debug.prototype.bodyInfo);