UNPKG

phaser-ce

Version:

Phaser CE (Community Edition) is a fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.

1,846 lines (1,544 loc) 2.73 MB
/** * @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 * * v2.9.2 "2017-11-09" - Built: Thu Nov 09 2017 18:06:05 * * 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 */ /** * @author Richard Davey <rich@photonstorm.com> * @copyright 2016 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ (function(){ var root = this; /** * @author Richard Davey <rich@photonstorm.com> * @copyright 2016 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ /** * @namespace Phaser */ var Phaser = Phaser || { // jshint ignore:line /** * The Phaser version number. * @constant Phaser.VERSION * @type {string} */ VERSION: '2.9.2', /** * An array of Phaser game instances. * @constant Phaser.GAMES * @type {array} */ GAMES: [], /** * AUTO renderer - picks between WebGL or Canvas based on device. * @constant Phaser.AUTO * @type {integer} */ AUTO: 0, /** * Canvas Renderer. * @constant Phaser.CANVAS * @type {integer} */ CANVAS: 1, /** * WebGL Renderer. * @constant Phaser.WEBGL * @type {integer} */ WEBGL: 2, /** * Headless renderer (not visual output) * @constant Phaser.HEADLESS * @type {integer} */ HEADLESS: 3, /** * WebGL Renderer with MultiTexture support enabled. * @constant Phaser.WEBGL_MULTI * @type {integer} */ WEBGL_MULTI: 4, /** * Direction constant. * @constant Phaser.NONE * @type {integer} */ NONE: 0, /** * Direction constant. * @constant Phaser.LEFT * @type {integer} */ LEFT: 1, /** * Direction constant. * @constant Phaser.RIGHT * @type {integer} */ RIGHT: 2, /** * Direction constant. * @constant Phaser.UP * @type {integer} */ UP: 3, /** * Direction constant. * @constant Phaser.DOWN * @type {integer} */ DOWN: 4, /** * Game Object type. * @constant Phaser.SPRITE * @type {integer} */ SPRITE: 0, /** * Game Object type. * @constant Phaser.BUTTON * @type {integer} */ BUTTON: 1, /** * Game Object type. * @constant Phaser.IMAGE * @type {integer} */ IMAGE: 2, /** * Game Object type. * @constant Phaser.GRAPHICS * @type {integer} */ GRAPHICS: 3, /** * Game Object type. * @constant Phaser.TEXT * @type {integer} */ TEXT: 4, /** * Game Object type. * @constant Phaser.TILESPRITE * @type {integer} */ TILESPRITE: 5, /** * Game Object type. * @constant Phaser.BITMAPTEXT * @type {integer} */ BITMAPTEXT: 6, /** * Game Object type. * @constant Phaser.GROUP * @type {integer} */ GROUP: 7, /** * Game Object type. * @constant Phaser.RENDERTEXTURE * @type {integer} */ RENDERTEXTURE: 8, /** * Game Object type. * @constant Phaser.TILEMAP * @type {integer} */ TILEMAP: 9, /** * Game Object type. * @constant Phaser.TILEMAPLAYER * @type {integer} */ TILEMAPLAYER: 10, /** * Game Object type. * @constant Phaser.EMITTER * @type {integer} */ EMITTER: 11, /** * Game Object type. * @constant Phaser.POLYGON * @type {integer} */ POLYGON: 12, /** * Game Object type. * @constant Phaser.BITMAPDATA * @type {integer} */ BITMAPDATA: 13, /** * Game Object type. * @constant Phaser.CANVAS_FILTER * @type {integer} */ CANVAS_FILTER: 14, /** * Game Object type. * @constant Phaser.WEBGL_FILTER * @type {integer} */ WEBGL_FILTER: 15, /** * Game Object type. * @constant Phaser.ELLIPSE * @type {integer} */ ELLIPSE: 16, /** * Game Object type. * @constant Phaser.SPRITEBATCH * @type {integer} */ SPRITEBATCH: 17, /** * Game Object type. * @constant Phaser.RETROFONT * @type {integer} */ RETROFONT: 18, /** * Game Object type. * @constant Phaser.POINTER * @type {integer} */ POINTER: 19, /** * Game Object type. * @constant Phaser.ROPE * @type {integer} */ ROPE: 20, /** * Game Object type. * @constant Phaser.CIRCLE * @type {integer} */ CIRCLE: 21, /** * Game Object type. * @constant Phaser.RECTANGLE * @type {integer} */ RECTANGLE: 22, /** * Game Object type. * @constant Phaser.LINE * @type {integer} */ LINE: 23, /** * Game Object type. * @constant Phaser.MATRIX * @type {integer} */ MATRIX: 24, /** * Game Object type. * @constant Phaser.POINT * @type {integer} */ POINT: 25, /** * Game Object type. * @constant Phaser.ROUNDEDRECTANGLE * @type {integer} */ ROUNDEDRECTANGLE: 26, /** * Game Object type. * @constant Phaser.CREATURE * @type {integer} */ CREATURE: 27, /** * Game Object type. * @constant Phaser.VIDEO * @type {integer} */ VIDEO: 28, /** * Game Object type. * @constant Phaser.PENDING_ATLAS * @type {integer} */ PENDING_ATLAS: -1, /** * A horizontal orientation * @constant Phaser.HORIZONTAL * @type {integer} */ HORIZONTAL: 0, /** * A vertical orientation * @constant Phaser.VERTICAL * @type {integer} */ VERTICAL: 1, /** * A landscape orientation * @constant Phaser.LANDSCAPE * @type {integer} */ LANDSCAPE: 0, /** * A portrait orientation * @constant Phaser.PORTRAIT * @type {integer} */ PORTRAIT: 1, /** * The Angle (in degrees) a Game Object needs to be set to in order to face up. * @constant Phaser.ANGLE_UP * @type {integer} */ ANGLE_UP: 270, /** * The Angle (in degrees) a Game Object needs to be set to in order to face down. * @constant Phaser.ANGLE_DOWN * @type {integer} */ ANGLE_DOWN: 90, /** * The Angle (in degrees) a Game Object needs to be set to in order to face left. * @constant Phaser.ANGLE_LEFT * @type {integer} */ ANGLE_LEFT: 180, /** * The Angle (in degrees) a Game Object needs to be set to in order to face right. * @constant Phaser.ANGLE_RIGHT * @type {integer} */ ANGLE_RIGHT: 0, /** * The Angle (in degrees) a Game Object needs to be set to in order to face north east. * @constant Phaser.ANGLE_NORTH_EAST * @type {integer} */ ANGLE_NORTH_EAST: 315, /** * The Angle (in degrees) a Game Object needs to be set to in order to face north west. * @constant Phaser.ANGLE_NORTH_WEST * @type {integer} */ ANGLE_NORTH_WEST: 225, /** * The Angle (in degrees) a Game Object needs to be set to in order to face south east. * @constant Phaser.ANGLE_SOUTH_EAST * @type {integer} */ ANGLE_SOUTH_EAST: 45, /** * The Angle (in degrees) a Game Object needs to be set to in order to face south west. * @constant Phaser.ANGLE_SOUTH_WEST * @type {integer} */ ANGLE_SOUTH_WEST: 135, /** * A constant representing a top-left alignment or position. * @constant Phaser.TOP_LEFT * @type {integer} */ TOP_LEFT: 0, /** * A constant representing a top-center alignment or position. * @constant Phaser.TOP_CENTER * @type {integer} */ TOP_CENTER: 1, /** * A constant representing a top-right alignment or position. * @constant Phaser.TOP_RIGHT * @type {integer} */ TOP_RIGHT: 2, /** * A constant representing a left-top alignment or position. * @constant Phaser.Phaser.LEFT_TOP * @type {integer} */ LEFT_TOP: 3, /** * A constant representing a left-center alignment or position. * @constant Phaser.LEFT_TOP * @type {integer} */ LEFT_CENTER: 4, /** * A constant representing a left-bottom alignment or position. * @constant Phaser.LEFT_BOTTOM * @type {integer} */ LEFT_BOTTOM: 5, /** * A constant representing a center alignment or position. * @constant Phaser.CENTER * @type {integer} */ CENTER: 6, /** * A constant representing a right-top alignment or position. * @constant Phaser.RIGHT_TOP * @type {integer} */ RIGHT_TOP: 7, /** * A constant representing a right-center alignment or position. * @constant Phaser.RIGHT_CENTER * @type {integer} */ RIGHT_CENTER: 8, /** * A constant representing a right-bottom alignment or position. * @constant Phaser.RIGHT_BOTTOM * @type {integer} */ RIGHT_BOTTOM: 9, /** * A constant representing a bottom-left alignment or position. * @constant Phaser.BOTTOM_LEFT * @type {integer} */ BOTTOM_LEFT: 10, /** * A constant representing a bottom-center alignment or position. * @constant Phaser.BOTTOM_CENTER * @type {integer} */ BOTTOM_CENTER: 11, /** * A constant representing a bottom-right alignment or position. * @constant Phaser.BOTTOM_RIGHT * @type {integer} */ BOTTOM_RIGHT: 12, /** * Various blend modes supported by Pixi. See the samples in {@link https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing Canvas Tutorial: Compositing}. * * IMPORTANT: The WebGL renderer only supports the NORMAL, ADD, MULTIPLY and SCREEN blend modes. * * @constant {Object} Phaser.blendModes * @property {Number} blendModes.NORMAL - Draws new shapes on top of the existing content. This is the default setting. * @property {Number} blendModes.ADD - Where both shapes overlap the color is determined by adding color values. * @property {Number} blendModes.MULTIPLY - The pixels of the top layer are multiplied with the corresponding pixel of the bottom layer, making a darker picture. * @property {Number} blendModes.SCREEN - The pixels are inverted, multiplied, and inverted again, making a lighter picture. * @property {Number} blendModes.OVERLAY * @property {Number} blendModes.DARKEN * @property {Number} blendModes.LIGHTEN * @property {Number} blendModes.COLOR_DODGE * @property {Number} blendModes.COLOR_BURN * @property {Number} blendModes.HARD_LIGHT * @property {Number} blendModes.SOFT_LIGHT * @property {Number} blendModes.DIFFERENCE * @property {Number} blendModes.EXCLUSION * @property {Number} blendModes.HUE * @property {Number} blendModes.SATURATION * @property {Number} blendModes.COLOR * @property {Number} blendModes.LUMINOSITY * @static */ blendModes: { NORMAL: 0, ADD: 1, MULTIPLY: 2, SCREEN: 3, OVERLAY: 4, DARKEN: 5, LIGHTEN: 6, COLOR_DODGE: 7, COLOR_BURN: 8, HARD_LIGHT: 9, SOFT_LIGHT: 10, DIFFERENCE: 11, EXCLUSION: 12, HUE: 13, SATURATION: 14, COLOR: 15, LUMINOSITY: 16 }, /** * The scale modes that are supported by Pixi. * * The DEFAULT scale mode affects the default scaling mode of future operations. * It can be re-assigned to either LINEAR or NEAREST, depending upon suitability. * * @constant {Object} Phaser.scaleModes * @property {Number} Phaser.scaleModes.DEFAULT=LINEAR * @property {Number} Phaser.scaleModes.LINEAR Smooth scaling * @property {Number} Phaser.scaleModes.NEAREST Pixelating scaling * @static */ scaleModes: { DEFAULT: 0, LINEAR: 0, NEAREST: 1 }, PIXI: PIXI || {}, // Used to create IDs for various Pixi objects. _UID: 0 }; /** * @copyright 2016 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ // ES6 Math.trunc - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc if (!Math.trunc) { Math.trunc = function trunc(x) { return x < 0 ? Math.ceil(x) : Math.floor(x); }; } /** * A polyfill for Function.prototype.bind */ if (!Function.prototype.bind) { /* jshint freeze: false */ Function.prototype.bind = (function () { var slice = Array.prototype.slice; return function (thisArg) { var target = this, boundArgs = slice.call(arguments, 1); if (typeof target !== 'function') { throw new TypeError(); } function bound() { var args = boundArgs.concat(slice.call(arguments)); target.apply(this instanceof bound ? this : thisArg, args); } bound.prototype = (function F(proto) { if (proto) { F.prototype = proto; } if (!(this instanceof F)) { /* jshint supernew: true */ return new F; } })(target.prototype); return bound; }; })(); } /** * A polyfill for Array.isArray */ if (!Array.isArray) { Array.isArray = function (arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; } /** * A polyfill for Array.forEach * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach */ if (!Array.prototype.forEach) { Array.prototype.forEach = function(fun /*, thisArg */) { "use strict"; if (this === void 0 || this === null) { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; if (typeof fun !== "function") { throw new TypeError(); } var thisArg = arguments.length >= 2 ? arguments[1] : void 0; for (var i = 0; i < len; i++) { if (i in t) { fun.call(thisArg, t[i], i, t); } } }; } /** * Low-budget Float32Array knock-off, suitable for use with P2.js in IE9 * Source: http://www.html5gamedevs.com/topic/5988-phaser-12-ie9/ * Cameron Foale (http://www.kibibu.com) */ if (typeof window.Uint32Array !== "function" && typeof window.Uint32Array !== "object") { var CheapArray = function(type) { var proto = new Array(); // jshint ignore:line window[type] = function(arg) { if (typeof(arg) === "number") { Array.call(this, arg); this.length = arg; for (var i = 0; i < this.length; i++) { this[i] = 0; } } else { Array.call(this, arg.length); this.length = arg.length; for (var i = 0; i < this.length; i++) { this[i] = arg[i]; } } }; window[type].prototype = proto; window[type].constructor = window[type]; }; CheapArray('Float32Array'); // jshint ignore:line CheapArray('Uint32Array'); // jshint ignore:line CheapArray('Uint16Array'); // jshint ignore:line CheapArray('Int16Array'); // jshint ignore:line CheapArray('ArrayBuffer'); // jshint ignore:line } /** * Also fix for the absent console in IE9 */ if (!window.console) { window.console = {}; window.console.log = window.console.assert = function(){}; window.console.warn = window.console.assert = function(){}; } /** * Fix for Object.assign not existing on older devices */ if (!Object.assign) { /* jshint -W098 */ // We include `varArgs` (unused) to ensure Object.assign.length === 2 Object.assign = function(target, varArgs) { /* jshint +W098 */ 'use strict'; if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); var hasOwn = Object.prototype.hasOwnProperty; for (var index = 1; index < arguments.length; index++) { var nextSource = arguments[index]; if (nextSource != null) { // Skip over if undefined or null for (var nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (hasOwn.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }; } /** * @author Richard Davey <rich@photonstorm.com> * @copyright 2016 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ /** * @class Phaser.Utils * @static */ Phaser.Utils = { /** * Takes the given string and reverses it, returning the reversed string. * For example if given the string `Atari 520ST` it would return `TS025 iratA`. * * @method Phaser.Utils.reverseString * @param {string} string - The string to be reversed. * @return {string} The reversed string. */ reverseString: function (string) { return string.split('').reverse().join(''); }, /** * Gets an object's property by string. * * @method Phaser.Utils.getProperty * @param {object} obj - The object to traverse. * @param {string} prop - The property whose value will be returned. * @return {any} - The value of the property or `undefined` if the property isn't found. */ getProperty: function(obj, prop) { var parts = prop.split('.'), len = parts.length, i = 0, val = obj; while (i < len) { var key = parts[i]; if (val != null) { val = val[key]; i++; } else { return undefined; } } return val; }, /** * Sets an object's properties from a map of property names and values. * * ```javascript * Phaser.Utils.setProperties(sprite, { * 'animations.paused': true, * 'body.enable': false, * 'input.draggable': true, * }); * ``` * * @method Phaser.Utils.setProperties * @param {object} obj - The object to modify. * @param {object} props - The property names and values to set on the object (see {@link #setProperty}). * @return {object} The modified object. */ setProperties: function(obj, props) { for (var name in props) { this.setProperty(obj, name, props[name]); } return obj; }, /** * Sets an object's property by name and value. * * ```javascript * Phaser.Utils.setProperty(sprite, 'body.velocity.x', 60); * ``` * * @method Phaser.Utils.setProperty * @param {object} obj - The object to modify. * @param {string} name - The property name, or a series of names separated by `.` (for nested properties). * @param {any} value - The value. * @return {object} The modified object. */ setProperty: function(obj, name, value) { var parts = name.split('.'); switch (parts.length) { case 1: obj[name] = value; break; case 2: obj[parts[0]][parts[1]] = value; break; case 3: obj[parts[0]][parts[1]][parts[2]] = value; break; case 4: obj[parts[0]][parts[1]][parts[2]][parts[3]] = value; break; default: this._setProperty(obj, name, value); } }, /** * Sets an object's property by name and value. * * @private * @method Phaser.Utils._setProperty * @param {object} obj - The object to modify. * @param {string} name - The property name, or a series of names separated by `.` (for nested properties). * @param {any} value - The value. * @return {object} The modified object. */ _setProperty: function(obj, name, value) { var parts = name.split('.'), len = parts.length, i = 0, currentObj = obj, key = parts[0]; if (len === 1) { obj[name] = value; } else { while (i < (len - 1)) { currentObj = currentObj[key]; i++; key = parts[i]; } currentObj[key] = value; } return obj; }, /** * Generate a random bool result based on the chance value. * * Returns true or false based on the chance value (default 50%). For example if you wanted a player to have a 30% chance * of getting a bonus, call chanceRoll(30) - true means the chance passed, false means it failed. * * @method Phaser.Utils#chanceRoll * @param {number} chance - The chance of receiving the value. A number between 0 and 100 (effectively 0% to 100%). * @return {boolean} True if the roll passed, or false otherwise. */ chanceRoll: function (chance) { if (chance === undefined) { chance = 50; } return chance > 0 && (Math.random() * 100 <= chance); }, /** * Choose between one of two values randomly. * * @method Phaser.Utils#randomChoice * @param {any} choice1 * @param {any} choice2 * @return {any} The randomly selected choice */ randomChoice: function (choice1, choice2) { return (Math.random() < 0.5) ? choice1 : choice2; }, /** * Get a unit dimension from a string. * * @method Phaser.Utils.parseDimension * @param {string|number} size - The size to parse. * @param {number} dimension - The window dimension to check. * @return {number} The parsed dimension. */ parseDimension: function (size, dimension) { var f = 0; var px = 0; if (typeof size === 'string') { // %? if (size.substr(-1) === '%') { f = parseInt(size, 10) / 100; if (dimension === 0) { px = window.innerWidth * f; } else { px = window.innerHeight * f; } } else { px = parseInt(size, 10); } } else { px = size; } return px; }, /** * Takes the given string and pads it out, to the length required, using the character * specified. For example if you need a string to be 6 characters long, you can call: * * `pad('bob', 6, '-', 2)` * * This would return: `bob---` as it has padded it out to 6 characters, using the `-` on the right. * * You can also use it to pad numbers (they are always returned as strings): * * `pad(512, 6, '0', 1)` * * Would return: `000512` with the string padded to the left. * * If you don't specify a direction it'll pad to both sides: * * `pad('c64', 7, '*')` * * Would return: `**c64**` * * @method Phaser.Utils.pad * @param {string} str - The target string. `toString()` will be called on the string, which means you can also pass in common data types like numbers. * @param {integer} [len=0] - The number of characters to be added. * @param {string} [pad=" "] - The string to pad it out with (defaults to a space). * @param {integer} [dir=3] - The direction dir = 1 (left), 2 (right), 3 (both). * @return {string} The padded string. */ pad: function (str, len, pad, dir) { if (len === undefined) { var len = 0; } if (pad === undefined) { var pad = ' '; } if (dir === undefined) { var dir = 3; } str = str.toString(); var padlen = 0; if (len + 1 >= str.length) { switch (dir) { case 1: str = new Array(len + 1 - str.length).join(pad) + str; break; case 3: var right = Math.ceil((padlen = len - str.length) / 2); var left = padlen - right; str = new Array(left+1).join(pad) + str + new Array(right+1).join(pad); break; default: str = str + new Array(len + 1 - str.length).join(pad); break; } } return str; }, /** * This is a slightly modified version of jQuery.isPlainObject. * A plain object is an object whose internal class property is [object Object]. * @method Phaser.Utils.isPlainObject * @param {object} obj - The object to inspect. * @return {boolean} - true if the object is plain, otherwise false. */ isPlainObject: function (obj) { // Not plain objects: // - Any object or value whose internal [[Class]] property is not "[object Object]" // - DOM nodes // - window if (typeof(obj) !== "object" || obj.nodeType || obj === obj.window) { return false; } // Support: Firefox <20 // The try/catch suppresses exceptions thrown when attempting to access // the "constructor" property of certain host objects, ie. |window.location| // https://bugzilla.mozilla.org/show_bug.cgi?id=814622 try { if (obj.constructor && !({}).hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) { return false; } } catch (e) { return false; } // If the function hasn't returned already, we're confident that // |obj| is a plain object, created by {} or constructed with new Object return true; }, /** * This is a slightly modified version of http://api.jquery.com/jQuery.extend/ * * @method Phaser.Utils.extend * @param {boolean} deep - Perform a deep copy? * @param {object} target - The target object to copy to. * @return {object} The extended object. */ extend: function () { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if (typeof target === "boolean") { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // extend Phaser if only one argument is passed if (length === i) { target = this; --i; } for (; i < length; i++) { // Only deal with non-null/undefined values if ((options = arguments[i]) != null) { // Extend the base object for (name in options) { src = target[name]; copy = options[name]; // Prevent never-ending loop if (target === copy) { continue; } // Recurse if we're merging plain objects or arrays if (deep && copy && (Phaser.Utils.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { if (copyIsArray) { copyIsArray = false; clone = src && Array.isArray(src) ? src : []; } else { clone = src && Phaser.Utils.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[name] = Phaser.Utils.extend(deep, clone, copy); // Don't bring in undefined values } else if (copy !== undefined) { target[name] = copy; } } } } // Return the modified object return target; }, /** * Mixes in an existing mixin object with the target. * * Values in the mixin that have either `get` or `set` functions are created as properties via `defineProperty` * _except_ if they also define a `clone` method - if a clone method is defined that is called instead and * the result is assigned directly. * * @method Phaser.Utils.mixinPrototype * @param {object} target - The target object to receive the new functions. * @param {object} mixin - The object to copy the functions from. * @param {boolean} [replace=false] - If the target object already has a matching function should it be overwritten or not? */ mixinPrototype: function (target, mixin, replace) { if (replace === undefined) { replace = false; } var mixinKeys = Object.keys(mixin); for (var i = 0; i < mixinKeys.length; i++) { var key = mixinKeys[i]; var value = mixin[key]; if (!replace && (key in target)) { // Not overwriting existing property continue; } else { if (value && (typeof value.get === 'function' || typeof value.set === 'function')) { // Special case for classes like Phaser.Point which has a 'set' function! if (typeof value.clone === 'function') { target[key] = value.clone(); } else { Object.defineProperty(target, key, value); } } else { target[key] = value; } } } }, /** * Mixes the source object into the destination object, returning the newly modified destination object. * Based on original code by @mudcube * * @method Phaser.Utils.mixin * @param {object} from - The object to copy (the source object). * @param {object} to - The object to copy to (the destination object). * @return {object} The modified destination object. */ mixin: function (from, to) { if (!from || typeof (from) !== "object") { return to; } for (var key in from) { var o = from[key]; if (o.childNodes || o.cloneNode) { continue; } var type = typeof (from[key]); if (!from[key] || type !== "object") { to[key] = from[key]; } else { // Clone sub-object if (typeof (to[key]) === type) { to[key] = Phaser.Utils.mixin(from[key], to[key]); } else { to[key] = Phaser.Utils.mixin(from[key], new o.constructor()); } } } return to; } }; /** * @author Richard Davey <rich@photonstorm.com> * @copyright 2016 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ /** * Creates a new Circle object with the center coordinate specified by the x and y parameters and the diameter specified by the diameter parameter. * If you call this function without parameters, a circle with x, y, diameter and radius properties set to 0 is created. * * @class Phaser.Circle * @constructor * @param {number} [x=0] - The x coordinate of the center of the circle. * @param {number} [y=0] - The y coordinate of the center of the circle. * @param {number} [diameter=0] - The diameter of the circle. */ Phaser.Circle = function (x, y, diameter) { x = x || 0; y = y || 0; diameter = diameter || 0; /** * @property {number} x - The x coordinate of the center of the circle. */ this.x = x; /** * @property {number} y - The y coordinate of the center of the circle. */ this.y = y; /** * @property {number} _diameter - The diameter of the circle. * @private */ this._diameter = diameter; /** * @property {number} _radius - The radius of the circle. * @private */ this._radius = 0; if (diameter > 0) { this._radius = diameter * 0.5; } /** * @property {number} type - The const type of this object. * @readonly */ this.type = Phaser.CIRCLE; }; Phaser.Circle.prototype = { /** * The circumference of the circle. * * @method Phaser.Circle#circumference * @return {number} The circumference of the circle. */ circumference: function () { return 2 * (Math.PI * this._radius); }, /** * Returns a uniformly distributed random point from anywhere within this Circle. * * @method Phaser.Circle#random * @param {Phaser.Point|object} [out] - A Phaser.Point, or any object with public x/y properties, that the values will be set in. * If no object is provided a new Phaser.Point object will be created. In high performance areas avoid this by re-using an existing object. * @return {Phaser.Point} An object containing the random point in its `x` and `y` properties. */ random: function (out) { if (out === undefined) { out = new Phaser.Point(); } var t = 2 * Math.PI * Math.random(); var u = Math.random() + Math.random(); var r = (u > 1) ? 2 - u : u; var x = r * Math.cos(t); var y = r * Math.sin(t); out.x = this.x + (x * this.radius); out.y = this.y + (y * this.radius); return out; }, /** * Returns the framing rectangle of the circle as a Phaser.Rectangle object. * * @method Phaser.Circle#getBounds * @return {Phaser.Rectangle} The bounds of the Circle. */ getBounds: function () { return new Phaser.Rectangle(this.x - this.radius, this.y - this.radius, this.diameter, this.diameter); }, /** * Sets the members of Circle to the specified values. * @method Phaser.Circle#setTo * @param {number} x - The x coordinate of the center of the circle. * @param {number} y - The y coordinate of the center of the circle. * @param {number} diameter - The diameter of the circle. * @return {Circle} This circle object. */ setTo: function (x, y, diameter) { this.x = x; this.y = y; this._diameter = diameter; this._radius = diameter * 0.5; return this; }, /** * Copies the x, y and diameter properties from any given object to this Circle. * @method Phaser.Circle#copyFrom * @param {any} source - The object to copy from. * @return {Circle} This Circle object. */ copyFrom: function (source) { return this.setTo(source.x, source.y, source.diameter); }, /** * Copies the x, y and diameter properties from this Circle to any given object. * @method Phaser.Circle#copyTo * @param {any} dest - The object to copy to. * @return {object} This dest object. */ copyTo: function (dest) { dest.x = this.x; dest.y = this.y; dest.diameter = this._diameter; return dest; }, /** * Returns the distance from the center of the Circle object to the given object * (can be Circle, Point or anything with x/y properties) * @method Phaser.Circle#distance * @param {object} dest - The target object. Must have visible x and y properties that represent the center of the object. * @param {boolean} [round=false] - Round the distance to the nearest integer. * @return {number} The distance between this Point object and the destination Point object. */ distance: function (dest, round) { var distance = Phaser.Math.distance(this.x, this.y, dest.x, dest.y); return round ? Math.round(distance) : distance; }, /** * Returns a new Circle object with the same values for the x, y, width, and height properties as this Circle object. * @method Phaser.Circle#clone * @param {Phaser.Circle} output - Optional Circle object. If given the values will be set into the object, otherwise a brand new Circle object will be created and returned. * @return {Phaser.Circle} The cloned Circle object. */ clone: function (output) { if (output === undefined || output === null) { output = new Phaser.Circle(this.x, this.y, this.diameter); } else { output.setTo(this.x, this.y, this.diameter); } return output; }, /** * Return true if the given x/y coordinates are within this Circle object. * @method Phaser.Circle#contains * @param {number} x - The X value of the coordinate to test. * @param {number} y - The Y value of the coordinate to test. * @return {boolean} True if the coordinates are within this circle, otherwise false. */ contains: function (x, y) { return Phaser.Circle.contains(this, x, y); }, /** * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle. * @method Phaser.Circle#circumferencePoint * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)? * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specified a new Point object will be created. * @return {Phaser.Point} The Point object holding the result. */ circumferencePoint: function (angle, asDegrees, out) { return Phaser.Circle.circumferencePoint(this, angle, asDegrees, out); }, /** * Creates or positions points on the circle. * * The points are equally distributed in the half-closed interval [startAngle, endAngle). The default arc is the entire circle. * * If the `out` argument is omitted, this method creates and returns an array of {@link Phaser.Point points}. If an array is passed as `out`, its items are treated as points and placed in the same way. * * @param {type} [steps=60] - The number of points to place. * @param {type} [startAngle=0] - The starting angle in radians (unless asDegrees is true). * @param {type} [endAngle=Phaser.Math.PI2] - The end angle in radians (unless asDegrees is true). * @param {type} [asDegrees=false] - Are the given angles in radians (false) or degrees (true)? * @param {any[]} [out] - An array of points or point-like objects (e.g., sprites). It should start at index 0 and its length should be equal to or greater than `steps`. * @return {any[]} - The modified `out` argument or a new array of points. */ sample: function (steps, startAngle, endAngle, asDegrees, out) { if (!steps) { steps = 60; } if (startAngle == null) { startAngle = 0; } if (endAngle == null) { endAngle = Phaser.Math.PI2; } if (!out) { out = []; } var i = 0; while (i < steps) { this.circumferencePoint( Phaser.Math.linear(startAngle, endAngle, i / steps), asDegrees, out[i] || (out[i] = new Phaser.Point()) ); i += 1; } return out; }, /** * Adjusts the location of the Circle object, as determined by its center coordinate, by the specified amounts. * @method Phaser.Circle#offset * @param {number} dx - Moves the x value of the Circle object by this amount. * @param {number} dy - Moves the y value of the Circle object by this amount. * @return {Circle} This Circle object. */ offset: function (dx, dy) { this.x += dx; this.y += dy; return this; }, /** * Adjusts the location of the Circle object using a Point object as a parameter. This method is similar to the Circle.offset() method, except that it takes a Point object as a parameter. * @method Phaser.Circle#offsetPoint * @param {Point} point A Point object to use to offset this Circle object (or any valid object with exposed x and y properties). * @return {Circle} This Circle object. */ offsetPoint: function (point) { return this.offset(point.x, point.y); }, /** * Returns a string representation of this object. * @method Phaser.Circle#toString * @return {string} a string representation of the instance. */ toString: function () { return "[{Phaser.Circle (x=" + this.x + " y=" + this.y + " diameter=" + this.diameter + " radius=" + this.radius + ")}]"; } }; Phaser.Circle.prototype.constructor = Phaser.Circle; /** * The largest distance between any two points on the circle. The same as the radius * 2. * * @name Phaser.Circle#diameter * @property {number} diameter - Gets or sets the diameter of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "diameter", { get: function () { return this._diameter; }, set: function (value) { if (value > 0) { this._diameter = value; this._radius = value * 0.5; } } }); /** * The length of a line extending from the center of the circle to any point on the circle itself. The same as half the diameter. * @name Phaser.Circle#radius * @property {number} radius - Gets or sets the radius of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "radius", { get: function () { return this._radius; }, set: function (value) { if (value > 0) { this._radius = value; this._diameter = value * 2; } } }); /** * The x coordinate of the leftmost point of the circle. Changing the left property of a Circle object has no effect on the x and y properties. However it does affect the diameter, whereas changing the x value does not affect the diameter property. * @name Phaser.Circle#left * @propety {number} left - Gets or sets the value of the leftmost point of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "left", { get: function () { return this.x - this._radius; }, set: function (value) { if (value > this.x) { this._radius = 0; this._diameter = 0; } else { this.radius = this.x - value; } } }); /** * The x coordinate of the rightmost point of the circle. Changing the right property of a Circle object has no effect on the x and y properties. However it does affect the diameter, whereas changing the x value does not affect the diameter property. * @name Phaser.Circle#right * @property {number} right - Gets or sets the value of the rightmost point of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "right", { get: function () { return this.x + this._radius; }, set: function (value) { if (value < this.x) { this._radius = 0; this._diameter = 0; } else { this.radius = value - this.x; } } }); /** * The sum of the y minus the radius property. Changing the top property of a Circle object has no effect on the x and y properties, but does change the diameter. * @name Phaser.Circle#top * @property {number} top - Gets or sets the top of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "top", { get: function () { return this.y - this._radius; }, set: function (value) { if (value > this.y) { this._radius = 0; this._diameter = 0; } else { this.radius = this.y - value; } } }); /** * The sum of the y and radius properties. Changing the bottom property of a Circle object has no effect on the x and y properties, but does change the diameter. * @name Phaser.Circle#bottom * @property {number} bottom - Gets or sets the bottom of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "bottom", { get: function () { return this.y + this._radius; }, set: function (value) { if (value < this.y) { this._radius = 0; this._diameter = 0; } else { this.radius = value - this.y; } } }); /** * The area of this Circle. * @name Phaser.Circle#area * @property {number} area - The area of this circle. * @readonly */ Object.defineProperty(Phaser.Circle.prototype, "area", { get: function () { if (this._radius > 0) { return Math.PI * this._radius * this._radius; } else { return 0; } } }); /** * Determines whether or not this Circle object is empty. Will return a value of true if the Circle objects diameter is less than or equal to 0; otherwise false. * If set to true it will reset all of the Circle objects properties to 0. A Circle object is empty if its diameter is less than or equal to 0. * @name Phaser.Circle#empty * @property {boolean} empty - Gets or sets the empty state of the circle. */ Object.defineProperty(Phaser.Circle.prototype, "empty", { get: function () { return (this._diameter === 0); }, set: function (value) { if (value === true) { this.setTo(0, 0, 0); } } }); /** * Return true if the given x/y coordinates are within the Circle object. * @method Phaser.Circle.contains * @param {Phaser.Circle} a - The Circle to be checked. * @param {number} x - The X value of the coordinate to test. * @param {number} y - The Y value of the coordinate to test. * @return {boolean} True if the coordinates are within this circle, otherwise false. */ Phaser.Circle.contains = function (a, x, y) { // Check if x/y are within the bounds first if (a.radius > 0 && x >= a.left && x <= a.right && y >= a.top && y <= a.bottom) { var dx = (a.x - x) * (a.x - x); var dy = (a.y - y) * (a.y - y); return (dx + dy) <= (a.radius * a.radius); } else { return false; } }; /** * Determines whether the two Circle objects match. This method compares the x, y and diameter properties. * @method Phaser.Circle.equals * @param {Phaser.Circle} a - The first Circle object. * @param {Phaser.Circle} b - The second Circle object. * @return {boolean} A value of true if the object has exactly the same values for the x, y and diameter properties as this Circle object; otherwise false. */ Phaser.Circle.equals = function (a, b) { return (a.x === b.x && a.y === b.y && a.diameter === b.diameter); }; /** * Determines whether the two Circle objects intersect. * This method checks the radius distances between the two Circle objects to see if they intersect. * @method Phaser.Circle.intersects * @param {Phaser.Circle} a - The first Circle object. * @param {Phaser.Circle} b - The second Circle object. * @return {boolean} A value of true if the specified object intersects with this Circle object; otherwise false. */ Phaser.Circle.intersects = function (a, b) { return (Phaser.Math.distance(a.x, a.y, b.x, b.y) <= (a.radius + b.radius)); }; /** * Returns a Point object containing the coordinates of a point on the circumference of the Circle based on the given angle. * @method Phaser.Circle.circumferencePoint * @param {Phaser.Circle} a - The first Circle object. * @param {number} angle - The angle in radians (unless asDegrees is true) to return the point from. * @param {boolean} [asDegrees=false] - Is the given angle in radians (false) or degrees (true)? * @param {Phaser.Point} [out] - An optional Point object to put the result in to. If none specif