var CONST = require('./const');
var Set = require('../structs/Set');
var XHRSettings = require('./XHRSettings');
var Event = require('./events/');
// var EventDispatcher = require('../events/EventDispatcher');
var Class = require('../utils/Class');
var ParseXMLBitmapFont = require('../gameobjects/bitmaptext/ParseXMLBitmapFont');

//  Phaser.Loader.BaseLoader

//  To finish the loader ...
//
//  3) Progress update

var BaseLoader = new Class({

    initialize:

    function BaseLoader (scene)
    {
        this.scene = scene;

        this.events = scene.sys.events;

        //  Move to a 'setURL' method?
        this.baseURL = '';
        this.path = '';

        //  Read from Game / Scene Config
        this.enableParallel = true;
        this.maxParallelDownloads = 4;

        //  xhr specific global settings (can be overridden on a per-file basis)
        this.xhr = XHRSettings();

        this.crossOrigin = undefined;

        this.list = new Set();
        this.inflight = new Set();
        this.failed = new Set();
        this.queue = new Set();
        this.storage = new Set();

        this.state = CONST.LOADER_IDLE;
    },

    setPath: function (path)
    {
        if (path.substr(-1) !== '/')
        {
            path = path.concat('/');
        }

        this.path = path;

        return this;
    },

    addFile: function (file)
    {
        if (!this.isReady())
        {
            return -1;
        }

        file.path = this.path;

        this.list.set(file);

        return this;
    },

    //  Is the Loader actively loading (or processing loaded files)
    isLoading: function ()
    {
        return (this.state === CONST.LOADER_LOADING || this.state === CONST.LOADER_PROCESSING);
    },

    //  Is the Loader ready to start a new load?
    isReady: function ()
    {
        return (this.state === CONST.LOADER_IDLE || this.state === CONST.LOADER_COMPLETE || this.state === CONST.LOADER_FAILED);
    },

    start: function ()
    {
        console.log(this.scene.sys.settings.key, '- BaseLoader start. Files to load:', this.list.size);

        if (!this.isReady())
        {
            return;
        }

        this.events.dispatch(new Event.LOADER_START_EVENT(this));

        if (this.list.size === 0)
        {
            this.finishedLoading();
        }
        else
        {
            this.state = CONST.LOADER_LOADING;

            this.failed.clear();
            this.inflight.clear();
            this.queue.clear();

            this.queue.debug = true;

            this.updateProgress();

            this.processLoadQueue();
        }
    },

    updateProgress: function ()
    {

    },

    processLoadQueue: function ()
    {
        // console.log('======== BaseLoader processLoadQueue');
        // console.log('List size', this.list.size);
        // console.log(this.inflight.size, 'items still in flight. Can load another', (this.maxParallelDownloads - this.inflight.size));

        var _this = this;

        this.list.each(function (file)
        {
            if (file.state === CONST.FILE_PENDING && _this.inflight.size < _this.maxParallelDownloads)
            {
                _this.inflight.set(file);

                _this.list.delete(file);

                _this.loadFile(file);
            }

            if (_this.inflight.size === _this.maxParallelDownloads)
            {
                //  Tells the Set iterator to abort
                return false;
            }

        });
    },

    //  private
    loadFile: function (file)
    {
        // console.log('LOADING', file.key);

        //  If the file doesn't have its own crossOrigin set,
        //  we'll use the Loaders (which is undefined by default)
        if (!file.crossOrigin)
        {
            file.crossOrigin = this.crossOrigin;
        }

        file.load(this.nextFile.bind(this), this.baseURL);
    },

    nextFile: function (previousFile, success)
    {
        // console.log('LOADED:', previousFile.src, success);

        //  Move the file that just loaded from the inflight list to the queue or failed Set

        if (success)
        {
            this.queue.set(previousFile);
        }
        else
        {
            this.failed.set(previousFile);
        }

        this.inflight.delete(previousFile);

        if (this.list.size > 0)
        {
            // console.log('nextFile - still something in the list');
            this.processLoadQueue();
        }
        else if (this.inflight.size === 0)
        {
            // console.log('nextFile calling finishedLoading');
            this.finishedLoading();
        }
    },

    finishedLoading: function ()
    {
        // console.log('---> BaseLoader.finishedLoading PROCESSING', this.queue.size, 'files');

        this.state = CONST.LOADER_PROCESSING;

        this.storage.clear();

        var _this = this;

        this.queue.each(function (file)
        {
            // console.log('%c Calling process on ' + file.key, 'color: #000000; background: #ffff00;');

            file.onProcess(_this.processUpdate.bind(_this));
        });
    },

    //  Called automatically by the File when it has finished processing
    processUpdate: function (file)
    {
        // console.log('-> processUpdate', file.key, file.state);

        //  This file has failed to load, so move it to the failed Set
        if (file.state === CONST.FILE_ERRORED)
        {
            this.failed.set(file);

            if (file.linkFile)
            {
                this.queue.delete(file.linkFile);
            }

            return this.removeFromQueue(file);
        }

        //  If we got here, then the file loaded

        //  Special handling for multi-part files

        if (file.linkFile)
        {
            if (file.state === CONST.FILE_COMPLETE && file.linkFile.state === CONST.FILE_COMPLETE)
            {
                //  Partner has loaded, so add them both to Storage

                this.storage.set({ type: file.linkType, fileA: file, fileB: file.linkFile });

                this.queue.delete(file.linkFile);

                this.removeFromQueue(file);
            }
        }
        else
        {
            this.storage.set(file);

            this.removeFromQueue(file);
        }
    },

    removeFromQueue: function (file)
    {
        this.queue.delete(file);

        if (this.queue.size === 0 && this.state === CONST.LOADER_PROCESSING)
        {
            //  We've processed all the files we loaded
            this.processComplete();
        }
    },

    processComplete: function ()
    {
        console.log(this.scene.sys.settings.key, '- Loader Complete. Loaded:', this.storage.size, 'Failed:', this.failed.size);

        this.list.clear();
        this.inflight.clear();
        this.queue.clear();

        this.processCallback();

        this.state = CONST.LOADER_COMPLETE;

        this.events.dispatch(new Event.LOADER_COMPLETE_EVENT(this));
    },

    //  The Loader has finished
    processCallback: function ()
    {
        if (this.storage.size === 0)
        {
            return;
        }

        //  The global Texture Manager
        var cache = this.scene.sys.cache;
        var textures = this.scene.sys.textures;
        var anims = this.scene.sys.anims;

        //  Process multiatlas groups first

        var file;
        var fileA;
        var fileB;

        for (var key in this._multilist)
        {
            var data = [];
            var images = [];
            var keys = this._multilist[key];

            for (var i = 0; i < keys.length; i++)
            {
                file = this.storage.get('key', keys[i]);

                if (file)
                {
                    if (file.type === 'image')
                    {
                        images.push(file.data);
                    }
                    else if (file.type === 'json')
                    {
                        data.push(file.data);
                    }

                    this.storage.delete(file);
                }
            }

            //  Do we have everything needed?
            if (images.length + data.length === keys.length)
            {
                //  Yup, add them to the Texture Manager

                //  Is the data JSON Hash or JSON Array?
                if (Array.isArray(data[0].frames))
                {
                    textures.addAtlasJSONArray(key, images, data);
                }
                else
                {
                    textures.addAtlasJSONHash(key, images, data);
                }
            }
        }

        //  Process all of the files

        //  Because AnimationJSON may require images to be loaded first, we process them last
        var animJSON = [];

        this.storage.each(function (file)
        {
            switch (file.type)
            {
                case 'animationJSON':
                    animJSON.push(file);
                    break;

                case 'image':
                case 'svg':
                case 'html':
                    textures.addImage(file.key, file.data);
                    break;

                case 'atlasjson':

                    fileA = file.fileA;
                    fileB = file.fileB;

                    if (fileA.type === 'image')
                    {
                        textures.addAtlas(fileA.key, fileA.data, fileB.data);
                    }
                    else
                    {
                        textures.addAtlas(fileB.key, fileB.data, fileA.data);
                    }
                    break;

                case 'unityatlas':

                    fileA = file.fileA;
                    fileB = file.fileB;

                    if (fileA.type === 'image')
                    {
                        textures.addUnityAtlas(fileA.key, fileA.data, fileB.data);
                    }
                    else
                    {
                        textures.addUnityAtlas(fileB.key, fileB.data, fileA.data);
                    }
                    break;

                case 'bitmapfont':

                    fileA = file.fileA;
                    fileB = file.fileB;

                    if (fileA.type === 'image')
                    {
                        cache.bitmapFont.add(fileB.key, { data: ParseXMLBitmapFont(fileB.data), texture: fileA.key, frame: null });
                        textures.addImage(fileA.key, fileA.data);
                    }
                    else
                    {
                        cache.bitmapFont.add(fileA.key, { data: ParseXMLBitmapFont(fileA.data), texture: fileB.key, frame: null });
                        textures.addImage(fileB.key, fileB.data);
                    }
                    break;

                case 'spritesheet':
                    textures.addSpriteSheet(file.key, file.data, file.config);
                    break;

                case 'json':
                    cache.json.add(file.key, file.data);
                    break;

                case 'xml':
                    cache.xml.add(file.key, file.data);
                    break;

                case 'text':
                    cache.text.add(file.key, file.data);
                    break;

                case 'binary':
                    cache.binary.add(file.key, file.data);
                    break;

                case 'sound':
                    cache.sound.add(file.key, file.data);
                    break;

                case 'glsl':
                    cache.shader.add(file.key, file.data);
                    break;
            }
        });

        animJSON.forEach(function (file)
        {
            anims.fromJSON(file.data);
        });

        this.storage.clear();
    },

    reset: function ()
    {
        this.list.clear();
        this.inflight.clear();
        this.failed.clear();
        this.queue.clear();
        this.storage.clear();

        this.events.removeAll('LOADER_START_EVENT');
        this.events.removeAll('LOADER_COMPLETE_EVENT');

        this.tag = '';
        this.path = '';
        this.baseURL = '';

        this.state = CONST.LOADER_IDLE;
    },

    destroy: function ()
    {
        this.reset();
        this.state = CONST.LOADER_DESTROYED;
    }

});

module.exports = BaseLoader;


queue: function (tween)
{
tween.parent = this;
tween.parentIsTimeline = true;

/**
* @author       Richard Davey <rich@photonstorm.com>
* @author       Pete Baron <pete@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

/**
* A data representation of a Hermite Curve (see http://en.wikipedia.org/wiki/Cubic_Hermite_spline)
*
* A Hermite curve has a start and end point and tangent vectors for both of them.
* The curve will always pass through the two control points and the shape of it is controlled
* by the length and direction of the tangent vectors.  At the control points the curve will
* be facing exactly in the vector direction.
*
* As these curves change speed (speed = distance between points separated by an equal change in
* 't' value - see Hermite.getPoint) this class attempts to reduce the variation by pre-calculating
* the `accuracy` number of points on the curve. The straight-line distances to these points are stored
* in the private 'points' array, and this information is used by Hermite.findT() to convert a pixel
* distance along the curve into a 'time' value.
*
* Higher `accuracy` values will result in more even movement, but require more memory for the points
* list. 5 works, but 10 seems to be an ideal value for the length of curves found in most games on
* a desktop screen. If you use very long curves (more than 400 pixels) you may need to increase
* this value further.
*
* @class Phaser.Hermite
* @constructor
* @param {number} p1x - The x coordinate of the start of the curve.
* @param {number} p1y - The y coordinate of the start of the curve.
* @param {number} p2x - The x coordinate of the end of the curve.
* @param {number} p2y - The y coordinate of the end of the curve.
* @param {number} v1x - The x component of the tangent vector for the start of the curve.
* @param {number} v1y - The y component of the tangent vector for the start of the curve.
* @param {number} v2x - The x component of the tangent vector for the end of the curve.
* @param {number} v2y - The y component of the tangent vector for the end of the curve.
* @param {number} [accuracy=10] The amount of points to pre-calculate on the curve.
*/
Phaser.Hermite = function (p1x, p1y, p2x, p2y, v1x, v1y, v2x, v2y, accuracy) {

    if (accuracy === undefined) { accuracy = 10; }

    /**
    * @property {number} _accuracy - The amount of points to pre-calculate on the curve.
    * @private
    */
    this._accuracy = accuracy;

    /**
    * @property {number} _p1x - The x coordinate of the start of the curve.
    * @private
    */
    this._p1x = p1x;

    /**
    * @property {number} _p1y - The y coordinate of the start of the curve.
    * @private
    */
    this._p1y = p1y;

    /**
    * @property {number} _p2x - The x coordinate of the end of the curve.
    * @private
    */
    this._p2x = p2x;

    /**
    * @property {number} _p2y - The y coordinate of the end of the curve.
    * @private
    */
    this._p2y = p2y;

    /**
    * @property {number} _v1x - The x component of the tangent vector for the start of the curve.
    * @private
    */
    this._v1x = v1x;

    /**
    * @property {number} _v1y - The y component of the tangent vector for the start of the curve.
    * @private
    */
    this._v1y = v1y;

    /**
    * @property {number} _v2x - The x component of the tangent vector for the end of the curve.
    * @private
    */
    this._v2x = v2x;

    /**
    * @property {number} _v2y - The y component of the tangent vector for the end of the curve.
    * @private
    */
    this._v2y = v2y;

    /**
    * @property {array} _points - A local array of cached points.
    * @private
    */
    this._points = [];

    /**
    * @property {Phaser.Point} _temp1 - A local cached Point object.
    * @private
    */
    this._temp1 = new Phaser.Point();

    /**
    * @property {Phaser.Point} _temp2 - A local cached Point object.
    * @private
    */
    this._temp2 = new Phaser.Point();

    this.recalculate();

};

Phaser.Hermite.prototype.constructor = Phaser.Hermite;

Phaser.Hermite.prototype = {

    /**
    * Performs the curve calculations.
    *
    * This is called automatically if you change any of the curves public properties, such as `Hermite.p1x` or `Hermite.v2y`.
    *
    * If you adjust any of the internal private values, then call this to update the points.
    *
    * @method Phaser.Hermite#recalculate
    * @return {Phaser.Hermite} This object.
    */
    recalculate: function () {

        this._ax = (2 * this._p1x - 2 * this._p2x + this._v1x + this._v2x);
        this._ay = (2 * this._p1y - 2 * this._p2y + this._v1y + this._v2y);
        this._bx = (-3 * this._p1x + 3 * this._p2x - 2 * this._v1x - this._v2x);
        this._by = (-3 * this._p1y + 3 * this._p2y - 2 * this._v1y - this._v2y);

        this.length = this.calculateEvenPoints();

        return this;

    },

    /**
    * Calculate a number of points along the curve, based on `Hermite.accuracy`, and stores them in the private `_points` array.
    *
    * @method Phaser.Hermite#calculateEvenPoints
    * @return {number} The total length of the curve approximated as straight line distances between the points.
    */
    calculateEvenPoints: function () {

        var totalLength = 0;

        this._temp1.setTo(0, 0);                    //  pnt
        this._temp2.setTo(this._p1x, this._p1y);    //  lastPnt

        this._points[0] = 0;

        for (var i = 1; i <= this._accuracy; i++)
        {
            this.getPoint(i / this._accuracy, this._temp1);
            totalLength += this._temp1.distance(this._temp2);
            this._points[i] = totalLength;
            this._temp2.copyFrom(this._temp1);
        }

        return totalLength;

    },

    /**
    * Convert a distance along this curve into a `time` value which will be between 0 and 1.
    *
    * For example if this curve has a length of 100 pixels then `findT(50)` would return `0.5`.
    *
    * @method Phaser.Hermite#findT
    * @param {integer} distance - The distance into the curve in pixels. Should be a positive integer.
    * @return {number} The time (`t`) value, a float between 0 and 1.
    */
    findT: function (distance) {

        if (distance <= 0)
        {
            return 0;
        }

        //  Find the _points which bracket the distance value
        var ti = Math.floor(distance / this.length * this._accuracy);

        while (ti > 0 && this._points[ti] > distance)
        {
            ti--;
        }

        while (ti < this._accuracy && this._points[ti] < distance)
        {
            ti++;
        }

        //  Linear interpolation to get a more accurate fix
        var dt = this._points[ti] - this._points[ti - 1];
        var d = distance - this._points[ti - 1];

        return ((ti - 1) / this._accuracy) + d / (dt * this._accuracy);

    },

    /**
    * Get the X component of a point on the curve based on the `t` (time) value, which must be between 0 and 1.
    *
    * @method Phaser.Hermite#getX
    * @param {number} [t=0] - The time value along the curve from which to extract a point. This is a value between 0 and 1, where 0 represents the start of the curve and 1 the end.
    * @return {number} The X component of a point on the curve based on the `t` (time) value.
    */
    getX: function (t) {

        if (t === undefined)
        {
            t = 0;
        }
        else
        {
            if (t < 0)
            {
                t = 0;
            }

            if (t > 1)
            {
                t = 1;
            }
        }

        var t2 = t * t;
        var t3 = t * t2;

        return (t3 * this._ax + t2 * this._bx + t * this._v1x + this._p1x);

    },

    /**
    * Get the Y component of a point on the curve based on the `t` (time) value, which must be between 0 and 1.
    *
    * @method Phaser.Hermite#getY
    * @param {number} [t=0] - The time value along the curve from which to extract a point. This is a value between 0 and 1, where 0 represents the start of the curve and 1 the end.
    * @return {number} The Y component of a point on the curve based on the `t` (time) value.
    */
    getY: function (t) {

        if (t === undefined)
        {
            t = 0;
        }
        else
        {
            if (t < 0)
            {
                t = 0;
            }

            if (t > 1)
            {
                t = 1;
            }
        }

        var t2 = t * t;
        var t3 = t * t2;

        return (t3 * this._ay + t2 * this._by + t * this._v1y + this._p1y);

    },

    /**
    * Get a point on the curve using the `t` (time) value, which must be between 0 and 1.
    *
    * @method Phaser.Hermite#getPoint
    * @param {number} [t=0] - The time value along the curve from which to extract a point. This is a value between 0 and 1, where 0 represents the start of the curve and 1 the end.
    * @param {Phaser.Point|Object} [point] - An optional Phaser.Point, or Object containing public `x` and `y` properties. If given the resulting values will be stored in the Objects `x` and `y` properties. If omitted a new Phaser.Point object is created.
    * @return {Phaser.Point} An Object with the x, y coordinate of the curve at the specified `t` value set in its `x` and `y` properties.
    */
    getPoint: function (t, point) {

        if (t === undefined) { t = 0; }
        if (point === undefined) { point = new Phaser.Point(); }

        if (t < 0)
        {
            t = 0;
        }

        if (t > 1)
        {
            t = 1;
        }

        var t2 = t * t;
        var t3 = t * t2;

        point.x = t3 * this._ax + t2 * this._bx + t * this._v1x + this._p1x;
        point.y = t3 * this._ay + t2 * this._by + t * this._v1y + this._p1y;

        return point;

    },

    /**
    * Get a point on the curve using the distance, in pixels, along the curve.
    *
    * @method Phaser.Hermite#getPointWithDistance
    * @param {integer} [distance=0] - The distance along the curve to get the point from, given in pixels.
    * @param {Phaser.Point|Object} [point] - An optional Phaser.Point, or Object containing public `x` and `y` properties. If given the resulting values will be stored in the Objects `x` and `y` properties. If omitted a new Phaser.Point object is created.
    * @return {Phaser.Point} The point on the line at the specified 'distance' along the curve.
    */
    getPointWithDistance: function (distance, point) {

        if (distance === undefined) { distance = 0; }
        if (point === undefined) { point = new Phaser.Point(); }

        if (distance <= 0)
        {
            point.x = this._p1x;
            point.y = this._p1y;
        }
        else
        {
            this.getPoint(this.findT(distance), point);
        }

        return point;

    },

    /**
    * Calculate and return the angle, in radians, of the curves tangent based on time.
    *
    * @method Phaser.Hermite#getAngle
    * @param {number} [t=0] - The `t` (time) value at which to find the angle. Must be between 0 and 1.
    * @return {number} The angle of the line at the specified `t` time value along the curve. The value is in radians.
    */
    getAngle: function (t) {

        if (t === undefined) { t = 0; }

        this.getPoint(t - 0.01, this._temp1);
        this.getPoint(t + 0.01, this._temp2);

        return Math.atan2(this._temp2.y - this._temp1.y, this._temp2.x - this._temp1.x);

    },

    /**
    * Calculate and return the angle, in radians, of the curves tangent at the given pixel distance along the curves length.
    *
    * @method Phaser.Hermite#getAngleWithDistance
    * @param {number} [distance=0] - The distance along the curve to get the angle from, in pixels.
    * @return {number} The angle of the line at the specified distance along the curve. The value is in radians.
    */
    getAngleWithDistance: function (distance) {

        if (distance === undefined) { distance = 0; }

        if (distance <= 0)
        {
            return Math.atan2(this._v1y, this._v1x);
        }
        else
        {
            return this.getAngle(this.findT(distance));
        }

    },

    /**
    * Get the angle of the curves entry point.
    *
    * @method Phaser.Hermite#getEntryTangent
    * @param {Phaser.Point|Object} point - The Phaser.Point object, or an Object with public `x` and `y` properties, in which the tangent vector values will be stored.
    * @return {Phaser.Point} A Point object containing the tangent vector of this Hermite curve.
    */
    getEntryTangent: function (point) {

        point.x = this._v1x;
        point.y = this._v1y;

        return point;

    }

};

Object.defineProperties(Phaser.Hermite.prototype, {

    /**
    * @name Phaser.Hermite#accuracy
    * @property {number} accuracy - The amount of points to pre-calculate on the curve.
    */
    accuracy: {

        get: function () {

            return this._accuracy;

        },

        set: function (value) {

            if (value !== this._accuracy)
            {
                this._accuracy = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#p1x
    * @property {number} p1x - The x coordinate of the start of the curve. Setting this value will recalculate the curve.
    */
    p1x: {

        get: function () {

            return this._p1x;

        },

        set: function (value) {

            if (value !== this._p1x)
            {
                this._p1x = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#p1y
    * @property {number} p1y - The y coordinate of the start of the curve. Setting this value will recalculate the curve.
    */
    p1y: {

        get: function () {

            return this._p1y;

        },

        set: function (value) {

            if (value !== this._p1y)
            {
                this._p1y = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#p2x
    * @property {number} p2x - The x coordinate of the end of the curve. Setting this value will recalculate the curve.
    */
    p2x: {

        get: function () {

            return this._p2x;

        },

        set: function (value) {

            if (value !== this._p2x)
            {
                this._p2x = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#p2y
    * @property {number} p2y - The y coordinate of the end of the curve. Setting this value will recalculate the curve.
    */
    p2y: {

        get: function () {

            return this._p2y;

        },

        set: function (value) {

            if (value !== this._p2y)
            {
                this._p2y = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#v1x
    * @property {number} v1x - The x component of the tangent vector for the start of the curve. Setting this value will recalculate the curve.
    */
    v1x: {

        get: function () {

            return this._v1x;

        },

        set: function (value) {

            if (value !== this._v1x)
            {
                this._v1x = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#v1y
    * @property {number} v1y - The y component of the tangent vector for the start of the curve. Setting this value will recalculate the curve.
    */
    v1y: {

        get: function () {

            return this._v1y;

        },

        set: function (value) {

            if (value !== this._v1y)
            {
                this._v1y = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#v2x
    * @property {number} v2x - The x component of the tangent vector for the end of the curve. Setting this value will recalculate the curve.
    */
    v2x: {

        get: function () {

            return this._v2x;

        },

        set: function (value) {

            if (value !== this._v2x)
            {
                this._v2x = value;
                this.recalculate();
            }

        }

    },

    /**
    * @name Phaser.Hermite#v2y
    * @property {number} v2y - The y component of the tangent vector for the end of the curve. Setting this value will recalculate the curve.
    */
    v2y: {

        get: function () {

            return this._v2y;

        },

        set: function (value) {

            if (value !== this._v2y)
            {
                this._v2y = value;
                this.recalculate();
            }

        }

    }

});


/**
* @author       Richard Davey <rich@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

/**
* The MSPointer class handles Microsoft touch interactions with the game and the resulting Pointer objects.
*
* It will work only in Internet Explorer 10+ and Windows Store or Windows Phone 8 apps using JavaScript.
* http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx
*
* You should not normally access this class directly, but instead use a Phaser.Pointer object which
* normalises all game input for you including accurate button handling.
*
* Please note that at the current time of writing Phaser does not yet support chorded button interactions:
* http://www.w3.org/TR/pointerevents/#chorded-button-interactions
*
* @class Phaser.MSPointer
* @constructor
* @param {Phaser.Game} game - A reference to the currently running game.
*/
Phaser.MSPointer = function (game) {

    /**
    * @property {Phaser.Game} game - A reference to the currently running game.
    */
    this.game = game;

    /**
    * @property {Phaser.Input} input - A reference to the Phaser Input Manager.
    * @protected
    */
    this.input = game.input;

    /**
    * @property {object} callbackContext - The context under which callbacks are called (defaults to game).
    */
    this.callbackContext = this.game;

    /**
    * @property {function} pointerDownCallback - A callback that can be fired on a MSPointerDown event.
    */
    this.pointerDownCallback = null;

    /**
    * @property {function} pointerMoveCallback - A callback that can be fired on a MSPointerMove event.
    */
    this.pointerMoveCallback = null;

    /**
    * @property {function} pointerUpCallback - A callback that can be fired on a MSPointerUp event.
    */
    this.pointerUpCallback = null;

    /**
    * @property {boolean} capture - If true the Pointer events will have event.preventDefault applied to them, if false they will propagate fully.
    */
    this.capture = true;

    /**
    * This property was removed in Phaser 2.4 and should no longer be used.
    * Instead please see the Pointer button properties such as `Pointer.leftButton`, `Pointer.rightButton` and so on.
    * Or Pointer.button holds the DOM event button value if you require that.
    * @property {number} button
    */
    this.button = -1;

    /**
    * The browser MSPointer DOM event. Will be null if no event has ever been received.
    * Access this property only inside a Pointer event handler and do not keep references to it.
    * @property {MSPointerEvent|null} event
    * @default
    */
    this.event = null;

    /**
    * MSPointer input will only be processed if enabled.
    * @property {boolean} enabled
    * @default
    */
    this.enabled = true;

    /**
    * @property {function} _onMSPointerDown - Internal function to handle MSPointer events.
    * @private
    */
    this._onMSPointerDown = null;

    /**
    * @property {function} _onMSPointerMove - Internal function to handle MSPointer events.
    * @private
    */
    this._onMSPointerMove = null;

    /**
    * @property {function} _onMSPointerUp - Internal function to handle MSPointer events.
    * @private
    */
    this._onMSPointerUp = null;

    /**
    * @property {function} _onMSPointerUpGlobal - Internal function to handle MSPointer events.
    * @private
    */
    this._onMSPointerUpGlobal = null;

    /**
    * @property {function} _onMSPointerOut - Internal function to handle MSPointer events.
    * @private
    */
    this._onMSPointerOut = null;

    /**
    * @property {function} _onMSPointerOver - Internal function to handle MSPointer events.
    * @private
    */
    this._onMSPointerOver = null;

};

Phaser.MSPointer.prototype = {

    /**
    * Starts the event listeners running.
    * @method Phaser.MSPointer#start
    */
    start: function () {

        if (this._onMSPointerDown !== null)
        {
            //  Avoid setting multiple listeners
            return;
        }

        var _this = this;

        if (this.game.device.mspointer)
        {
            this._onMSPointerDown = function (event) {
                return _this.onPointerDown(event);
            };

            this._onMSPointerMove = function (event) {
                return _this.onPointerMove(event);
            };

            this._onMSPointerUp = function (event) {
                return _this.onPointerUp(event);
            };

            this._onMSPointerUpGlobal = function (event) {
                return _this.onPointerUpGlobal(event);
            };

            this._onMSPointerOut = function (event) {
                return _this.onPointerOut(event);
            };

            this._onMSPointerOver = function (event) {
                return _this.onPointerOver(event);
            };

            var canvas = this.game.canvas;

            canvas.addEventListener('MSPointerDown', this._onMSPointerDown, false);
            canvas.addEventListener('MSPointerMove', this._onMSPointerMove, false);
            canvas.addEventListener('MSPointerUp', this._onMSPointerUp, false);

            //  IE11+ uses non-prefix events
            canvas.addEventListener('pointerdown', this._onMSPointerDown, false);
            canvas.addEventListener('pointermove', this._onMSPointerMove, false);
            canvas.addEventListener('pointerup', this._onMSPointerUp, false);

            canvas.style['-ms-content-zooming'] = 'none';
            canvas.style['-ms-touch-action'] = 'none';

            if (!this.game.device.cocoonJS)
            {
                window.addEventListener('MSPointerUp', this._onMSPointerUpGlobal, true);
                canvas.addEventListener('MSPointerOver', this._onMSPointerOver, true);
                canvas.addEventListener('MSPointerOut', this._onMSPointerOut, true);

                //  IE11+ uses non-prefix events
                window.addEventListener('pointerup', this._onMSPointerUpGlobal, true);
                canvas.addEventListener('pointerover', this._onMSPointerOver, true);
                canvas.addEventListener('pointerout', this._onMSPointerOut, true);
            }
        }

    },

    /**
    * The function that handles the PointerDown event.
    *
    * @method Phaser.MSPointer#onPointerDown
    * @param {PointerEvent} event - The native DOM event.
    */
    onPointerDown: function (event) {

        this.event = event;

        if (this.capture)
        {
            event.preventDefault();
        }

        if (this.pointerDownCallback)
        {
            this.pointerDownCallback.call(this.callbackContext, event);
        }

        if (!this.input.enabled || !this.enabled)
        {
            return;
        }

        event.identifier = event.pointerId;

        if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
        {
            this.input.mousePointer.start(event);
        }
        else
        {
            this.input.startPointer(event);
        }

    },

    /**
    * The function that handles the PointerMove event.
    * @method Phaser.MSPointer#onPointerMove
    * @param {PointerEvent} event - The native DOM event.
    */
    onPointerMove: function (event) {

        this.event = event;

        if (this.capture)
        {
            event.preventDefault();
        }

        if (this.pointerMoveCallback)
        {
            this.pointerMoveCallback.call(this.callbackContext, event);
        }

        if (!this.input.enabled || !this.enabled)
        {
            return;
        }

        event.identifier = event.pointerId;

        if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
        {
            this.input.mousePointer.move(event);
        }
        else
        {
            this.input.updatePointer(event);
        }

    },

    /**
    * The function that handles the PointerUp event.
    * @method Phaser.MSPointer#onPointerUp
    * @param {PointerEvent} event - The native DOM event.
    */
    onPointerUp: function (event) {

        this.event = event;

        if (this.capture)
        {
            event.preventDefault();
        }

        if (this.pointerUpCallback)
        {
            this.pointerUpCallback.call(this.callbackContext, event);
        }

        if (!this.input.enabled || !this.enabled)
        {
            return;
        }

        event.identifier = event.pointerId;

        if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
        {
            this.input.mousePointer.stop(event);
        }
        else
        {
            this.input.stopPointer(event);
        }

    },

    /**
    * The internal method that handles the mouse up event from the window.
    *
    * @method Phaser.MSPointer#onPointerUpGlobal
    * @param {PointerEvent} event - The native event from the browser. This gets stored in MSPointer.event.
    */
    onPointerUpGlobal: function (event) {

        if ((event.pointerType === 'mouse' || event.pointerType === 0x00000004) && !this.input.mousePointer.withinGame)
        {
            this.onPointerUp(event);
        }
        else
        {
            var pointer = this.input.getPointerFromIdentifier(event.identifier);

            if (pointer && pointer.withinGame)
            {
                this.onPointerUp(event);
            }
        }

    },

    /**
    * The internal method that handles the pointer out event from the browser.
    *
    * @method Phaser.MSPointer#onPointerOut
    * @param {PointerEvent} event - The native event from the browser. This gets stored in MSPointer.event.
    */
    onPointerOut: function (event) {

        this.event = event;

        if (this.capture)
        {
            event.preventDefault();
        }

        if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
        {
            this.input.mousePointer.withinGame = false;
        }
        else
        {
            var pointer = this.input.getPointerFromIdentifier(event.identifier);

            if (pointer)
            {
                pointer.withinGame = false;
            }
        }

        if (this.input.mouse.mouseOutCallback)
        {
            this.input.mouse.mouseOutCallback.call(this.input.mouse.callbackContext, event);
        }

        if (!this.input.enabled || !this.enabled)
        {
            return;
        }

        if (this.input.mouse.stopOnGameOut)
        {
            event['identifier'] = 0;

            if (pointer)
            {
                pointer.stop(event);
            }
            else
            {
                this.input.mousePointer.stop(event);
            }
        }

    },

    /**
    * The internal method that handles the pointer out event from the browser.
    *
    * @method Phaser.MSPointer#onPointerOut
    * @param {PointerEvent} event - The native event from the browser. This gets stored in MSPointer.event.
    */
    onPointerOver: function (event) {

        this.event = event;

        if (this.capture)
        {
            event.preventDefault();
        }

        if (event.pointerType === 'mouse' || event.pointerType === 0x00000004)
        {
            this.input.mousePointer.withinGame = true;
        }
        else
        {
            var pointer = this.input.getPointerFromIdentifier(event.identifier);

            if (pointer)
            {
                pointer.withinGame = true;
            }
        }

        if (this.input.mouse.mouseOverCallback)
        {
            this.input.mouse.mouseOverCallback.call(this.input.mouse.callbackContext, event);
        }

    },

    /**
    * Stop the event listeners.
    * @method Phaser.MSPointer#stop
    */
    stop: function () {

        var canvas = this.game.canvas;

        canvas.removeEventListener('MSPointerDown', this._onMSPointerDown, false);
        canvas.removeEventListener('MSPointerMove', this._onMSPointerMove, false);
        canvas.removeEventListener('MSPointerUp', this._onMSPointerUp, false);

        //  IE11+ uses non-prefix events
        canvas.removeEventListener('pointerdown', this._onMSPointerDown, false);
        canvas.removeEventListener('pointermove', this._onMSPointerMove, false);
        canvas.removeEventListener('pointerup', this._onMSPointerUp, false);

        window.removeEventListener('MSPointerUp', this._onMSPointerUpGlobal, true);
        canvas.removeEventListener('MSPointerOver', this._onMSPointerOver, true);
        canvas.removeEventListener('MSPointerOut', this._onMSPointerOut, true);

        //  IE11+ uses non-prefix events
        window.removeEventListener('pointerup', this._onMSPointerUpGlobal, true);
        canvas.removeEventListener('pointerover', this._onMSPointerOver, true);
        canvas.removeEventListener('pointerout', this._onMSPointerOut, true);

    }

};

Phaser.MSPointer.prototype.constructor = Phaser.MSPointer;


var Class = require('../../utils/Class');
var TimelineBuilder = require('../builder/TimelineBuilder');
var TweenBuilder = require('../builder/TweenBuilder');

var TweenManager = new Class({

    initialize:

    function TweenManager (scene)
    {
        //  The Scene the Tween Manager belongs to (tweens are Scene specific, not Game global)
        this.scene = scene;

        this.timeScale = 1;

        this._add = [];
        this._pending = [];
        this._active = [];
        this._destroy = [];

        this._toProcess = 0;
    },

    //  Scene is starting up
    boot: function ()
    {
        this.timeScale = 1;
    },

    //  Create a Tween Timeline and return it, but do NOT add it to the active or pending Tween lists
    createTimeline: function (config)
    {
        return TimelineBuilder(this, config);
    },

    //  Create a Tween Timeline and add it to the active Tween list
    timeline: function (config)
    {
        var timeline = TimelineBuilder(this, config);

        this._add.push(timeline);

        this._toProcess++;

        return timeline;
    },

    //  Create a Tween and return it, but do NOT add it to the active or pending Tween lists
    create: function (config)
    {
        return TweenBuilder(this, config);
    },

    //  Create a Tween and add it to the active Tween list
    add: function (config)
    {
        var tween = TweenBuilder(this, config);

        this._add.push(tween);

        this._toProcess++;

        return tween;
    },

    //  Add an existing tween into the active Tween list
    existing: function (tween)
    {
        this._add.push(tween);

        this._toProcess++;

        return this;
    },

    begin: function ()
    {
        if (this._toProcess === 0)
        {
            //  Quick bail
            return;
        }

        var list = this._destroy;
        var active = this._active;
        var i;
        var tween;

        //  Clear the 'destroy' list
        for (i = 0; i < list.length; i++)
        {
            tween = list[i];

            //  Remove from the 'active' array
            var idx = active.indexOf(tween);

            if (idx !== -1)
            {
                active.splice(idx, 1);
            }
        }

        list.length = 0;

        //  Process the addition list
        //  This stops callbacks and out of sync events from populating the active array mid-way during the update

        list = this._add;

        for (i = 0; i < list.length; i++)
        {
            tween = list[i];

            //  Return true if the Tween should be started right away, otherwise false
            if (tween.init())
            {
                tween.play();

                this._active.push(tween);
            }
            else
            {
                this._pending.push(tween);
            }
        }

        list.length = 0;

        this._toProcess = 0;
    },

    update: function (timestamp, delta)
    {
        //  Process active tweens
        var list = this._active;
        var tween;

        //  Scale the delta
        delta *= this.timeScale;

        for (var i = 0; i < list.length; i++)
        {
            tween = list[i];

            //  If Tween.update returns 'true' then it means it has completed,
            //  so move it to the destroy list
            if (tween.update(timestamp, delta))
            {
                this._destroy.push(tween);
                this._toProcess++;
            }
        }
    },

    makeActive: function (tween)
    {
        var idx = this._pending.indexOf(tween);

        if (idx !== -1)
        {
            this._pending.splice(idx, 1);
        }

        this._add.push(tween);

        this._toProcess++;
    },

    setGlobalTimeScale: require('./components/SetGlobalTimeScale'),
    getGlobalTimeScale: require('./components/GetGlobalTimeScale'),
    getAllTweens: require('./components/GetAllTweens'),
    getTweensOf: require('./components/GetTweensOf'),
    isTweening: require('./components/IsTweening'),
    killAll: require('./components/KillAll'),
    killTweensOf: require('./components/KillTweensOf'),
    pauseAll: require('./components/PauseAll'),
    resumeAll: require('./components/ResumeAll'),
    each: require('./components/Each'),
    shutdown: require('./components/Shutdown'),
    destroy: require('./components/Destroy')

    // TODO: kill: function (vars, target)
});

module.exports = TweenManager;


module.exports = {

    renderCanvas: require('./EffectLayerCanvasRenderer'),
    renderWebGL: require('./EffectLayerWebGLRenderer')

};


var BlitterFactory = require('../../gameobjects/blitter/BlitterFactory');
var Class = require('../../utils/Class');
var DynamicBitmapTextFactory = require('../../gameobjects/bitmaptext/dynamic/DynamicBitmapTextFactory');
var DynamicTilemapFactory = require('../../gameobjects/tilemap/dynamic/TilemapFactory');
var EffectLayerFactory = require('../../gameobjects/effectlayer/EffectLayerFactory');
var GraphicsFactory = require('../../gameobjects/graphics/GraphicsFactory');
var GroupFactory = require('../../gameobjects/group/GroupFactory');
var ImageFactory = require('../../gameobjects/image/ImageFactory');
var LightLayerFactory = require('../../gameobjects/lightlayer/LightLayerFactory');
var MeshFactory = require('../../gameobjects/mesh/MeshFactory');
var QuadFactory = require('../../gameobjects/quad/QuadFactory');
var RenderPassFactory = require('../../gameobjects/renderpass/RenderPassFactory');
var SpriteFactory = require('../../gameobjects/sprite/SpriteFactory');
var StaticBitmapTextFactory = require('../../gameobjects/bitmaptext/static/BitmapTextFactory');
var StaticTilemapFactory = require('../../gameobjects/tilemap/static/StaticTilemapFactory');
var TextFactory = require('../../gameobjects/text/static/TextFactory');
var TileSpriteFactory = require('../../gameobjects/tilesprite/TileSpriteFactory');
var ZoneFactory = require('../../gameobjects/zone/ZoneFactory');

var GameObjectFactory = new Class({

    initialize:

    function GameObjectFactory (scene)
    {
        this.scene = scene;

        this.displayList;
        this.updateList;
    },

    boot: function ()
    {
        this.displayList = this.scene.sys.displayList;
        this.updateList = this.scene.sys.updateList;
    },

    existing: function (child)
    {
        if (child.renderCanvas || child.renderWebGL)
        {
            this.displayList.add(child);
        }

        if (child.preUpdate)
        {
            this.updateList.add(child);
        }

        return child;
    },

    bitmapText: function (x, y, font, text, size, align)
    {
        return this.displayList.add(StaticBitmapTextFactory(this.scene, x, y, font, text, size, align));
    },

    dynamicBitmapText: function (x, y, font, text, size, align)
    {
        return this.displayList.add(DynamicBitmapTextFactory(this.scene, x, y, font, text, size, align));
    },

    blitter: function (x, y, key, frame)
    {
        return this.displayList.add(BlitterFactory(this.scene, x, y, key, frame));
    },

    effectLayer: function (x, y, width, height, effectName, fragmentShader)
    {
        return this.displayList.add(EffectLayerFactory(this.scene, x, y, width, height, effectName, fragmentShader));
    },

    graphics: function (config)
    {
        return this.displayList.add(GraphicsFactory(this.scene, config));
    },

    group: function (displayList, config)
    {
        return GroupFactory(this.scene, displayList, config);
    },

    image: function (x, y, key, frame)
    {
        return this.displayList.add(ImageFactory(this.scene, x, y, key, frame));
    },

    mesh: function (x, y, vertices, uv, key, frame)
    {
        return this.displayList.add(MeshFactory(this.scene, x, y, vertices, uv, key, frame));
    },

    quad: function (x, y, key, frame)
    {
        return this.displayList.add(QuadFactory(this.scene, x, y, key, frame));
    },

    renderPass: function (x, y, width, height, shaderName, fragmentShader)
    {
        return this.displayList.add(RenderPassFactory(this.scene, x, y, width, height, shaderName, fragmentShader));
    },

    sprite: function (x, y, key, frame)
    {
        var sprite = SpriteFactory(this.scene, x, y, key, frame);

        this.displayList.add(sprite);
        this.updateList.add(sprite);

        return sprite;
    },

    text: function (x, y, text, style)
    {
        return this.displayList.add(TextFactory(this.scene, x, y, text, style));
    },

    tilemap: function (mapData, x, y, tileWidth, tileHeight, mapWidth, mapHeight, tileBorder, texture, frame)
    {
        return this.displayList.add(DynamicTilemapFactory(this.scene, mapData, x, y, tileWidth, tileHeight, mapWidth, mapHeight, tileBorder, texture, frame));
    },

    staticTilemap: function (mapData, x, y, tileWidth, tileHeight, mapWidth, mapHeight, tileBorder, texture, frame)
    {
        return this.displayList.add(StaticTilemapFactory(this.scene, mapData, x, y, tileWidth, tileHeight, mapWidth, mapHeight, tileBorder, texture, frame));
    },

    tileSprite: function (x, y, width, height, key, frame)
    {
        return this.displayList.add(TileSpriteFactory(this.scene, x, y, width, height, key, frame));
    },

    zone: function (x, y, width, height)
    {
        return this.displayList.add(ZoneFactory(this.scene, x, y, width, height));
    },

    tween: function (config)
    {
        return this.scene.sys.tweens.add(config);
    },

    lightLayer: function ()
    {
        return this.displayList.add(LightLayerFactory(this.scene));
    }

});

module.exports = GameObjectFactory;


var SetY = function (items, value, step)
{
    if (step === undefined) { step = 0; }

    for (var i = 0; i < items.length; i++)
    {
        items[i].y = value + (i * step);
    }

    return items;
};

module.exports = SetY;


var Class = require('../../utils/Class');
var TweenBuilder = require('../builder/TweenBuilder');
var TWEEN_CONST = require('../tween/const');

var Timeline = new Class({

    initialize:

    function Timeline (manager)
    {
        this.manager = manager;

        this.isTimeline = true;

        //  An array of Tween objects, each containing a unique property and target being tweened.
        this.data = [];

        //  data array doesn't usually change, so we can cache the length
        this.totalData = 0;

        //  If true then duration, delay, etc values are all frame totals
        this.useFrames = false;

        //  Scales the time applied to this Tween. A value of 1 runs in real-time. A value of 0.5 runs 50% slower, and so on.
        //  Value isn't used when calculating total duration of the tween, it's a run-time delta adjustment only.
        this.timeScale = 1;

        //  Loop this tween? Can be -1 for an infinite loop, or an integer.
        //  When enabled it will play through ALL TweenDatas again (use TweenData.repeat to loop a single TD)
        this.loop = 0;

        //  Time in ms/frames before the tween loops.
        this.loopDelay = 0;

        //  How many loops are left to run?
        this.loopCounter = 0;

        //  Time in ms/frames before the 'onComplete' event fires. This never fires if loop = true (as it never completes)
        this.completeDelay = 0;

        //  Countdown timer (used by loopDelay and completeDelay)
        this.countdown = 0;

        //  The current state of the tween
        this.state = TWEEN_CONST.PENDING_ADD;

        //  The state of the tween when it was paused (used by Resume)
        this._pausedState = TWEEN_CONST.PENDING_ADD;

        //  Does the Tween start off paused? (if so it needs to be started with Tween.play)
        this.paused = false;

        //  Elapsed time in ms/frames of this run through the Tween.
        this.elapsed = 0;

        //  Total elapsed time in ms/frames of the entire Tween, including looping.
        this.totalElapsed = 0;

        //  Time in ms/frames for the whole Tween to play through once, excluding loop amounts and loop delays
        this.duration = 0;

        //  Value between 0 and 1. The amount through the Tween, excluding loops.
        this.progress = 0;

        //  Time in ms/frames for all Tweens to complete (including looping)
        this.totalDuration = 0;

        //  Value between 0 and 1. The amount through the entire Tween, including looping.
        this.totalProgress = 0;

        this.callbacks = {
            onComplete: null,
            onLoop: null,
            onStart: null,
            onUpdate: null,
            onYoyo: null
        };

        this.callbackScope;
    },

    setTimeScale: function (value)
    {
        this.timeScale = value;

        return this;
    },

    getTimeScale: function ()
    {
        return this.timeScale;
    },

    isPlaying: function ()
    {
        return (this.state === TWEEN_CONST.ACTIVE);
    },

    add: function (config)
    {
        return this.queue(TweenBuilder(this, config));
    },

    queue: function (tween)
    {
        tween.parent = this;
        tween.parentIsTimeline = true;

        this.data.push(tween);

        this.totalData = this.data.length;

        return this;
    },

    hasOffset: function (tween)
    {
        return (tween.offset !== null);
    },

    isOffsetAbsolute: function (value)
    {
        return (typeof(value) === 'number');
    },

    isOffsetRelative: function (value)
    {
        var t = typeof(value);

        if (t === 'string')
        {
            var op = value[0];

            if (op === '-' || op === '+')
            {
                return true;
            }
        }

        return false;
    },

    getRelativeOffset: function (value, base)
    {
        var op = value[0];
        var num = parseFloat(value.substr(2));
        var result = base;

        switch (op)
        {
            case '+':
                result += num;
                break;

            case '-':
                result -= num;
                break;
        }

        //  Cannot ever be < 0
        return Math.max(0, result);
    },

    calcDuration: function ()
    {
        var prevEnd = 0;
        var totalDuration = 0;
        var offsetDuration = 0;

        for (var i = 0; i < this.totalData; i++)
        {
            var tween = this.data[i];

            tween.init();

            if (this.hasOffset(tween))
            {
                if (this.isOffsetAbsolute(tween.offset))
                {
                    //  An actual number, so it defines the start point from the beginning of the timeline
                    tween.calculatedOffset = tween.offset;

                    if (tween.offset === 0)
                    {
                        offsetDuration = 0;
                    }

                    // console.log('Timeline.calcDuration', i, 'absolute', tween.calculatedOffset);
                }
                else if (this.isOffsetRelative(tween.offset))
                {
                    //  A relative offset (i.e. '-=1000', so starts at 'offset' ms relative to the PREVIOUS Tweens ending time)
                    tween.calculatedOffset = this.getRelativeOffset(tween.offset, prevEnd);

                    // console.log('Timeline.calcDuration', i, 'relative', tween.calculatedOffset);
                }
            }
            else
            {
                //  Sequential
                tween.calculatedOffset = offsetDuration;

                // console.log('Timeline.calcDuration', i, 'sequential', tween.calculatedOffset);
            }

            prevEnd = tween.totalDuration + tween.calculatedOffset;

            // console.log('Span', i, tween.calculatedOffset, 'to', prevEnd);

            totalDuration += tween.totalDuration;
            offsetDuration += tween.totalDuration;
        }

        //  Excludes loop values
        this.duration = totalDuration;

        this.loopCounter = (this.loop === -1) ? 999999999999 : this.loop;

        if (this.loopCounter > 0)
        {
            this.totalDuration = this.duration + this.completeDelay + ((this.duration + this.loopDelay) * this.loopCounter);
        }
        else
        {
            this.totalDuration = this.duration + this.completeDelay;
        }
    },

    init: function ()
    {
        this.calcDuration();

        this.progress = 0;
        this.totalProgress = 0;

        if (this.paused)
        {
            this.state = TWEEN_CONST.PAUSED;

            return false;
        }
        else
        {
            return true;
        }
    },

    resetTweens: function (resetFromLoop)
    {
        for (var i = 0; i < this.totalData; i++)
        {
            var tween = this.data[i];

            tween.play(resetFromLoop);
        }
    },

    setCallback: function (type, callback, params, scope)
    {
        if (Timeline.TYPES.indexOf(type) !== -1)
        {
            this.callbacks[type] = { func: callback, scope: scope, params: params };
        }

        return this;
    },

    play: function ()
    {
        if (this.state === TWEEN_CONST.ACTIVE)
        {
            return;
        }

        if (this.paused)
        {
            this.paused = false;

            this.manager.makeActive(this);

            return;
        }
        else
        {
            this.resetTweens(false);

            this.state = TWEEN_CONST.ACTIVE;
        }

        var onStart = this.callbacks.onStart;

        if (onStart)
        {
            onStart.func.apply(onStart.scope, onStart.params);
        }
    },

    nextState: function ()
    {
        if (this.loopCounter > 0)
        {
            this.resetTweens(true);

            //  Reset the elapsed time
            //  TODO: Probably ought to be set to the remainder from elapsed - duration
            //  as the tweens nearly always over-run by a few ms due to rAf

            this.elapsed = 0;
            this.progress = 0;

            this.loopCounter--;

            var onLoop = this.callbacks.onLoop;

            if (onLoop)
            {
                onLoop.func.apply(onLoop.scope, onLoop.params);
            }

            if (this.loopDelay > 0)
            {
                this.countdown = this.loopDelay;
                this.state = TWEEN_CONST.LOOP_DELAY;
            }
            else
            {
                this.state = TWEEN_CONST.ACTIVE;
            }
        }
        else if (this.completeDelay > 0)
        {
            this.countdown = this.completeDelay;
            this.state = TWEEN_CONST.COMPLETE_DELAY;
        }
        else
        {
            var onComplete = this.callbacks.onComplete;

            if (onComplete)
            {
                onComplete.func.apply(onComplete.scope, onComplete.params);
            }

            this.state = TWEEN_CONST.PENDING_REMOVE;
        }
    },

    //  Returns 'true' if this Timeline has finished and should be removed from the Tween Manager
    //  Otherwise, returns false
    update: function (timestamp, delta)
    {
        if (this.state === TWEEN_CONST.PAUSED)
        {
            return;
        }

        var rawDelta = delta;

        if (this.useFrames)
        {
            delta = 1 * this.manager.timeScale;
        }

        delta *= this.timeScale;

        this.elapsed += delta;
        this.progress = Math.min(this.elapsed / this.duration, 1);

        this.totalElapsed += delta;
        this.totalProgress = Math.min(this.totalElapsed / this.totalDuration, 1);

        switch (this.state)
        {
            case TWEEN_CONST.ACTIVE:

                var stillRunning = this.totalData;

                for (var i = 0; i < this.totalData; i++)
                {
                    var tween = this.data[i];

                    if (tween.update(timestamp, rawDelta))
                    {
                        stillRunning--;
                    }
                }

                var onUpdate = this.callbacks.onUpdate;

                if (onUpdate)
                {
                    onUpdate.func.apply(onUpdate.scope, onUpdate.params);
                }

                //  Anything still running? If not, we're done
                if (stillRunning === 0)
                {
                    this.nextState();
                }

                break;

            case TWEEN_CONST.LOOP_DELAY:

                this.countdown -= delta;

                if (this.countdown <= 0)
                {
                    this.state = TWEEN_CONST.ACTIVE;
                }

                break;

            case TWEEN_CONST.COMPLETE_DELAY:

                this.countdown -= delta;

                if (this.countdown <= 0)
                {
                    var onComplete = this.callbacks.onComplete;

                    if (onComplete)
                    {
                        onComplete.func.apply(onComplete.scope, onComplete.params);
                    }

                    this.state = TWEEN_CONST.PENDING_REMOVE;
                }

                break;
        }

        return (this.state === TWEEN_CONST.PENDING_REMOVE);
    },

    //  Stops the Tween immediately, whatever stage of progress it is at and flags it for removal by the TweenManager
    stop: function ()
    {
        this.state = TWEEN_CONST.PENDING_REMOVE;
    },

    pause: function ()
    {
        if (this.state === TWEEN_CONST.PAUSED)
        {
            return;
        }

        this.paused = true;

        this._pausedState = this.state;

        this.state = TWEEN_CONST.PAUSED;

        return this;
    },

    resume: function ()
    {
        if (this.state === TWEEN_CONST.PAUSED)
        {
            this.paused = false;

            this.state = this._pausedState;
        }

        return this;
    },

    hasTarget: function ()
    {

    },

    destroy: function ()
    {

    }
});

Timeline.TYPES = [ 'onStart', 'onUpdate', 'onLoop', 'onComplete', 'onYoyo' ];

module.exports = Timeline;


var CONST = require('./const');

var AlignInMap = [];

AlignInMap[CONST.BOTTOM_CENTER] = require('./InBottomCenter');
AlignInMap[CONST.BOTTOM_LEFT] = require('./InBottomLeft');
AlignInMap[CONST.BOTTOM_RIGHT] = require('./InBottomRight');
AlignInMap[CONST.CENTER] = require('./InCenter');
AlignInMap[CONST.LEFT_CENTER] = require('./InLeftCenter');
AlignInMap[CONST.RIGHT_CENTER] = require('./InRightCenter');
AlignInMap[CONST.TOP_CENTER] = require('./InTopCenter');
AlignInMap[CONST.TOP_LEFT] = require('./InTopLeft');
AlignInMap[CONST.TOP_RIGHT] = require('./InTopRight');

var AlignIn = function (child, container, position, offsetX, offsetY)
{
    return AlignInMap[position](child, container, offsetX, offsetY);
};

module.exports = AlignIn;


var Friction = {

    setFrictionX: function (x)
    {
        this.friction.x = x;

        return this;
    },

    setFrictionY: function (y)
    {
        this.friction.y = y;

        return this;
    },

    setFriction: function (x, y)
    {
        this.friction.x = x;
        this.friction.y = y;

        return this;
    }

};

module.exports = Friction;


<!DOCTYPE html>

	<meta charset="utf-8">
	<title>Phaser Source: src/tilemap/Tile.js</title>

	<link type="text/css" rel="stylesheet" href="styles/default.css">

	<link type="text/css" rel="stylesheet" href="styles/sunlight.default.css">

	<link type="text/css" rel="stylesheet" href="styles/site.cerulean.css">

			Phaser API

					Namespaces

							Phaser

							PIXI

					Classes

							Event

							EventTarget

							Animation

							AnimationManager

							AnimationParser

							ArraySet

							ArrayUtils

							AudioSprite

							BitmapData

							BitmapText

							Bullet

							Button

							Cache

							Camera

							Canvas

							Circle

							Color

							Angle

							Animation

							AutoCull

							Bounds

							BringToTop

							Core

							Crop

							Delta

							Destroy

							FixedToCamera

							Health

							InCamera

							InputEnabled

							InWorld

							LifeSpan

							LoadTexture

							Overlap

							PhysicsBody

							Reset

							ScaleMinMax

							Smoothed

							Create

							Creature

							Device

							DeviceButton

							DOM

							Easing

							Back

							Bounce

							Circular

							Cubic

							Elastic

							Exponential

							Linear

							Quadratic

							Quartic

							Quintic

							Sinusoidal

							Ellipse

							Events

							Filter

							FlexGrid

							FlexLayer

							Frame

							FrameData

							Game

							GameObjectCreator

							GameObjectFactory

							Gamepad

							Graphics

							Group

							Hermite

							Image

							ImageCollection

							Input

							InputHandler

							Key

							Keyboard

							KeyCode

							Line

							LinkedList

							Loader

							LoaderParser

							Math

							Matrix

							Mouse

							MSPointer

							Net

							Particle

							Particles

							Arcade

							Emitter

							Path

							PathFollower

							PathPoint

							Physics

							Arcade

							Body

							TilemapCollision

							Ninja

							AABB

							Body

							Circle

							Tile

							P2

							Body

							BodyDebug

							CollisionGroup

							ContactMaterial

							DistanceConstraint

							FixtureList

							GearConstraint

							InversePointProxy

							LockConstraint

							Material

							PointProxy

							PrismaticConstraint

							RevoluteConstraint

							RotationalSpring

							Spring

							Plugin

							PathManager

							PluginManager

							Point

							Pointer

							PointerMode

							Polygon

							QuadTree

							RandomDataGenerator

							Rectangle

							RenderTexture

							RequestAnimationFrame

							RetroFont

							Rope

							RoundedRectangle

							ScaleManager

							Signal

							SignalBinding

							SinglePad

							Sound

							SoundManager

							Sprite

							SpriteBatch

							Stage

							State

							StateManager

							Text

							Tile

							Tilemap

							TilemapLayer

							TilemapParser

							Tileset

							TileSprite

							Time

							Timer

							TimerEvent

							Touch

							Tween

							TweenData

							TweenManager

							Utils

							Debug

							Video

							Weapon

							World

							AbstractFilter

							BaseTexture

							CanvasBuffer

							CanvasGraphics

							CanvasMaskManager

							CanvasPool

							CanvasRenderer

							CanvasTinter

							ComplexPrimitiveShader

							DisplayObjectContainer

							EarCut

							Event

							EventTarget

							FilterTexture

							Graphics

							GraphicsData

							PIXI

							DisplayObject

							PixiFastShader

							PixiShader

							PrimitiveShader

							RenderTexture

							Rope

							Sprite

							SpriteBatch

							Strip

							StripShader

							Texture

							TilingSprite

							WebGLBlendModeManager

							WebGLFastSpriteBatch

							WebGLFilterManager

							WebGLRenderer

					Global

							ANGLE_DOWN

							ANGLE_LEFT

							ANGLE_NORTH_EAST

							ANGLE_NORTH_WEST

							ANGLE_RIGHT

							ANGLE_SOUTH_EAST

							ANGLE_SOUTH_WEST

							ANGLE_UP

							AUTO

							BITMAPDATA

							BITMAPTEXT

							blendModes

							BOTTOM_CENTER

							BOTTOM_LEFT

							BOTTOM_RIGHT

							BUTTON

							CANVAS

							CANVAS_FILTER

							CENTER

							CIRCLE

							CREATURE

							displayList

							DOWN

							ELLIPSE

							emit

							EMITTER

							GAMES

							GRAPHICS

							GROUP

							HEADLESS

							HORIZONTAL

							IMAGE

							LANDSCAPE

							LEFT

							LEFT_BOTTOM

							LEFT_CENTER

							LEFT_TOP

							LINE

							listeners

							MATRIX

							mixin

							NONE

							off

							on

							once

							PENDING_ATLAS

							Phaser.Path#numPoints
return {number} The total number of PathPoints in this Path.

							POINT

							POINTER

							POLYGON

							PORTRAIT

							RECTANGLE

							removeAllListeners

							RENDERTEXTURE

							RETROFONT

							RIGHT

							RIGHT_BOTTOM

							RIGHT_CENTER

							RIGHT_TOP

							ROPE

							ROUNDEDRECTANGLE

							scaleModes

							SPRITE

							SPRITEBATCH

							stopImmediatePropagation

							stopPropagation

							TEXT

							TILEMAP

							TILEMAPLAYER

							TILESPRITE

							TOP_CENTER

							TOP_LEFT

							TOP_RIGHT

							UP

							VERSION

							VERTICAL

							VIDEO

							WEBGL

							WEBGL_FILTER

					Core

Game

Group

World

Loader

Cache

Time

Camera

State Manager

Tween Manager

Sound Manager

Input Manager

Scale Manager

					Game Objects

Factory (game.add)

Creator (game.make)

Sprite

Image

Sound

Video

Particle Emitter

Particle

Text

Tween

BitmapText

Tilemap

BitmapData

RetroFont

Button

Animation

Graphics

RenderTexture

TileSprite

					Geometry

Circle

Ellipse

Line

Matrix

Point

Polygon

Rectangle

Rounded Rectangle

					Physics

Arcade Physics

Body

Weapon

P2 Physics

Body

Spring

CollisionGroup

ContactMaterial

Ninja Physics

Body

					Input

Input Handler

Pointer

Device Button

Mouse

Keyboard

Key

Key Codes

Gamepad

					Community

Phaser Web Site

Phaser Github

Phaser Examples

Phaser Plugins

Forum

Stack Overflow

Tutorials

Newsletter

Twitter

Slack

Donate

Texture Packer

Source: src/tilemap/Tile.js

/**
* @author       Richard Davey <rich@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/

/**
* A Tile is a representation of a single tile within the Tilemap.
*
* @class Phaser.Tile
* @constructor
* @param {object} layer - The layer in the Tilemap data that this tile belongs to.
* @param {number} index - The index of this tile type in the core map data.
* @param {number} x - The x coordinate of this tile.
* @param {number} y - The y coordinate of this tile.
* @param {number} width - Width of the tile.
* @param {number} height - Height of the tile.
*/
Phaser.Tile = function (layer, index, x, y, width, height) {

    /**
    * @property {object} layer - The layer in the Tilemap data that this tile belongs to.
    */
    this.layer = layer;

    /**
    * @property {number} index - The index of this tile within the map data corresponding to the tileset, or -1 if this represents a blank/null tile.
    */
    this.index = index;

    /**
    * @property {number} x - The x map coordinate of this tile.
    */
    this.x = x;

    /**
    * @property {number} y - The y map coordinate of this tile.
    */
    this.y = y;

    /**
    * @property {number} rotation - The rotation angle of this tile.
    */
    this.rotation = 0;

    /**
    * @property {boolean} flipped - Whether this tile is flipped (mirrored) or not.
    */
    this.flipped = false;

    /**
    * @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.
    */
    this.width = width;

    /**
    * @property {number} height - The height of the tile in pixels.
    */
    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.
    */
    this.alpha = 1;

    /**
    * @property {object} properties - Tile specific properties.
    */
    this.properties = {};

    /**
    * @property {boolean} scanned - Has this tile been walked / turned into a poly?
    */
    this.scanned = false;

    /**
    * @property {boolean} faceTop - Is the top of this tile an interesting edge?
    */
    this.faceTop = false;

    /**
    * @property {boolean} faceBottom - Is the bottom of this tile an interesting edge?
    */
    this.faceBottom = false;

    /**
    * @property {boolean} faceLeft - Is the left of this tile an interesting edge?
    */
    this.faceLeft = false;

    /**
    * @property {boolean} faceRight - Is the right of this tile an interesting edge?
    */
    this.faceRight = false;

    /**
    * @property {boolean} collideLeft - Indicating collide with any object on the left.
    * @default
    */
    this.collideLeft = false;

    /**
    * @property {boolean} collideRight - Indicating collide with any object on the right.
    * @default
    */
    this.collideRight = false;

    /**
    * @property {boolean} collideUp - Indicating collide with any object on the top.
    * @default
    */
    this.collideUp = false;

    /**
    * @property {boolean} collideDown - Indicating collide with any object on the bottom.
    * @default
    */
    this.collideDown = false;

    /**
    * @property {function} collisionCallback - Tile collision callback.
    * @default
    */
    this.collisionCallback = null;

    /**
    * @property {object} collisionCallbackContext - The context in which the collision callback will be called.
    * @default
    */
    this.collisionCallbackContext = this;

};

Phaser.Tile.prototype = {

    /**
    * Check if the given x and y world coordinates are within this Tile.
    *
    * @method Phaser.Tile#containsPoint
    * @param {number} x - The x coordinate to test.
    * @param {number} y - The y coordinate to test.
    * @return {boolean} True if the coordinates are within this Tile, otherwise false.
    */
    containsPoint: function (x, y) {

        return !(x < this.worldX || y < this.worldY || x > this.right || y > this.bottom);

    },

    /**
    * Check for intersection with this tile.
    *
    * @method Phaser.Tile#intersects
    * @param {number} x - The x axis in pixels.
    * @param {number} y - The y axis in pixels.
    * @param {number} right - The right point.
    * @param {number} bottom - The bottom point.
    */
    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.
    *
    * @method Phaser.Tile#setCollisionCallback
    * @param {function} callback - Callback function.
    * @param {object} context - Callback will be called within this context.
    */
    setCollisionCallback: function (callback, context) {

        this.collisionCallback = callback;
        this.collisionCallbackContext = context;

    },

    /**
    * Clean up memory.
    *
    * @method Phaser.Tile#destroy
    */
    destroy: function () {

        this.collisionCallback = null;
        this.collisionCallbackContext = null;
        this.properties = null;

    },

    /**
    * Sets the collision flags for each side of this tile and updates the interesting faces list.
    *
    * @method Phaser.Tile#setCollision
    * @param {boolean} left - Indicating collide with any object on the left.
    * @param {boolean} right - Indicating collide with any object on the right.
    * @param {boolean} up - Indicating collide with any object on the top.
    * @param {boolean} down - Indicating collide with any object on the bottom.
    */
    setCollision: function (left, right, up, down) {

        this.collideLeft = left;
        this.collideRight = right;
        this.collideUp = up;
        this.collideDown = down;

        this.faceLeft = left;
        this.faceRight = right;
        this.faceTop = up;
        this.faceBottom = down;

    },

    /**
    * Reset collision status flags.
    *
    * @method Phaser.Tile#resetCollision
    */
    resetCollision: function () {

        this.collideLeft = false;
        this.collideRight = false;
        this.collideUp = false;
        this.collideDown = false;

        this.faceTop = false;
        this.faceBottom = false;
        this.faceLeft = false;
        this.faceRight = false;

    },

    /**
    * Is this tile interesting?
    *
    * @method Phaser.Tile#isInteresting
    * @param {boolean} collides - If true will check any collides value.
    * @param {boolean} faces - If true will check any face value.
    * @return {boolean} True if the Tile is interesting, otherwise false.
    */
    isInteresting: function (collides, faces) {

        if (collides && faces)
        {
            //  Does this tile have any collide flags OR interesting face?
            return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown || this.faceTop || this.faceBottom || this.faceLeft || this.faceRight || this.collisionCallback);
        }
        else if (collides)
        {
            //  Does this tile collide?
            return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown);
        }
        else if (faces)
        {
            //  Does this tile have an interesting face?
            return (this.faceTop || this.faceBottom || this.faceLeft || this.faceRight);
        }

        return false;

    },

    /**
    * Copies the tile data and properties from the given tile to this tile.
    *
    * @method Phaser.Tile#copy
    * @param {Phaser.Tile} tile - The tile to copy from.
    */
    copy: function (tile) {

        this.index = tile.index;
        this.alpha = tile.alpha;
        this.properties = tile.properties;

        this.collideUp = tile.collideUp;
        this.collideDown = tile.collideDown;
        this.collideLeft = tile.collideLeft;
        this.collideRight = tile.collideRight;

        this.collisionCallback = tile.collisionCallback;
        this.collisionCallbackContext = tile.collisionCallbackContext;

    }

};

Phaser.Tile.prototype.constructor = Phaser.Tile;

/**
* @name Phaser.Tile#collides
* @property {boolean} collides - True if this tile can collide on any of its faces.
* @readonly
*/
Object.defineProperty(Phaser.Tile.prototype, "collides", {

    get: function () {
        return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown);
    }

});

/**
* @name Phaser.Tile#canCollide
* @property {boolean} canCollide - True if this tile can collide on any of its faces or has a collision callback set.
* @readonly
*/
Object.defineProperty(Phaser.Tile.prototype, "canCollide", {

    get: function () {
        return (this.collideLeft || this.collideRight || this.collideUp || this.collideDown || this.collisionCallback);
    }

});

/**
* @name Phaser.Tile#left
* @property {number} left - The x value in pixels.
* @readonly
*/
Object.defineProperty(Phaser.Tile.prototype, "left", {

    get: function () {
        return this.worldX;
    }

});

/**
* @name Phaser.Tile#right
* @property {number} right - The sum of the x and width properties.
* @readonly
*/
Object.defineProperty(Phaser.Tile.prototype, "right", {

    get: function () {
        return this.worldX + this.width;
    }

});

/**
* @name Phaser.Tile#top
* @property {number} top - The y value.
* @readonly
*/
Object.defineProperty(Phaser.Tile.prototype, "top", {

    get: function () {
        return this.worldY;
    }

});

/**
* @name Phaser.Tile#bottom
* @property {number} bottom - The sum of the y and height properties.
* @readonly
*/
Object.defineProperty(Phaser.Tile.prototype, "bottom", {

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

});

		Phaser Copyright © 2012-2016 Photon Storm Ltd.

		Documentation generated by JSDoc 3.4.0
		on Fri Aug 26 2016 01:16:09 GMT+0100 (BST) using the DocStrap template.


return this;
},
hasTarget: function ()
{


/**
* @author       Richard Davey <rich@photonstorm.com>
* @copyright    2016 Photon Storm Ltd.
* @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*
* @overview
*
* Phaser - http://phaser.io
*
* v<%= package.version %> "<%= package.release %>" - Built: <%= grunt.template.today() %>
*
* By Richard Davey http://www.photonstorm.com @photonstorm
*
* Phaser is a fun, free and fast 2D game framework for making HTML5 games
* for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
*
* Phaser uses Pixi.js for rendering, created by Mat Groves http://matgroves.com @Doormat23
* Phaser uses p2.js for full-body physics, created by Stefan Hedman https://github.com/schteppe/p2.js @schteppe
* Phaser contains a port of N+ Physics, converted by Richard Davey, original by http://www.metanetsoftware.com
*
* Many thanks to Adam Saltsman (@ADAMATOMIC) for releasing Flixel, from which both Phaser and my love of framework development originate.
*
* Follow development at http://phaser.io and on our forum
*
* "If you want your children to be intelligent,  read them fairy tales."
* "If you want them to be more intelligent, read them more fairy tales."
*                                                     -- Albert Einstein
*/


Phaser.Physics.Ninja

Ninja Physics. The Ninja Physics system was created in Flash by Metanet Software and ported to JavaScript by Richard Davey.\n\nIt allows for AABB and Circle to Tile collision. Tiles can be any of 34 different types, including slopes, convex and concave shapes.\n\nIt does what it does very well, but is ripe for expansion and optimisation. Here are some features that I'd love to see the community add:\n\n* AABB to AABB collision\n* AABB to Circle collision\n* AABB and Circle 'immovable' property support\n* n-way collision, so an AABB/Circle could pass through a tile from below and land upon it.\n* QuadTree or spatial grid for faster Body vs. Tile Group look-ups.\n* Optimise the internal vector math and reduce the quantity of temporary vars created.\n* Expand Gravity and Bounce to allow for separate x/y axis values.\n* Support Bodies linked to Sprites that don't have anchor set to 0.5\n\nFeel free to attempt any of the above and submit a Pull Request with your code! Be sure to include test cases proving they work.

clearTilemapLayerBodies

Clears all physics bodies from the given TilemapLayer that were created with `World.convertTilemap`.

layer

The layer to operate on. If not given will default to map.currentLayer.

collide

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.\nThe second parameter can be an array of objects, of differing types.\nThe objects are also automatically separated. If you don't require separation then use ArcadePhysics.overlap instead.\nAn 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,\ngiving 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.\nThe 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.

The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter, or Phaser.TilemapLayer.

The second object or array of objects to check. Can be Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.TilemapLayer.

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.

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.

callbackContext

The context in which to run the callbacks.

convertTilemap

An array of the Phaser.Physics.Ninja.Tile objects that were created.

Goes through all tiles in the given Tilemap and TilemapLayer and converts those set to collide into physics tiles.\nOnly call this *after* you have specified all of the tiles you wish to collide with calls like Tilemap.setCollisionBetween, etc.\nEvery time you call this method it will destroy any previously created bodies and remove them from the world.\nTherefore understand it's a very expensive operation and not to be done in a core game update loop.\n\nIn Ninja the Tiles have an ID from 0 to 33, where 0 is 'empty', 1 is a full tile, 2 is a 45-degree slope, etc. You can find the ID\nlist either at the very bottom of `Tile.js`, or in a handy visual reference in the `resources/Ninja Physics Debug Tiles` folder in the repository.\nThe slopeMap parameter is an array that controls how the indexes of the tiles in your tilemap data will map to the Ninja Tile IDs.\nFor example if you had 6 tiles in your tileset: Imagine the first 4 should be converted into fully solid Tiles and the other 2 are 45-degree slopes.\nYour slopeMap array would look like this: `[ 1, 1, 1, 1, 2, 3 ]`.\nWhere each element of the array is a tile in your tilemap and the resulting Ninja Tile it should create.

enable

This will create a Ninja Physics body on the given game object or array of game objects.\nA game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.

object

The game object to create the physics body on. Can also be an array or Group of objects, a body will be created on every child that has a `body` property.

type

The type of Ninja shape to create. 1 = AABB, 2 = Circle or 3 = Tile.

id

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.

radius

If this body is using a Circle shape this controls the radius.

children

Should a body be created on all children of this object? If true it will recurse down the display list as far as it can go.

enableAABB

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.\nA game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.

enableBody

Creates a Ninja Physics body on the given game object.\nA game object can only have 1 physics body active at any one time, and it can't be changed until the body is nulled.

object

The game object to create the physics body on. A body will only be created if this object has a null `body` property.

enableCircle

This will create a Ninja Physics Circle body on the given game object.\nA game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.

enableTile

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,\nconvex and concave circles and more. The id parameter controls which Tile type is created, but you can also change it at run-time.\nNote 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.\nA game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.

id

The type of Tile this will use, i.e. Phaser.Physics.Ninja.Tile.SLOPE_45DEGpn, Phaser.Physics.Ninja.Tile.CONVEXpp, etc.

overlap

Checks for overlaps between two game objects. The objects can be Sprites, Groups or Emitters.\nYou can perform Sprite vs. Sprite, Sprite vs. Group and Group vs. Group overlap checks.\nUnlike collide the objects are NOT automatically separated or have any physics applied, they merely test for overlap results.\nThe second parameter can be an array of objects, of differing types.

The first object to check. Can be an instance of Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter.

The second object or array of objects to check. Can be Phaser.Sprite, Phaser.Group or Phaser.Particles.Emitter.

overlapCallback

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.

processCallback

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.

separate

The core separation function to separate two physics bodies.

setBounds

width

New width of the world. Can never be smaller than the Game.width.

height

New height of the world. Can never be smaller than the Game.height.

setBoundsToWorld

Updates the size of this physics world to match the size of the game world.

collideGroupVsGroup

An internal function. Use Phaser.Physics.Ninja.collide instead.

collideHandler

The second object to check. Can be an instance of Phaser.Sprite, Phaser.Group, Phaser.Particles.Emitter or Phaser.TilemapLayer. Can also be an array of objects to check.

overlapOnly

Just run an overlap or a full collision.

bounds

The bounds inside of which the physics world exists. Defaults to match the world bounds.

maxLevels

Used by the QuadTree to set the maximum number of iteration levels.

maxObjects

Used by the QuadTree to set the maximum number of objects per quad.


//  Return a string containing a hex representation of the given color component.
//  @param {integer} color - The color channel to get the hex value for, must be a value between 0 and 255.
//  @return {string} A string of length 2 characters, i.e. 255 = ff, 100 = 64.
var ComponentToHex = function (color)
{
    var hex = color.toString(16);

    return (hex.length === 1) ? '0' + hex : hex;
};

module.exports = ComponentToHex;


for (var i = 0; i < this.data.length; i++)