@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
JavaScript
/**
* @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.