UNPKG

@azerion/phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.

1,568 lines (1,253 loc) 94.9 kB
/** * @author Richard Davey <rich@photonstorm.com> * @copyright 2016 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ Phaser.Component = 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} */ /** * The Angle Component provides access to an `angle` property; the rotation of a Game Object in degrees. * * @class */ Phaser.Component.Angle = function () {}; Phaser.Component.Angle.prototype = { /** * The angle property is the rotation of the Game Object in *degrees* from its original orientation. * * Values from 0 to 180 represent clockwise rotation; values from 0 to -180 represent counterclockwise rotation. * * Values outside this range are added to or subtracted from 360 to obtain a value within the range. * For example, the statement player.angle = 450 is the same as player.angle = 90. * * If you wish to work in radians instead of degrees you can use the property `rotation` instead. * Working in radians is slightly faster as it doesn't have to perform any calculations. * * @property {number} angle */ angle: { get: function() { return Phaser.Math.wrapAngle(Phaser.Math.radToDeg(this.rotation)); }, set: function(value) { this.rotation = Phaser.Math.degToRad(Phaser.Math.wrapAngle(value)); } } }; /** * @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 Animation Component provides a `play` method, which is a proxy to the `AnimationManager.play` method. * * @class */ Phaser.Component.Animation = function () {}; Phaser.Component.Animation.prototype = { /** * Plays an Animation. * * The animation should have previously been created via `animations.add`. * * If the animation is already playing calling this again won't do anything. * If you need to reset an already running animation do so directly on the Animation object itself or via `AnimationManager.stop`. * * @method * @param {string} name - The name of the animation to be played, e.g. "fire", "walk", "jump". Must have been previously created via 'AnimationManager.add'. * @param {number} [frameRate=null] - The framerate to play the animation at. The speed is given in frames per second. If not provided the previously set frameRate of the Animation is used. * @param {boolean} [loop=false] - Should the animation be looped after playback. If not provided the previously set loop value of the Animation is used. * @param {boolean} [killOnComplete=false] - If set to true when the animation completes (only happens if loop=false) the parent Sprite will be killed. * @return {Phaser.Animation} A reference to playing Animation. */ play: function (name, frameRate, loop, killOnComplete) { if (this.animations) { return this.animations.play(name, frameRate, loop, killOnComplete); } } }; /** * @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 AutoCull Component is responsible for providing methods that check if a Game Object is within the bounds of the World Camera. * It is used by the InWorld component. * * @class */ Phaser.Component.AutoCull = function () {}; Phaser.Component.AutoCull.prototype = { /** * A Game Object with `autoCull` set to true will check its bounds against the World Camera every frame. * If it is not intersecting the Camera bounds at any point then it has its `renderable` property set to `false`. * This keeps the Game Object alive and still processing updates, but forces it to skip the render step entirely. * * This is a relatively expensive operation, especially if enabled on hundreds of Game Objects. So enable it only if you know it's required, * or you have tested performance and find it acceptable. * * @property {boolean} autoCull * @default */ autoCull: false, /** * Checks if the Game Objects bounds intersect with the Game Camera bounds. * Returns `true` if they do, otherwise `false` if fully outside of the Cameras bounds. * * @property {boolean} inCamera * @readonly */ inCamera: { get: function() { if (!this.autoCull && !this.checkWorldBounds) { this._bounds.copyFrom(this.getBounds()); this._bounds.x += this.game.camera.view.x; this._bounds.y += this.game.camera.view.y; } return this.game.world.camera.view.intersects(this._bounds); } } }; /** * @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 Bounds component contains properties related to the bounds of the Game Object. * * @class */ Phaser.Component.Bounds = function () {}; Phaser.Component.Bounds.prototype = { /** * The amount the Game Object is visually offset from its x coordinate. * This is the same as `width * anchor.x`. * It will only be > 0 if anchor.x is not equal to zero. * * @property {number} offsetX * @readOnly */ offsetX: { get: function () { return this.anchor.x * this.width; } }, /** * The amount the Game Object is visually offset from its y coordinate. * This is the same as `height * anchor.y`. * It will only be > 0 if anchor.y is not equal to zero. * * @property {number} offsetY * @readOnly */ offsetY: { get: function () { return this.anchor.y * this.height; } }, /** * The center x coordinate of the Game Object. * This is the same as `(x - offsetX) + (width / 2)`. * * @property {number} centerX */ centerX: { get: function () { return (this.x - this.offsetX) + (this.width * 0.5); }, set: function (value) { this.x = (value + this.offsetX) - (this.width * 0.5); } }, /** * The center y coordinate of the Game Object. * This is the same as `(y - offsetY) + (height / 2)`. * * @property {number} centerY */ centerY: { get: function () { return (this.y - this.offsetY) + (this.height * 0.5); }, set: function (value) { this.y = (value + this.offsetY) - (this.height * 0.5); } }, /** * The left coordinate of the Game Object. * This is the same as `x - offsetX`. * * @property {number} left */ left: { get: function () { return this.x - this.offsetX; }, set: function (value) { this.x = value + this.offsetX; } }, /** * The right coordinate of the Game Object. * This is the same as `x + width - offsetX`. * * @property {number} right */ right: { get: function () { return (this.x + this.width) - this.offsetX; }, set: function (value) { this.x = value - (this.width) + this.offsetX; } }, /** * The y coordinate of the Game Object. * This is the same as `y - offsetY`. * * @property {number} top */ top: { get: function () { return this.y - this.offsetY; }, set: function (value) { this.y = value + this.offsetY; } }, /** * The sum of the y and height properties. * This is the same as `y + height - offsetY`. * * @property {number} bottom */ bottom: { get: function () { return (this.y + this.height) - this.offsetY; }, set: function (value) { this.y = value - (this.height) + this.offsetY; } }, /** * Aligns this Game Object within another Game Object, or Rectangle, known as the * 'container', to one of 9 possible positions. * * The container must be a Game Object, or Phaser.Rectangle object. This can include properties * such as `World.bounds` or `Camera.view`, for aligning Game Objects within the world * and camera bounds. Or it can include other Sprites, Images, Text objects, BitmapText, * TileSprites or Buttons. * * Please note that aligning a Sprite to another Game Object does **not** make it a child of * the container. It simply modifies its position coordinates so it aligns with it. * * The position constants you can use are: * * `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`, * `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`, * `Phaser.BOTTOM_CENTER` and `Phaser.BOTTOM_RIGHT`. * * The Game Objects are placed in such a way that their _bounds_ align with the * container, taking into consideration rotation, scale and the anchor property. * This allows you to neatly align Game Objects, irrespective of their position value. * * The optional `offsetX` and `offsetY` arguments allow you to apply extra spacing to the final * aligned position of the Game Object. For example: * * `sprite.alignIn(background, Phaser.BOTTOM_RIGHT, -20, -20)` * * Would align the `sprite` to the bottom-right, but moved 20 pixels in from the corner. * Think of the offsets as applying an adjustment to the containers bounds before the alignment takes place. * So providing a negative offset will 'shrink' the container bounds by that amount, and providing a positive * one expands it. * * @method * @param {Phaser.Rectangle|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Button|Phaser.Graphics|Phaser.TileSprite} container - The Game Object or Rectangle with which to align this Game Object to. Can also include properties such as `World.bounds` or `Camera.view`. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_CENTER`, `Phaser.CENTER`, `Phaser.RIGHT_CENTER`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`. * @param {integer} [offsetX=0] - A horizontal adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it. * @param {integer} [offsetY=0] - A vertical adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it. * @return {Object} This Game Object. */ alignIn: function (container, position, offsetX, offsetY) { if (offsetX === undefined) { offsetX = 0; } if (offsetY === undefined) { offsetY = 0; } switch (position) { default: case Phaser.TOP_LEFT: this.left = container.left - offsetX; this.top = container.top - offsetY; break; case Phaser.TOP_CENTER: this.centerX = container.centerX + offsetX; this.top = container.top - offsetY; break; case Phaser.TOP_RIGHT: this.right = container.right + offsetX; this.top = container.top - offsetY; break; case Phaser.LEFT_CENTER: this.left = container.left - offsetX; this.centerY = container.centerY + offsetY; break; case Phaser.CENTER: this.centerX = container.centerX + offsetX; this.centerY = container.centerY + offsetY; break; case Phaser.RIGHT_CENTER: this.right = container.right + offsetX; this.centerY = container.centerY + offsetY; break; case Phaser.BOTTOM_LEFT: this.left = container.left - offsetX; this.bottom = container.bottom + offsetY; break; case Phaser.BOTTOM_CENTER: this.centerX = container.centerX + offsetX; this.bottom = container.bottom + offsetY; break; case Phaser.BOTTOM_RIGHT: this.right = container.right + offsetX; this.bottom = container.bottom + offsetY; break; } return this; }, /** * Aligns this Game Object to the side of another Game Object, or Rectangle, known as the * 'parent', in one of 11 possible positions. * * The parent must be a Game Object, or Phaser.Rectangle object. This can include properties * such as `World.bounds` or `Camera.view`, for aligning Game Objects within the world * and camera bounds. Or it can include other Sprites, Images, Text objects, BitmapText, * TileSprites or Buttons. * * Please note that aligning a Sprite to another Game Object does **not** make it a child of * the parent. It simply modifies its position coordinates so it aligns with it. * * The position constants you can use are: * * `Phaser.TOP_LEFT` (default), `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_TOP`, * `Phaser.LEFT_CENTER`, `Phaser.LEFT_BOTTOM`, `Phaser.RIGHT_TOP`, `Phaser.RIGHT_CENTER`, * `Phaser.RIGHT_BOTTOM`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` * and `Phaser.BOTTOM_RIGHT`. * * The Game Objects are placed in such a way that their _bounds_ align with the * parent, taking into consideration rotation, scale and the anchor property. * This allows you to neatly align Game Objects, irrespective of their position value. * * The optional `offsetX` and `offsetY` arguments allow you to apply extra spacing to the final * aligned position of the Game Object. For example: * * `sprite.alignTo(background, Phaser.BOTTOM_RIGHT, -20, -20)` * * Would align the `sprite` to the bottom-right, but moved 20 pixels in from the corner. * Think of the offsets as applying an adjustment to the parents bounds before the alignment takes place. * So providing a negative offset will 'shrink' the parent bounds by that amount, and providing a positive * one expands it. * * @method * @param {Phaser.Rectangle|Phaser.Sprite|Phaser.Image|Phaser.Text|Phaser.BitmapText|Phaser.Button|Phaser.Graphics|Phaser.TileSprite} parent - The Game Object or Rectangle with which to align this Game Object to. Can also include properties such as `World.bounds` or `Camera.view`. * @param {integer} [position] - The position constant. One of `Phaser.TOP_LEFT`, `Phaser.TOP_CENTER`, `Phaser.TOP_RIGHT`, `Phaser.LEFT_TOP`, `Phaser.LEFT_CENTER`, `Phaser.LEFT_BOTTOM`, `Phaser.RIGHT_TOP`, `Phaser.RIGHT_CENTER`, `Phaser.RIGHT_BOTTOM`, `Phaser.BOTTOM_LEFT`, `Phaser.BOTTOM_CENTER` or `Phaser.BOTTOM_RIGHT`. * @param {integer} [offsetX=0] - A horizontal adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it. * @param {integer} [offsetY=0] - A vertical adjustment of the Containers bounds, applied to the aligned position of the Game Object. Use a negative value to shrink the bounds, positive to increase it. * @return {Object} This Game Object. */ alignTo: function (parent, position, offsetX, offsetY) { if (offsetX === undefined) { offsetX = 0; } if (offsetY === undefined) { offsetY = 0; } switch (position) { default: case Phaser.TOP_LEFT: this.left = parent.left - offsetX; this.bottom = parent.top - offsetY; break; case Phaser.TOP_CENTER: this.centerX = parent.centerX + offsetX; this.bottom = parent.top - offsetY; break; case Phaser.TOP_RIGHT: this.right = parent.right + offsetX; this.bottom = parent.top - offsetY; break; case Phaser.LEFT_TOP: this.right = parent.left - offsetX; this.top = parent.top - offsetY; break; case Phaser.LEFT_CENTER: this.right = parent.left - offsetX; this.centerY = parent.centerY + offsetY; break; case Phaser.LEFT_BOTTOM: this.right = parent.left - offsetX; this.bottom = parent.bottom + offsetY; break; case Phaser.RIGHT_TOP: this.left = parent.right + offsetX; this.top = parent.top - offsetY; break; case Phaser.RIGHT_CENTER: this.left = parent.right + offsetX; this.centerY = parent.centerY + offsetY; break; case Phaser.RIGHT_BOTTOM: this.left = parent.right + offsetX; this.bottom = parent.bottom + offsetY; break; case Phaser.BOTTOM_LEFT: this.left = parent.left - offsetX; this.top = parent.bottom + offsetY; break; case Phaser.BOTTOM_CENTER: this.centerX = parent.centerX + offsetX; this.top = parent.bottom + offsetY; break; case Phaser.BOTTOM_RIGHT: this.right = parent.right + offsetX; this.top = parent.bottom + offsetY; break; } return this; } }; // Phaser.Group extensions Phaser.Group.prototype.alignIn = Phaser.Component.Bounds.prototype.alignIn; Phaser.Group.prototype.alignTo = Phaser.Component.Bounds.prototype.alignTo; /** * @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 BringToTop Component features quick access to Group sorting related methods. * * @class */ Phaser.Component.BringToTop = function () {}; /** * Brings this Game Object to the top of its parents display list. * Visually this means it will render over the top of any old child in the same Group. * * If this Game Object hasn't been added to a custom Group then this method will bring it to the top of the Game World, * because the World is the root Group from which all Game Objects descend. * * @method * @return {PIXI.DisplayObject} This instance. */ Phaser.Component.BringToTop.prototype.bringToTop = function() { if (this.parent) { this.parent.bringToTop(this); } return this; }; /** * Sends this Game Object to the bottom of its parents display list. * Visually this means it will render below all other children in the same Group. * * If this Game Object hasn't been added to a custom Group then this method will send it to the bottom of the Game World, * because the World is the root Group from which all Game Objects descend. * * @method * @return {PIXI.DisplayObject} This instance. */ Phaser.Component.BringToTop.prototype.sendToBack = function() { if (this.parent) { this.parent.sendToBack(this); } return this; }; /** * Moves this Game Object up one place in its parents display list. * This call has no effect if the Game Object is already at the top of the display list. * * If this Game Object hasn't been added to a custom Group then this method will move it one object up within the Game World, * because the World is the root Group from which all Game Objects descend. * * @method * @return {PIXI.DisplayObject} This instance. */ Phaser.Component.BringToTop.prototype.moveUp = function () { if (this.parent) { this.parent.moveUp(this); } return this; }; /** * Moves this Game Object down one place in its parents display list. * This call has no effect if the Game Object is already at the bottom of the display list. * * If this Game Object hasn't been added to a custom Group then this method will move it one object down within the Game World, * because the World is the root Group from which all Game Objects descend. * * @method * @return {PIXI.DisplayObject} This instance. */ Phaser.Component.BringToTop.prototype.moveDown = function () { if (this.parent) { this.parent.moveDown(this); } return 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} */ /** * Core Component Features. * * @class */ Phaser.Component.Core = function () {}; /** * Installs / registers mixin components. * * The `this` context should be that of the applicable object instance or prototype. * * @method * @protected */ Phaser.Component.Core.install = function (components) { // Always install 'Core' first Phaser.Utils.mixinPrototype(this, Phaser.Component.Core.prototype); this.components = {}; for (var i = 0; i < components.length; i++) { var id = components[i]; var replace = false; if (id === 'Destroy') { replace = true; } Phaser.Utils.mixinPrototype(this, Phaser.Component[id].prototype, replace); this.components[id] = true; } }; /** * Initializes the mixin components. * * The `this` context should be an instance of the component mixin target. * * @method * @protected */ Phaser.Component.Core.init = function (game, x, y, key, frame) { this.game = game; this.key = key; this.data = {}; this.position.set(x, y); this.world = new Phaser.Point(x, y); this.previousPosition = new Phaser.Point(x, y); this.events = new Phaser.Events(this); this._bounds = new Phaser.Rectangle(); if (this.components.PhysicsBody) { // Enable-body checks for hasOwnProperty; makes sure to lift property from prototype. this.body = this.body; } if (this.components.Animation) { this.animations = new Phaser.AnimationManager(this); } if (this.components.LoadTexture && key !== null) { this.loadTexture(key, frame); } if (this.components.FixedToCamera) { this.cameraOffset = new Phaser.Point(x, y); } }; Phaser.Component.Core.preUpdate = function () { if (this.pendingDestroy) { this.destroy(); return; } this.previousPosition.set(this.world.x, this.world.y); this.previousRotation = this.rotation; if (!this.exists || !this.parent.exists) { this.renderOrderID = -1; return false; } this.world.setTo(this.game.camera.x + this.worldTransform.tx, this.game.camera.y + this.worldTransform.ty); if (this.visible) { this.renderOrderID = this.game.stage.currentRenderOrderID++; } if (this.animations) { this.animations.update(); } if (this.body) { this.body.preUpdate(); } for (var i = 0; i < this.children.length; i++) { this.children[i].preUpdate(); } return true; }; Phaser.Component.Core.prototype = { /** * A reference to the currently running Game. * @property {Phaser.Game} game */ game: null, /** * A user defined name given to this Game Object. * This value isn't ever used internally by Phaser, it is meant as a game level property. * @property {string} name * @default */ name: '', /** * An empty Object that belongs to this Game Object. * This value isn't ever used internally by Phaser, but may be used by your own code, or * by Phaser Plugins, to store data that needs to be associated with the Game Object, * without polluting the Game Object directly. * @property {Object} data * @default */ data: {}, /** * The components this Game Object has installed. * @property {object} components * @protected */ components: {}, /** * The z depth of this Game Object within its parent Group. * No two objects in a Group can have the same z value. * This value is adjusted automatically whenever the Group hierarchy changes. * If you wish to re-order the layering of a Game Object then see methods like Group.moveUp or Group.bringToTop. * @property {number} z * @readOnly */ z: 0, /** * All Phaser Game Objects have an Events class which contains all of the events that are dispatched when certain things happen to this * Game Object, or any of its components. * @see Phaser.Events * @property {Phaser.Events} events */ events: undefined, /** * If the Game Object is enabled for animation (such as a Phaser.Sprite) this is a reference to its AnimationManager instance. * Through it you can create, play, pause and stop animations. * @see Phaser.AnimationManager * @property {Phaser.AnimationManager} animations */ animations: undefined, /** * The key of the image or texture used by this Game Object during rendering. * If it is a string it's the string used to retrieve the texture from the Phaser Image Cache. * It can also be an instance of a RenderTexture, BitmapData, Video or PIXI.Texture. * If a Game Object is created without a key it is automatically assigned the key `__default` which is a 32x32 transparent PNG stored within the Cache. * If a Game Object is given a key which doesn't exist in the Image Cache it is re-assigned the key `__missing` which is a 32x32 PNG of a green box with a line through it. * @property {string|Phaser.RenderTexture|Phaser.BitmapData|Phaser.Video|PIXI.Texture} key */ key: '', /** * The world coordinates of this Game Object in pixels. * Depending on where in the display list this Game Object is placed this value can differ from `position`, * which contains the x/y coordinates relative to the Game Objects parent. * @property {Phaser.Point} world */ world: null, /** * A debug flag designed for use with `Game.enableStep`. * @property {boolean} debug * @default */ debug: false, /** * The position the Game Object was located in the previous frame. * @property {Phaser.Point} previousPosition * @readOnly */ previousPosition: null, /** * The rotation the Game Object was in set to in the previous frame. Value is in radians. * @property {number} previousRotation * @readOnly */ previousRotation: 0, /** * The render order ID is used internally by the renderer and Input Manager and should not be modified. * This property is mostly used internally by the renderers, but is exposed for the use of plugins. * @property {number} renderOrderID * @readOnly */ renderOrderID: 0, /** * A Game Object is considered `fresh` if it has just been created or reset and is yet to receive a renderer transform update. * This property is mostly used internally by the physics systems, but is exposed for the use of plugins. * @property {boolean} fresh * @readOnly */ fresh: true, /** * A Game Object is that is pendingDestroy is flagged to have its destroy method called on the next logic update. * You can set it directly to allow you to flag an object to be destroyed on its next update. * * This is extremely useful if you wish to destroy an object from within one of its own callbacks * such as with Buttons or other Input events. * * @property {boolean} pendingDestroy */ pendingDestroy: false, /** * @property {Phaser.Rectangle} _bounds - Internal cache var. * @private */ _bounds: null, /** * @property {boolean} _exists - Internal cache var. * @private */ _exists: true, /** * Controls if this Game Object is processed by the core game loop. * If this Game Object has a physics body it also controls if its physics body is updated or not. * When `exists` is set to `false` it will remove its physics body from the physics world if it has one. * It also toggles the `visible` property to false as well. * * Setting `exists` to true will add its physics body back in to the physics world, if it has one. * It will also set the `visible` property to `true`. * * @property {boolean} exists */ exists: { get: function () { return this._exists; }, set: function (value) { if (value) { this._exists = true; if (this.body && this.body.type === Phaser.Physics.P2JS) { this.body.addToWorld(); } this.visible = true; } else { this._exists = false; if (this.body && this.body.type === Phaser.Physics.P2JS) { this.body.removeFromWorld(); } this.visible = false; } } }, /** * Override this method in your own custom objects to handle any update requirements. * It is called immediately after `preUpdate` and before `postUpdate`. * Remember if this Game Object has any children you should call update on those too. * * @method */ update: function() { }, /** * Internal method called by the World postUpdate cycle. * * @method * @protected */ postUpdate: function() { if (this.customRender) { this.key.render(); } if (this.components.PhysicsBody) { Phaser.Component.PhysicsBody.postUpdate.call(this); } if (this.components.FixedToCamera) { Phaser.Component.FixedToCamera.postUpdate.call(this); } for (var i = 0; i < this.children.length; i++) { this.children[i].postUpdate(); } } }; /** * @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 Crop component provides the ability to crop a texture based Game Object to a defined rectangle, * which can be updated in real-time. * * @class */ Phaser.Component.Crop = function () {}; Phaser.Component.Crop.prototype = { /** * The Rectangle used to crop the texture this Game Object uses. * Set this property via `crop`. * If you modify this property directly you must call `updateCrop` in order to have the change take effect. * @property {Phaser.Rectangle} cropRect * @default */ cropRect: null, /** * @property {Phaser.Rectangle} _crop - Internal cache var. * @private */ _crop: null, /** * Crop allows you to crop the texture being used to display this Game Object. * Setting a crop rectangle modifies the core texture frame. The Game Object width and height properties will be adjusted accordingly. * * Cropping takes place from the top-left and can be modified in real-time either by providing an updated rectangle object to this method, * or by modifying `cropRect` property directly and then calling `updateCrop`. * * The rectangle object given to this method can be either a `Phaser.Rectangle` or any other object * so long as it has public `x`, `y`, `width`, `height`, `right` and `bottom` properties. * * A reference to the rectangle is stored in `cropRect` unless the `copy` parameter is `true`, * in which case the values are duplicated to a local object. * * @method * @param {Phaser.Rectangle} rect - The Rectangle used during cropping. Pass null or no parameters to clear a previously set crop rectangle. * @param {boolean} [copy=false] - If false `cropRect` will be stored as a reference to the given rect. If true it will copy the rect values into a local Phaser Rectangle object stored in cropRect. */ crop: function (rect, copy) { if (copy === undefined) { copy = false; } if (rect) { if (copy && this.cropRect !== null) { this.cropRect.setTo(rect.x, rect.y, rect.width, rect.height); } else if (copy && this.cropRect === null) { this.cropRect = new Phaser.Rectangle(rect.x, rect.y, rect.width, rect.height); } else { this.cropRect = rect; } this.updateCrop(); } else { this._crop = null; this.cropRect = null; this.resetFrame(); } }, /** * If you have set a crop rectangle on this Game Object via `crop` and since modified the `cropRect` property, * or the rectangle it references, then you need to update the crop frame by calling this method. * * @method */ updateCrop: function () { if (!this.cropRect) { return; } var oldX = this.texture.crop.x; var oldY = this.texture.crop.y; var oldW = this.texture.crop.width; var oldH = this.texture.crop.height; this._crop = Phaser.Rectangle.clone(this.cropRect, this._crop); this._crop.x += this._frame.x; this._crop.y += this._frame.y; var cx = Math.max(this._frame.x, this._crop.x); var cy = Math.max(this._frame.y, this._crop.y); var cw = Math.min(this._frame.right, this._crop.right) - cx; var ch = Math.min(this._frame.bottom, this._crop.bottom) - cy; this.texture.crop.x = cx; this.texture.crop.y = cy; this.texture.crop.width = cw; this.texture.crop.height = ch; this.texture.frame.width = Math.min(cw, this.cropRect.width); this.texture.frame.height = Math.min(ch, this.cropRect.height); this.texture.width = this.texture.frame.width; this.texture.height = this.texture.frame.height; this.texture._updateUvs(); if (this.tint !== 0xffffff && (oldX !== cx || oldY !== cy || oldW !== cw || oldH !== ch)) { this.texture.requiresReTint = true; } } }; /** * @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 Delta component provides access to delta values between the Game Objects current and previous position. * * @class */ Phaser.Component.Delta = function () {}; Phaser.Component.Delta.prototype = { /** * Returns the delta x value. The difference between world.x now and in the previous frame. * * The value will be positive if the Game Object has moved to the right or negative if to the left. * * @property {number} deltaX * @readonly */ deltaX: { get: function() { return this.world.x - this.previousPosition.x; } }, /** * Returns the delta y value. The difference between world.y now and in the previous frame. * * The value will be positive if the Game Object has moved down or negative if up. * * @property {number} deltaY * @readonly */ deltaY: { get: function() { return this.world.y - this.previousPosition.y; } }, /** * Returns the delta z value. The difference between rotation now and in the previous frame. * * @property {number} deltaZ - The delta value. * @readonly */ deltaZ: { get: function() { return this.rotation - this.previousRotation; } } }; /** * @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 Destroy component is responsible for destroying a Game Object. * * @class */ Phaser.Component.Destroy = function () {}; Phaser.Component.Destroy.prototype = { /** * As a Game Object runs through its destroy method this flag is set to true, * and can be checked in any sub-systems or plugins it is being destroyed from. * @property {boolean} destroyPhase * @readOnly */ destroyPhase: false, /** * Destroys the Game Object. This removes it from its parent group, destroys the input, event and animation handlers if present * and nulls its reference to `game`, freeing it up for garbage collection. * * If this Game Object has the Events component it will also dispatch the `onDestroy` event. * * You can optionally also destroy the BaseTexture this Game Object is using. Be careful if you've * more than one Game Object sharing the same BaseTexture. * * @method * @param {boolean} [destroyChildren=true] - Should every child of this object have its destroy method called as well? * @param {boolean} [destroyTexture=false] - Destroy the BaseTexture this Game Object is using? Note that if another Game Object is sharing the same BaseTexture it will invalidate it. */ destroy: function (destroyChildren, destroyTexture) { if (this.game === null || this.destroyPhase) { return; } if (destroyChildren === undefined) { destroyChildren = true; } if (destroyTexture === undefined) { destroyTexture = false; } this.destroyPhase = true; if (this.events) { this.events.onDestroy$dispatch(this); } if (this.parent) { if (this.parent instanceof Phaser.Group) { this.parent.remove(this); } else { this.parent.removeChild(this); } } if (this.input) { this.input.destroy(); } if (this.animations) { this.animations.destroy(); } if (this.body) { this.body.destroy(); } if (this.events) { this.events.destroy(); } this.game.tweens.removeFrom(this); var i = this.children.length; if (destroyChildren) { while (i--) { this.children[i].destroy(destroyChildren); } } else { while (i--) { this.removeChild(this.children[i]); } } if (this._crop) { this._crop = null; this.cropRect = null; } if (this._frame) { this._frame = null; } if (Phaser.Video && this.key instanceof Phaser.Video) { this.key.onChangeSource.remove(this.resizeFrame, this); } if (Phaser.BitmapText && this._glyphs) { this._glyphs = []; } this.alive = false; this.exists = false; this.visible = false; this.filters = null; this.mask = null; this.game = null; this.data = {}; // In case Pixi is still going to try and render it even though destroyed this.renderable = false; if (this.transformCallback) { this.transformCallback = null; this.transformCallbackContext = null; } // Pixi level DisplayObject destroy this.hitArea = null; this.parent = null; this.stage = null; this.worldTransform = null; this.filterArea = null; this._bounds = null; this._currentBounds = null; this._mask = null; this._destroyCachedSprite(); // Texture? if (destroyTexture) { this.texture.destroy(true); } this.destroyPhase = false; this.pendingDestroy = false; } }; /** * @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 Events component is a collection of events fired by the parent Game Object. * * Phaser uses what are known as 'Signals' for all event handling. All of the events in * this class are signals you can subscribe to, much in the same way you'd "listen" for * an event. * * For example to tell when a Sprite has been added to a new group, you can bind a function * to the `onAddedToGroup` signal: * * `sprite.events.onAddedToGroup.add(yourFunction, this);` * * Where `yourFunction` is the function you want called when this event occurs. * * For more details about how signals work please see the Phaser.Signal class. * * The Input-related events will only be dispatched if the Sprite has had `inputEnabled` set to `true` * and the Animation-related events only apply to game objects with animations like {@link Phaser.Sprite}. * * @class Phaser.Events * @constructor * @param {Phaser.Sprite} sprite - A reference to the game object / Sprite that owns this Events object. */ Phaser.Events = function (sprite) { /** * @property {Phaser.Sprite} parent - The Sprite that owns these events. */ this.parent = sprite; // The signals are automatically added by the corresponding proxy properties }; Phaser.Events.prototype = { /** * Removes all events. * * @method Phaser.Events#destroy */ destroy: function () { this._parent = null; if (this._onDestroy) { this._onDestroy.dispose(); } if (this._onAddedToGroup) { this._onAddedToGroup.dispose(); } if (this._onRemovedFromGroup) { this._onRemovedFromGroup.dispose(); } if (this._onRemovedFromWorld) { this._onRemovedFromWorld.dispose(); } if (this._onKilled) { this._onKilled.dispose(); } if (this._onRevived) { this._onRevived.dispose(); } if (this._onEnterBounds) { this._onEnterBounds.dispose(); } if (this._onOutOfBounds) { this._onOutOfBounds.dispose(); } if (this._onInputOver) { this._onInputOver.dispose(); } if (this._onInputOut) { this._onInputOut.dispose(); } if (this._onInputDown) { this._onInputDown.dispose(); } if (this._onInputUp) { this._onInputUp.dispose(); } if (this._onDragStart) { this._onDragStart.dispose(); } if (this._onDragUpdate) { this._onDragUpdate.dispose(); } if (this._onDragStop) { this._onDragStop.dispose(); } if (this._onAnimationStart) { this._onAnimationStart.dispose(); } if (this._onAnimationComplete) { this._onAnimationComplete.dispose(); } if (this._onAnimationLoop) { this._onAnimationLoop.dispose(); } }, // The following properties are sentinels that will be replaced with getters /** * This signal is dispatched when this Game Object is added to a new Group. * It is sent two arguments: * {any} The Game Object that was added to the Group. * {Phaser.Group} The Group it was added to. * @property {Phaser.Signal} onAddedToGroup */ onAddedToGroup: null, /** * This signal is dispatched when the Game Object is removed from a Group. * It is sent two arguments: * {any} The Game Object that was removed from the Group. * {Phaser.Group} The Group it was removed from. * @property {Phaser.Signal} onRemovedFromGroup */ onRemovedFromGroup: null, /** * This Signal is never used internally by Phaser and is now deprecated. * @deprecated * @property {Phaser.Signal} onRemovedFromWorld */ onRemovedFromWorld: null, /** * This signal is dispatched when the Game Object is destroyed. * This happens when `Sprite.destroy()` is called, or `Group.destroy()` with `destroyChildren` set to true. * It is sent one argument: * {any} The Game Object that was destroyed. * @property {Phaser.Signal} onDestroy */ onDestroy: null, /** * This signal is dispatched when the Game Object is killed. * This happens when `Sprite.kill()` is called. * Please understand the difference between `kill` and `destroy` by looking at their respective methods. * It is sent one argument: * {any} The Game Object that was killed. * @property {Phaser.Signal} onKilled */ onKilled: null, /** * This signal is dispatched when the Game Object is revived from a previously killed state. * This happens when `Sprite.revive()` is called. * It is sent one argument: * {any} The Game Object that was revived. * @property {Phaser.Signal} onRevived */ onRevived: null, /** * This signal is dispatched when the Game Object leaves the Phaser.World bounds. * This signal is only if `Sprite.checkWorldBounds` is set to `true`. * It is sent one argument: * {any} The Game Object that left the World bounds. * @property {Phaser.Signal} onOutOfBounds */ onOutOfBounds: null, /** * This signal is dispatched when the Game Object returns within the Phaser.World bounds, having previously been outside of them. * This signal is only if `Sprite.checkWorldBounds` is set to `true`. * It is sent one argument: * {any} The Game Object that entered the World bounds. * @property {Phaser.Signal} onEnterBounds */ onEnterBounds: null, /** * This signal is dispatched if the Game Object has `inputEnabled` set to `true`, * and receives an over event from a Phaser.Pointer. * It is sent two arguments: * {any} The Game Object that received the event. * {Phaser.Pointer} The Phaser.Pointer object that caused the event. * @property {Phaser.Signal} onInputOver */ onInputOver: null, /** * This signal is dispatched if the Game Object has `inputEnabled` set to `true`, * and receives an out event from a Phaser.Pointer, which was previously over it. * It is sent two arguments: * {any} The Game Object that received the event. * {Phaser.Pointer} The Phaser.Pointer object that caused the event. * @property {Phaser.Signal} onInputOut */ onInputOut: null, /** * This signal is dispatched if the Game Object has `inputEnabled` set to `true`, * and receives a down event from a Phaser.Pointer. This effectively means the Pointer has been * pressed down (but not yet released) on the Game Object. * It is sent two arguments: * {any} The Game Object that received the event. * {Phaser.Pointer} The Phaser.Pointer object that caused the event. * @property {Phaser.Signal} onInputDown */ onInputDown: null, /** * This signal is dispatched if the Game Object has `inputEnabled` set to `true`, * and receives an up event from a Phaser.Pointer. This effectively means the Pointer had been * pressed down, and was then released on the Game Object. * It is sent three arguments: * {any} The Game Object that received the event. * {Phaser.Pointer} The Phaser.Pointer object that caused the event. * {boolean} isOver - Is the Pointer still over the Game Object? * @property {Phaser.Signal} onInputUp */ onInputUp: null, /** * This signal is dispatched if the Game Object has been `inputEnabled` and `enableDrag` has been set. * It is sent when a Phaser.Pointer starts to drag the Game Object, taking into consideration the various * drag limitations that may be set.