phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
1,367 lines (1,200 loc) • 62.6 kB
JavaScript
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2025 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Actions = require('../../actions/');
var Class = require('../../utils/Class');
var Events = require('../events');
var EventEmitter = require('eventemitter3');
var GetAll = require('../../utils/array/GetAll');
var GetFastValue = require('../../utils/object/GetFastValue');
var GetValue = require('../../utils/object/GetValue');
var HasValue = require('../../utils/object/HasValue');
var IsPlainObject = require('../../utils/object/IsPlainObject');
var Range = require('../../utils/array/Range');
var Set = require('../../structs/Set');
var Sprite = require('../sprite/Sprite');
/**
* @classdesc
* A Group is a way for you to create, manipulate, or recycle similar Game Objects.
*
* Group membership is non-exclusive. A Game Object can belong to several groups, one group, or none.
*
* Groups themselves aren't displayable, and can't be positioned, rotated, scaled, or hidden.
*
* @class Group
* @memberof Phaser.GameObjects
* @extends Phaser.Events.EventEmitter
* @constructor
* @since 3.0.0
* @param {Phaser.Scene} scene - The scene this group belongs to.
* @param {(Phaser.GameObjects.GameObject[]|Phaser.Types.GameObjects.Group.GroupConfig|Phaser.Types.GameObjects.Group.GroupCreateConfig)} [children] - Game Objects to add to this group; or the `config` argument.
* @param {Phaser.Types.GameObjects.Group.GroupConfig|Phaser.Types.GameObjects.Group.GroupCreateConfig} [config] - Settings for this group. If `key` is set, Phaser.GameObjects.Group#createMultiple is also called with these settings.
*
* @see Phaser.Physics.Arcade.Group
* @see Phaser.Physics.Arcade.StaticGroup
*/
var Group = new Class({
Extends: EventEmitter,
initialize:
function Group (scene, children, config)
{
EventEmitter.call(this);
// They can pass in any of the following as the first argument:
// 1) A single child
// 2) An array of children
// 3) A config object
// 4) An array of config objects
// Or they can pass in a child, or array of children AND a config object
if (config)
{
// config has been set, are the children an array?
if (children && !Array.isArray(children))
{
children = [ children ];
}
}
else if (Array.isArray(children))
{
// No config, so let's check the children argument
if (IsPlainObject(children[0]))
{
// It's an array of plain config objects
config = children;
children = null;
}
}
else if (IsPlainObject(children))
{
// Children isn't an array. Is it a config object though?
config = children;
children = null;
}
/**
* This scene this group belongs to.
*
* @name Phaser.GameObjects.Group#scene
* @type {Phaser.Scene}
* @since 3.0.0
*/
this.scene = scene;
/**
* Members of this group.
*
* @name Phaser.GameObjects.Group#children
* @type {Phaser.Structs.Set.<Phaser.GameObjects.GameObject>}
* @since 3.0.0
*/
this.children = new Set();
/**
* A flag identifying this object as a group.
*
* @name Phaser.GameObjects.Group#isParent
* @type {boolean}
* @default true
* @since 3.0.0
*/
this.isParent = true;
/**
* A textual representation of this Game Object.
* Used internally by Phaser but is available for your own custom classes to populate.
*
* @name Phaser.GameObjects.Group#type
* @type {string}
* @default 'Group'
* @since 3.21.0
*/
this.type = 'Group';
/**
* The class to create new group members from.
*
* @name Phaser.GameObjects.Group#classType
* @type {function}
* @since 3.0.0
* @default Phaser.GameObjects.Sprite
* @see Phaser.Types.GameObjects.Group.GroupClassTypeConstructor
*/
this.classType = GetFastValue(config, 'classType', Sprite);
/**
* The name of this group.
* Empty by default and never populated by Phaser, this is left for developers to use.
*
* @name Phaser.GameObjects.Group#name
* @type {string}
* @default ''
* @since 3.18.0
*/
this.name = GetFastValue(config, 'name', '');
/**
* Whether this group runs its {@link Phaser.GameObjects.Group#preUpdate} method (which may update any members).
*
* @name Phaser.GameObjects.Group#active
* @type {boolean}
* @since 3.0.0
*/
this.active = GetFastValue(config, 'active', true);
/**
* The maximum size of this group, if used as a pool. -1 is no limit.
*
* @name Phaser.GameObjects.Group#maxSize
* @type {number}
* @since 3.0.0
* @default -1
*/
this.maxSize = GetFastValue(config, 'maxSize', -1);
/**
* A default texture key to use when creating new group members.
*
* This is used in {@link Phaser.GameObjects.Group#create}
* but not in {@link Phaser.GameObjects.Group#createMultiple}.
*
* @name Phaser.GameObjects.Group#defaultKey
* @type {string}
* @since 3.0.0
*/
this.defaultKey = GetFastValue(config, 'defaultKey', null);
/**
* A default texture frame to use when creating new group members.
*
* @name Phaser.GameObjects.Group#defaultFrame
* @type {(string|number)}
* @since 3.0.0
*/
this.defaultFrame = GetFastValue(config, 'defaultFrame', null);
/**
* Whether to call the update method of any members.
*
* @name Phaser.GameObjects.Group#runChildUpdate
* @type {boolean}
* @default false
* @since 3.0.0
* @see Phaser.GameObjects.Group#preUpdate
*/
this.runChildUpdate = GetFastValue(config, 'runChildUpdate', false);
/**
* A function to be called when adding or creating group members.
*
* @name Phaser.GameObjects.Group#createCallback
* @type {?Phaser.Types.GameObjects.Group.GroupCallback}
* @since 3.0.0
*/
this.createCallback = GetFastValue(config, 'createCallback', null);
/**
* A function to be called when removing group members.
*
* @name Phaser.GameObjects.Group#removeCallback
* @type {?Phaser.Types.GameObjects.Group.GroupCallback}
* @since 3.0.0
*/
this.removeCallback = GetFastValue(config, 'removeCallback', null);
/**
* A function to be called when creating several group members at once.
*
* @name Phaser.GameObjects.Group#createMultipleCallback
* @type {?Phaser.Types.GameObjects.Group.GroupMultipleCreateCallback}
* @since 3.0.0
*/
this.createMultipleCallback = GetFastValue(config, 'createMultipleCallback', null);
/**
* A function to be called when adding or creating group members.
* For internal use only by a Group, or any class that extends it.
*
* @name Phaser.GameObjects.Group#internalCreateCallback
* @type {?Phaser.Types.GameObjects.Group.GroupCallback}
* @private
* @since 3.22.0
*/
this.internalCreateCallback = GetFastValue(config, 'internalCreateCallback', null);
/**
* A function to be called when removing group members.
* For internal use only by a Group, or any class that extends it.
*
* @name Phaser.GameObjects.Group#internalRemoveCallback
* @type {?Phaser.Types.GameObjects.Group.GroupCallback}
* @private
* @since 3.22.0
*/
this.internalRemoveCallback = GetFastValue(config, 'internalRemoveCallback', null);
if (children)
{
this.addMultiple(children);
}
if (config)
{
this.createMultiple(config);
}
this.on(Events.ADDED_TO_SCENE, this.addedToScene, this);
this.on(Events.REMOVED_FROM_SCENE, this.removedFromScene, this);
},
// Overrides Game Object method
addedToScene: function ()
{
this.scene.sys.updateList.add(this);
},
// Overrides Game Object method
removedFromScene: function ()
{
this.scene.sys.updateList.remove(this);
},
/**
* Creates a new Game Object and adds it to this group, unless the group {@link Phaser.GameObjects.Group#isFull is full}.
*
* Calls {@link Phaser.GameObjects.Group#createCallback}.
*
* @method Phaser.GameObjects.Group#create
* @since 3.0.0
*
* @param {number} [x=0] - The horizontal position of the new Game Object in the world.
* @param {number} [y=0] - The vertical position of the new Game Object in the world.
* @param {string} [key=defaultKey] - The texture key of the new Game Object.
* @param {(string|number)} [frame=defaultFrame] - The texture frame of the new Game Object.
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of the new Game Object.
* @param {boolean} [active=true] - The {@link Phaser.GameObjects.GameObject#active} state of the new Game Object.
*
* @return {any} The new Game Object (usually a Sprite, etc.).
*/
create: function (x, y, key, frame, visible, active)
{
if (x === undefined) { x = 0; }
if (y === undefined) { y = 0; }
if (key === undefined) { key = this.defaultKey; }
if (frame === undefined) { frame = this.defaultFrame; }
if (visible === undefined) { visible = true; }
if (active === undefined) { active = true; }
// Pool?
if (this.isFull())
{
return null;
}
var child = new this.classType(this.scene, x, y, key, frame);
child.addToDisplayList(this.scene.sys.displayList);
child.addToUpdateList();
child.visible = visible;
child.setActive(active);
this.add(child);
return child;
},
/**
* Creates several Game Objects and adds them to this group.
*
* If the group becomes {@link Phaser.GameObjects.Group#isFull}, no further Game Objects are created.
*
* Calls {@link Phaser.GameObjects.Group#createMultipleCallback} and {@link Phaser.GameObjects.Group#createCallback}.
*
* @method Phaser.GameObjects.Group#createMultiple
* @since 3.0.0
*
* @param {Phaser.Types.GameObjects.Group.GroupCreateConfig|Phaser.Types.GameObjects.Group.GroupCreateConfig[]} config - Creation settings. This can be a single configuration object or an array of such objects, which will be applied in turn.
*
* @return {any[]} The newly created Game Objects.
*/
createMultiple: function (config)
{
if (this.isFull())
{
return [];
}
if (!Array.isArray(config))
{
config = [ config ];
}
var output = [];
if (config[0].key)
{
for (var i = 0; i < config.length; i++)
{
var entries = this.createFromConfig(config[i]);
output = output.concat(entries);
}
}
return output;
},
/**
* A helper for {@link Phaser.GameObjects.Group#createMultiple}.
*
* @method Phaser.GameObjects.Group#createFromConfig
* @since 3.0.0
*
* @param {Phaser.Types.GameObjects.Group.GroupCreateConfig} options - Creation settings.
*
* @return {any[]} The newly created Game Objects.
*/
createFromConfig: function (options)
{
if (this.isFull())
{
return [];
}
this.classType = GetFastValue(options, 'classType', this.classType);
var key = GetFastValue(options, 'key', undefined);
var frame = GetFastValue(options, 'frame', null);
var visible = GetFastValue(options, 'visible', true);
var active = GetFastValue(options, 'active', true);
var entries = [];
// Can't do anything without at least a key
if (key === undefined)
{
return entries;
}
else
{
if (!Array.isArray(key))
{
key = [ key ];
}
if (!Array.isArray(frame))
{
frame = [ frame ];
}
}
// Build an array of key frame pairs to loop through
var repeat = GetFastValue(options, 'repeat', 0);
var randomKey = GetFastValue(options, 'randomKey', false);
var randomFrame = GetFastValue(options, 'randomFrame', false);
var yoyo = GetFastValue(options, 'yoyo', false);
var quantity = GetFastValue(options, 'quantity', false);
var frameQuantity = GetFastValue(options, 'frameQuantity', 1);
var max = GetFastValue(options, 'max', 0);
// If a quantity value is set we use that to override the frameQuantity
var range = Range(key, frame, {
max: max,
qty: (quantity) ? quantity : frameQuantity,
random: randomKey,
randomB: randomFrame,
repeat: repeat,
yoyo: yoyo
});
if (options.createCallback)
{
this.createCallback = options.createCallback;
}
if (options.removeCallback)
{
this.removeCallback = options.removeCallback;
}
if (options.internalCreateCallback)
{
this.internalCreateCallback = options.internalCreateCallback;
}
if (options.internalRemoveCallback)
{
this.internalRemoveCallback = options.internalRemoveCallback;
}
for (var c = 0; c < range.length; c++)
{
var created = this.create(0, 0, range[c].a, range[c].b, visible, active);
if (!created)
{
break;
}
entries.push(created);
}
// Post-creation options (applied only to those items created in this call):
if (HasValue(options, 'setXY'))
{
var x = GetValue(options, 'setXY.x', 0);
var y = GetValue(options, 'setXY.y', 0);
var stepX = GetValue(options, 'setXY.stepX', 0);
var stepY = GetValue(options, 'setXY.stepY', 0);
Actions.SetXY(entries, x, y, stepX, stepY);
}
if (HasValue(options, 'setRotation'))
{
var rotation = GetValue(options, 'setRotation.value', 0);
var stepRotation = GetValue(options, 'setRotation.step', 0);
Actions.SetRotation(entries, rotation, stepRotation);
}
if (HasValue(options, 'setScale'))
{
var scaleX = GetValue(options, 'setScale.x', 1);
var scaleY = GetValue(options, 'setScale.y', scaleX);
var stepScaleX = GetValue(options, 'setScale.stepX', 0);
var stepScaleY = GetValue(options, 'setScale.stepY', 0);
Actions.SetScale(entries, scaleX, scaleY, stepScaleX, stepScaleY);
}
if (HasValue(options, 'setOrigin'))
{
var originX = GetValue(options, 'setOrigin.x', 0.5);
var originY = GetValue(options, 'setOrigin.y', originX);
var stepOriginX = GetValue(options, 'setOrigin.stepX', 0);
var stepOriginY = GetValue(options, 'setOrigin.stepY', 0);
Actions.SetOrigin(entries, originX, originY, stepOriginX, stepOriginY);
}
if (HasValue(options, 'setAlpha'))
{
var alpha = GetValue(options, 'setAlpha.value', 1);
var stepAlpha = GetValue(options, 'setAlpha.step', 0);
Actions.SetAlpha(entries, alpha, stepAlpha);
}
if (HasValue(options, 'setDepth'))
{
var depth = GetValue(options, 'setDepth.value', 0);
var stepDepth = GetValue(options, 'setDepth.step', 0);
Actions.SetDepth(entries, depth, stepDepth);
}
if (HasValue(options, 'setScrollFactor'))
{
var scrollFactorX = GetValue(options, 'setScrollFactor.x', 1);
var scrollFactorY = GetValue(options, 'setScrollFactor.y', scrollFactorX);
var stepScrollFactorX = GetValue(options, 'setScrollFactor.stepX', 0);
var stepScrollFactorY = GetValue(options, 'setScrollFactor.stepY', 0);
Actions.SetScrollFactor(entries, scrollFactorX, scrollFactorY, stepScrollFactorX, stepScrollFactorY);
}
var hitArea = GetFastValue(options, 'hitArea', null);
var hitAreaCallback = GetFastValue(options, 'hitAreaCallback', null);
if (hitArea)
{
Actions.SetHitArea(entries, hitArea, hitAreaCallback);
}
var grid = GetFastValue(options, 'gridAlign', false);
if (grid)
{
Actions.GridAlign(entries, grid);
}
if (this.createMultipleCallback)
{
this.createMultipleCallback.call(this, entries);
}
return entries;
},
/**
* Updates any group members, if {@link Phaser.GameObjects.Group#runChildUpdate} is enabled.
*
* @method Phaser.GameObjects.Group#preUpdate
* @since 3.0.0
*
* @param {number} time - The current timestamp.
* @param {number} delta - The delta time elapsed since the last frame.
*/
preUpdate: function (time, delta)
{
if (!this.runChildUpdate || this.children.size === 0)
{
return;
}
// Because a Group child may mess with the length of the Group during its update
var temp = this.children.entries.slice();
for (var i = 0; i < temp.length; i++)
{
var item = temp[i];
if (item.active)
{
item.update(time, delta);
}
}
},
/**
* Adds a Game Object to this group.
*
* Calls {@link Phaser.GameObjects.Group#createCallback}.
*
* @method Phaser.GameObjects.Group#add
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject} child - The Game Object to add.
* @param {boolean} [addToScene=false] - Also add the Game Object to the scene.
*
* @return {this} This Group object.
*/
add: function (child, addToScene)
{
if (addToScene === undefined) { addToScene = false; }
if (this.isFull())
{
return this;
}
this.children.set(child);
if (this.internalCreateCallback)
{
this.internalCreateCallback.call(this, child);
}
if (this.createCallback)
{
this.createCallback.call(this, child);
}
if (addToScene)
{
child.addToDisplayList(this.scene.sys.displayList);
child.addToUpdateList();
}
child.on(Events.DESTROY, this.remove, this);
return this;
},
/**
* Adds several Game Objects to this group.
*
* Calls {@link Phaser.GameObjects.Group#createCallback}.
*
* @method Phaser.GameObjects.Group#addMultiple
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject[]} children - The Game Objects to add.
* @param {boolean} [addToScene=false] - Also add the Game Objects to the scene.
*
* @return {this} This group.
*/
addMultiple: function (children, addToScene)
{
if (addToScene === undefined) { addToScene = false; }
if (Array.isArray(children))
{
for (var i = 0; i < children.length; i++)
{
this.add(children[i], addToScene);
}
}
return this;
},
/**
* Removes a member of this Group and optionally removes it from the Scene and / or destroys it.
*
* Calls {@link Phaser.GameObjects.Group#removeCallback}.
*
* @method Phaser.GameObjects.Group#remove
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject} child - The Game Object to remove.
* @param {boolean} [removeFromScene=false] - Optionally remove the Group member from the Scene it belongs to.
* @param {boolean} [destroyChild=false] - Optionally call destroy on the removed Group member.
*
* @return {this} This Group object.
*/
remove: function (child, removeFromScene, destroyChild)
{
if (removeFromScene === undefined) { removeFromScene = false; }
if (destroyChild === undefined) { destroyChild = false; }
if (!this.children.contains(child))
{
return this;
}
this.children.delete(child);
if (this.internalRemoveCallback)
{
this.internalRemoveCallback.call(this, child);
}
if (this.removeCallback)
{
this.removeCallback.call(this, child);
}
child.off(Events.DESTROY, this.remove, this);
if (destroyChild)
{
child.destroy();
}
else if (removeFromScene)
{
child.removeFromDisplayList();
child.removeFromUpdateList();
}
return this;
},
/**
* Removes all members of this Group and optionally removes them from the Scene and / or destroys them.
*
* Does not call {@link Phaser.GameObjects.Group#removeCallback}.
*
* @method Phaser.GameObjects.Group#clear
* @since 3.0.0
*
* @param {boolean} [removeFromScene=false] - Optionally remove each Group member from the Scene.
* @param {boolean} [destroyChild=false] - Optionally call destroy on the removed Group members.
*
* @return {this} This group.
*/
clear: function (removeFromScene, destroyChild)
{
if (removeFromScene === undefined) { removeFromScene = false; }
if (destroyChild === undefined) { destroyChild = false; }
var children = this.children;
for (var i = 0; i < children.size; i++)
{
var gameObject = children.entries[i];
gameObject.off(Events.DESTROY, this.remove, this);
if (destroyChild)
{
gameObject.destroy();
}
else if (removeFromScene)
{
gameObject.removeFromDisplayList();
gameObject.removeFromUpdateList();
}
}
this.children.clear();
return this;
},
/**
* Tests if a Game Object is a member of this group.
*
* @method Phaser.GameObjects.Group#contains
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject} child - A Game Object.
*
* @return {boolean} True if the Game Object is a member of this group.
*/
contains: function (child)
{
return this.children.contains(child);
},
/**
* All members of the group.
*
* @method Phaser.GameObjects.Group#getChildren
* @since 3.0.0
*
* @return {Phaser.GameObjects.GameObject[]} The group members.
*/
getChildren: function ()
{
return this.children.entries;
},
/**
* The number of members of the group.
*
* @method Phaser.GameObjects.Group#getLength
* @since 3.0.0
*
* @return {number}
*/
getLength: function ()
{
return this.children.size;
},
/**
* Returns all children in this Group that match the given criteria based on the `property` and `value` arguments.
*
* For example: `getMatching('visible', true)` would return only children that have their `visible` property set.
*
* Optionally, you can specify a start and end index. For example if the Group has 100 elements,
* and you set `startIndex` to 0 and `endIndex` to 50, it would return matches from only
* the first 50.
*
* @method Phaser.GameObjects.Group#getMatching
* @since 3.50.0
*
* @param {string} [property] - The property to test on each array element.
* @param {*} [value] - The value to test the property against. Must pass a strict (`===`) comparison check.
* @param {number} [startIndex] - An optional start index to search from.
* @param {number} [endIndex] - An optional end index to search to.
*
* @return {any[]} An array of matching Group members. The array will be empty if nothing matched.
*/
getMatching: function (property, value, startIndex, endIndex)
{
return GetAll(this.children.entries, property, value, startIndex, endIndex);
},
/**
* Scans the Group, from top to bottom, for the first member that has an {@link Phaser.GameObjects.GameObject#active} state matching the argument,
* assigns `x` and `y`, and returns the member.
*
* If no matching member is found and `createIfNull` is true and the group isn't full then it will create a new Game Object using `x`, `y`, `key`, `frame`, and `visible`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getFirst
* @since 3.0.0
*
* @param {boolean} [state=false] - The {@link Phaser.GameObjects.GameObject#active} value to match.
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {?any} The first matching group member, or a newly created member, or null.
*/
getFirst: function (state, createIfNull, x, y, key, frame, visible)
{
return this.getHandler(true, 1, state, createIfNull, x, y, key, frame, visible);
},
/**
* Scans the Group, from top to bottom, for the nth member that has an {@link Phaser.GameObjects.GameObject#active} state matching the argument,
* assigns `x` and `y`, and returns the member.
*
* If no matching member is found and `createIfNull` is true and the group isn't full then it will create a new Game Object using `x`, `y`, `key`, `frame`, and `visible`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getFirstNth
* @since 3.6.0
*
* @param {number} nth - The nth matching Group member to search for.
* @param {boolean} [state=false] - The {@link Phaser.GameObjects.GameObject#active} value to match.
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {?any} The first matching group member, or a newly created member, or null.
*/
getFirstNth: function (nth, state, createIfNull, x, y, key, frame, visible)
{
return this.getHandler(true, nth, state, createIfNull, x, y, key, frame, visible);
},
/**
* Scans the Group for the last member that has an {@link Phaser.GameObjects.GameObject#active} state matching the argument,
* assigns `x` and `y`, and returns the member.
*
* If no matching member is found and `createIfNull` is true and the group isn't full then it will create a new Game Object using `x`, `y`, `key`, `frame`, and `visible`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getLast
* @since 3.6.0
*
* @param {boolean} [state=false] - The {@link Phaser.GameObjects.GameObject#active} value to match.
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {?any} The first matching group member, or a newly created member, or null.
*/
getLast: function (state, createIfNull, x, y, key, frame, visible)
{
return this.getHandler(false, 1, state, createIfNull, x, y, key, frame, visible);
},
/**
* Scans the Group for the last nth member that has an {@link Phaser.GameObjects.GameObject#active} state matching the argument,
* assigns `x` and `y`, and returns the member.
*
* If no matching member is found and `createIfNull` is true and the group isn't full then it will create a new Game Object using `x`, `y`, `key`, `frame`, and `visible`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getLastNth
* @since 3.6.0
*
* @param {number} nth - The nth matching Group member to search for.
* @param {boolean} [state=false] - The {@link Phaser.GameObjects.GameObject#active} value to match.
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {?any} The first matching group member, or a newly created member, or null.
*/
getLastNth: function (nth, state, createIfNull, x, y, key, frame, visible)
{
return this.getHandler(false, nth, state, createIfNull, x, y, key, frame, visible);
},
/**
* Scans the group for the last member that has an {@link Phaser.GameObjects.GameObject#active} state matching the argument,
* assigns `x` and `y`, and returns the member.
*
* If no matching member is found and `createIfNull` is true and the group isn't full then it will create a new Game Object using `x`, `y`, `key`, `frame`, and `visible`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getHandler
* @private
* @since 3.6.0
*
* @param {boolean} forwards - Search front to back or back to front?
* @param {number} nth - Stop matching after nth successful matches.
* @param {boolean} [state=false] - The {@link Phaser.GameObjects.GameObject#active} value to match.
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {?any} The first matching group member, or a newly created member, or null.
*/
getHandler: function (forwards, nth, state, createIfNull, x, y, key, frame, visible)
{
if (state === undefined) { state = false; }
if (createIfNull === undefined) { createIfNull = false; }
var gameObject;
var i;
var total = 0;
var children = this.children.entries;
if (forwards)
{
for (i = 0; i < children.length; i++)
{
gameObject = children[i];
if (gameObject.active === state)
{
total++;
if (total === nth)
{
break;
}
}
else
{
gameObject = null;
}
}
}
else
{
for (i = children.length - 1; i >= 0; i--)
{
gameObject = children[i];
if (gameObject.active === state)
{
total++;
if (total === nth)
{
break;
}
}
else
{
gameObject = null;
}
}
}
if (gameObject)
{
if (typeof(x) === 'number')
{
gameObject.x = x;
}
if (typeof(y) === 'number')
{
gameObject.y = y;
}
return gameObject;
}
// Got this far? We need to create or bail
if (createIfNull)
{
return this.create(x, y, key, frame, visible);
}
else
{
return null;
}
},
/**
* Scans the group for the first member that has an {@link Phaser.GameObjects.GameObject#active} state set to `false`,
* assigns `x` and `y`, and returns the member.
*
* If no inactive member is found and the group isn't full then it will create a new Game Object using `x`, `y`, `key`, `frame`, and `visible`.
* The new Game Object will have its active state set to `true`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#get
* @since 3.0.0
*
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {?any} The first inactive group member, or a newly created member, or null.
*/
get: function (x, y, key, frame, visible)
{
return this.getFirst(false, true, x, y, key, frame, visible);
},
/**
* Scans the group for the first member that has an {@link Phaser.GameObjects.GameObject#active} state set to `true`,
* assigns `x` and `y`, and returns the member.
*
* If no active member is found and `createIfNull` is `true` and the group isn't full then it will create a new one using `x`, `y`, `key`, `frame`, and `visible`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getFirstAlive
* @since 3.0.0
*
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {any} The first active group member, or a newly created member, or null.
*/
getFirstAlive: function (createIfNull, x, y, key, frame, visible)
{
return this.getFirst(true, createIfNull, x, y, key, frame, visible);
},
/**
* Scans the group for the first member that has an {@link Phaser.GameObjects.GameObject#active} state set to `false`,
* assigns `x` and `y`, and returns the member.
*
* If no inactive member is found and `createIfNull` is `true` and the group isn't full then it will create a new one using `x`, `y`, `key`, `frame`, and `visible`.
* The new Game Object will have an active state set to `true`.
* Unless a new member is created, `key`, `frame`, and `visible` are ignored.
*
* @method Phaser.GameObjects.Group#getFirstDead
* @since 3.0.0
*
* @param {boolean} [createIfNull=false] - Create a new Game Object if no matching members are found, using the following arguments.
* @param {number} [x] - The horizontal position of the Game Object in the world.
* @param {number} [y] - The vertical position of the Game Object in the world.
* @param {string} [key=defaultKey] - The texture key assigned to a new Game Object (if one is created).
* @param {(string|number)} [frame=defaultFrame] - A texture frame assigned to a new Game Object (if one is created).
* @param {boolean} [visible=true] - The {@link Phaser.GameObjects.Components.Visible#visible} state of a new Game Object (if one is created).
*
* @return {any} The first inactive group member, or a newly created member, or null.
*/
getFirstDead: function (createIfNull, x, y, key, frame, visible)
{
return this.getFirst(false, createIfNull, x, y, key, frame, visible);
},
/**
* {@link Phaser.Animations.AnimationState#play Plays} an animation for all members of this group.
*
* @method Phaser.GameObjects.Group#playAnimation
* @since 3.0.0
*
* @param {string} key - The string-based key of the animation to play.
* @param {string} [startFrame=0] - Optionally start the animation playing from this frame index.
*
* @return {this} This Group object.
*/
playAnimation: function (key, startFrame)
{
Actions.PlayAnimation(this.children.entries, key, startFrame);
return this;
},
/**
* Whether this group's size at its {@link Phaser.GameObjects.Group#maxSize maximum}.
*
* @method Phaser.GameObjects.Group#isFull
* @since 3.0.0
*
* @return {boolean} True if the number of members equals {@link Phaser.GameObjects.Group#maxSize}.
*/
isFull: function ()
{
if (this.maxSize === -1)
{
return false;
}
else
{
return (this.children.size >= this.maxSize);
}
},
/**
* Counts the number of active (or inactive) group members.
*
* @method Phaser.GameObjects.Group#countActive
* @since 3.0.0
*
* @param {boolean} [value=true] - Count active (true) or inactive (false) group members.
*
* @return {number} The number of group members with an active state matching the `active` argument.
*/
countActive: function (value)
{
if (value === undefined) { value = true; }
var total = 0;
for (var i = 0; i < this.children.size; i++)
{
if (this.children.entries[i].active === value)
{
total++;
}
}
return total;
},
/**
* Counts the number of in-use (active) group members.
*
* @method Phaser.GameObjects.Group#getTotalUsed
* @since 3.0.0
*
* @return {number} The number of group members with an active state of true.
*/
getTotalUsed: function ()
{
return this.countActive();
},
/**
* The difference of {@link Phaser.GameObjects.Group#maxSize} and the number of active group members.
*
* This represents the number of group members that could be created or reactivated before reaching the size limit.
*
* @method Phaser.GameObjects.Group#getTotalFree
* @since 3.0.0
*
* @return {number} maxSize minus the number of active group numbers; or a large number (if maxSize is -1).
*/
getTotalFree: function ()
{
var used = this.getTotalUsed();
var capacity = (this.maxSize === -1) ? 999999999999 : this.maxSize;
return (capacity - used);
},
/**
* Sets the `active` property of this Group.
* When active, this Group runs its `preUpdate` method.
*
* @method Phaser.GameObjects.Group#setActive
* @since 3.24.0
*
* @param {boolean} value - True if this Group should be set as active, false if not.
*
* @return {this} This Group object.
*/
setActive: function (value)
{
this.active = value;
return this;
},
/**
* Sets the `name` property of this Group.
* The `name` property is not populated by Phaser and is presented for your own use.
*
* @method Phaser.GameObjects.Group#setName
* @since 3.24.0
*
* @param {string} value - The name to be given to this Group.
*
* @return {this} This Group object.
*/
setName: function (value)
{
this.name = value;
return this;
},
/**
* Sets the property as defined in `key` of each group member to the given value.
*
* @method Phaser.GameObjects.Group#propertyValueSet
* @since 3.21.0
*
* @param {string} key - The property to be updated.
* @param {number} value - The amount to set the property to.
* @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
* @param {number} [index=0] - An optional offset to start searching from within the items array.
* @param {number} [direction=1] - The direction to iterate through the array. 1 is from beginning to end, -1 from end to beginning.
*
* @return {this} This Group object.
*/
propertyValueSet: function (key, value, step, index, direction)
{
Actions.PropertyValueSet(this.children.entries, key, value, step, index, direction);
return this;
},
/**
* Adds the given value to the property as defined in `key` of each group member.
*
* @method Phaser.GameObjects.Group#propertyValueInc
* @since 3.21.0
*
* @param {string} key - The property to be updated.
* @param {number} value - The amount to set the property to.
* @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
* @param {number} [index=0] - An optional offset to start searching from within the items array.
* @param {number} [direction=1] - The direction to iterate through the array. 1 is from beginning to end, -1 from end to beginning.
*
* @return {this} This Group object.
*/
propertyValueInc: function (key, value, step, index, direction)
{
Actions.PropertyValueInc(this.children.entries, key, value, step, index, direction);
return this;
},
/**
* Sets the x of each group member.
*
* @method Phaser.GameObjects.Group#setX
* @since 3.21.0
*
* @param {number} value - The amount to set the property to.
* @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
*
* @return {this} This Group object.
*/
setX: function (value, step)
{
Actions.SetX(this.children.entries, value, step);
return this;
},
/**
* Sets the y of each group member.
*
* @method Phaser.GameObjects.Group#setY
* @since 3.21.0
*
* @param {number} value - The amount to set the property to.
* @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
*
* @return {this} This Group object.
*/
setY: function (value, step)
{
Actions.SetY(this.children.entries, value, step);
return this;
},
/**
* Sets the x, y of each group member.
*
* @method Phaser.GameObjects.Group#setXY
* @since 3.21.0
*
* @param {number} x - The amount to set the `x` property to.
* @param {number} [y=x] - The amount to set the `y` property to. If `undefined` or `null` it uses the `x` value.
* @param {number} [stepX=0] - This is added to the `x` amount, multiplied by the iteration counter.
* @param {number} [stepY=0] - This is added to the `y` amount, multiplied by the iteration counter.
*
* @return {this} This Group object.
*/
setXY: function (x, y, stepX, stepY)
{
Actions.SetXY(this.children.entries, x, y, stepX, stepY);
return this;
},
/**
* Adds the given value to the x of each group member.
*
* @method Phaser.GameObjects.Group#incX
* @since 3.21.0
*
* @param {number} value - The amount to be added to the `x` property.
* @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
*
* @return {this} This Group object.
*/
incX: function (value, step)
{
Actions.IncX(this.children.entries, value, step);
return this;
},
/**
* Adds the given value to the y of each group member.
*
* @method Phaser.GameObjects.Group#incY
* @since 3.21.0
*
* @param {number} value - The amount to be added to the `y` property.
* @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
*
* @return {this} This Group object.
*/
incY: function (value, step)
{
Actions.IncY(this.children.entries, value, step);
return this;
},
/**
* Adds the given value to the x, y of each group member.
*
* @method Phaser.GameObjects.Group#incXY
* @since 3.21.0
*
* @param {number} x - The amount to be added to the `x` property.
* @param {number} [y=x] - The amount to be added to the `y` property. If `undefined` or `null` it uses the `x` value.
* @param {number} [stepX=0] - This is added to the `x` amount, multiplied by the iteration counter.
* @param {number} [stepY=0] - This is added to the `y` amount, multiplied by the iteration counter.
*
* @return {this} This Group object.
*/
incXY: function (x, y, stepX, stepY)
{
Actions.IncXY(this.children.entries, x, y, stepX, stepY);