diff --git a/README.md b/README.md index 77600118..a4cc4d20 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Version 1.2 - "Shienar" - -in development- Significant API changes: * Upgraded to Pixi.js 1.4.4 +* Group now extends PIXI.DisplayObjectContainer, rather than owning a _container property, which makes life a whole lot easier re: nesting. + New features: diff --git a/build/config.php b/build/config.php index 0881b73f..77ba03a8 100644 --- a/build/config.php +++ b/build/config.php @@ -13,47 +13,76 @@ - + - + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -145,7 +174,5 @@ - - EOL; ?> diff --git a/examples/wip/index.php b/examples/wip/index.php index 74826bf3..f72e4b70 100644 --- a/examples/wip/index.php +++ b/examples/wip/index.php @@ -32,7 +32,7 @@ function dirToArray($dir) { - $ignore = array('.', '..', '_site', 'assets', 'states', 'book', 'filters'); + $ignore = array('.', '..', '_site', 'assets', 'states', 'book', 'filters', 'misc'); $result = array(); $root = scandir($dir); $dirs = array_diff($root, $ignore); diff --git a/examples/wip/2ball.js b/examples/wip/misc/2ball.js similarity index 100% rename from examples/wip/2ball.js rename to examples/wip/misc/2ball.js diff --git a/examples/wip/64x64.png b/examples/wip/misc/64x64.png similarity index 100% rename from examples/wip/64x64.png rename to examples/wip/misc/64x64.png diff --git a/examples/wip/SAT.js b/examples/wip/misc/SAT.js similarity index 100% rename from examples/wip/SAT.js rename to examples/wip/misc/SAT.js diff --git a/examples/wip/acceleration.js b/examples/wip/misc/acceleration.js similarity index 100% rename from examples/wip/acceleration.js rename to examples/wip/misc/acceleration.js diff --git a/examples/wip/audio loop.js b/examples/wip/misc/audio loop.js similarity index 100% rename from examples/wip/audio loop.js rename to examples/wip/misc/audio loop.js diff --git a/examples/wip/blocked.js b/examples/wip/misc/blocked.js similarity index 100% rename from examples/wip/blocked.js rename to examples/wip/misc/blocked.js diff --git a/examples/wip/bmd.js b/examples/wip/misc/bmd.js similarity index 100% rename from examples/wip/bmd.js rename to examples/wip/misc/bmd.js diff --git a/examples/wip/bmd2.js b/examples/wip/misc/bmd2.js similarity index 100% rename from examples/wip/bmd2.js rename to examples/wip/misc/bmd2.js diff --git a/examples/wip/bmd3.js b/examples/wip/misc/bmd3.js similarity index 100% rename from examples/wip/bmd3.js rename to examples/wip/misc/bmd3.js diff --git a/examples/wip/body angle.js b/examples/wip/misc/body angle.js similarity index 100% rename from examples/wip/body angle.js rename to examples/wip/misc/body angle.js diff --git a/examples/wip/body group.js b/examples/wip/misc/body group.js similarity index 100% rename from examples/wip/body group.js rename to examples/wip/misc/body group.js diff --git a/examples/wip/body scale.js b/examples/wip/misc/body scale.js similarity index 100% rename from examples/wip/body scale.js rename to examples/wip/misc/body scale.js diff --git a/examples/wip/body test.js b/examples/wip/misc/body test.js similarity index 100% rename from examples/wip/body test.js rename to examples/wip/misc/body test.js diff --git a/examples/wip/bunny.js b/examples/wip/misc/bunny.js similarity index 100% rename from examples/wip/bunny.js rename to examples/wip/misc/bunny.js diff --git a/examples/wip/button scale.js b/examples/wip/misc/button scale.js similarity index 100% rename from examples/wip/button scale.js rename to examples/wip/misc/button scale.js diff --git a/examples/wip/button size.js b/examples/wip/misc/button size.js similarity index 100% rename from examples/wip/button size.js rename to examples/wip/misc/button size.js diff --git a/examples/wip/circlebox.js b/examples/wip/misc/circlebox.js similarity index 100% rename from examples/wip/circlebox.js rename to examples/wip/misc/circlebox.js diff --git a/examples/wip/commando.js b/examples/wip/misc/commando.js similarity index 100% rename from examples/wip/commando.js rename to examples/wip/misc/commando.js diff --git a/examples/wip/create map polygon.js b/examples/wip/misc/create map polygon.js similarity index 100% rename from examples/wip/create map polygon.js rename to examples/wip/misc/create map polygon.js diff --git a/examples/wip/crop.js b/examples/wip/misc/crop.js similarity index 100% rename from examples/wip/crop.js rename to examples/wip/misc/crop.js diff --git a/examples/wip/cursor.js b/examples/wip/misc/cursor.js similarity index 100% rename from examples/wip/cursor.js rename to examples/wip/misc/cursor.js diff --git a/examples/wip/demo worm.js b/examples/wip/misc/demo worm.js similarity index 100% rename from examples/wip/demo worm.js rename to examples/wip/misc/demo worm.js diff --git a/examples/wip/dragonfire.js b/examples/wip/misc/dragonfire.js similarity index 100% rename from examples/wip/dragonfire.js rename to examples/wip/misc/dragonfire.js diff --git a/examples/wip/fiddle.js b/examples/wip/misc/fiddle.js similarity index 100% rename from examples/wip/fiddle.js rename to examples/wip/misc/fiddle.js diff --git a/examples/wip/filterconv.php b/examples/wip/misc/filterconv.php similarity index 100% rename from examples/wip/filterconv.php rename to examples/wip/misc/filterconv.php diff --git a/examples/wip/fixdrag.js b/examples/wip/misc/fixdrag.js similarity index 100% rename from examples/wip/fixdrag.js rename to examples/wip/misc/fixdrag.js diff --git a/examples/wip/forum.js b/examples/wip/misc/forum.js similarity index 100% rename from examples/wip/forum.js rename to examples/wip/misc/forum.js diff --git a/examples/wip/gc1.js b/examples/wip/misc/gc1.js similarity index 100% rename from examples/wip/gc1.js rename to examples/wip/misc/gc1.js diff --git a/examples/wip/gravity.js b/examples/wip/misc/gravity.js similarity index 100% rename from examples/wip/gravity.js rename to examples/wip/misc/gravity.js diff --git a/examples/wip/group call all.js b/examples/wip/misc/group call all.js similarity index 100% rename from examples/wip/group call all.js rename to examples/wip/misc/group call all.js diff --git a/examples/wip/group destroy.js b/examples/wip/misc/group destroy.js similarity index 100% rename from examples/wip/group destroy.js rename to examples/wip/misc/group destroy.js diff --git a/examples/wip/group extends.js b/examples/wip/misc/group extends.js similarity index 100% rename from examples/wip/group extends.js rename to examples/wip/misc/group extends.js diff --git a/examples/wip/group offset.js b/examples/wip/misc/group offset.js similarity index 100% rename from examples/wip/group offset.js rename to examples/wip/misc/group offset.js diff --git a/examples/wip/input active.js b/examples/wip/misc/input active.js similarity index 100% rename from examples/wip/input active.js rename to examples/wip/misc/input active.js diff --git a/examples/wip/jitter.js b/examples/wip/misc/jitter.js similarity index 100% rename from examples/wip/jitter.js rename to examples/wip/misc/jitter.js diff --git a/examples/wip/land.js b/examples/wip/misc/land.js similarity index 100% rename from examples/wip/land.js rename to examples/wip/misc/land.js diff --git a/examples/wip/line intersection.js b/examples/wip/misc/line intersection.js similarity index 100% rename from examples/wip/line intersection.js rename to examples/wip/misc/line intersection.js diff --git a/examples/wip/line polygon.js b/examples/wip/misc/line polygon.js similarity index 100% rename from examples/wip/line polygon.js rename to examples/wip/misc/line polygon.js diff --git a/examples/wip/mariotogether.js b/examples/wip/misc/mariotogether.js similarity index 100% rename from examples/wip/mariotogether.js rename to examples/wip/misc/mariotogether.js diff --git a/examples/wip/mod.js b/examples/wip/misc/mod.js similarity index 100% rename from examples/wip/mod.js rename to examples/wip/misc/mod.js diff --git a/examples/wip/mouse scale.js b/examples/wip/misc/mouse scale.js similarity index 100% rename from examples/wip/mouse scale.js rename to examples/wip/misc/mouse scale.js diff --git a/examples/wip/moveToPointer.js b/examples/wip/misc/moveToPointer.js similarity index 100% rename from examples/wip/moveToPointer.js rename to examples/wip/misc/moveToPointer.js diff --git a/examples/wip/multiball.js b/examples/wip/misc/multiball.js similarity index 100% rename from examples/wip/multiball.js rename to examples/wip/misc/multiball.js diff --git a/examples/wip/nested groups.js b/examples/wip/misc/nested groups.js similarity index 100% rename from examples/wip/nested groups.js rename to examples/wip/misc/nested groups.js diff --git a/examples/wip/offset.js b/examples/wip/misc/offset.js similarity index 100% rename from examples/wip/offset.js rename to examples/wip/misc/offset.js diff --git a/examples/wip/one way collision.js b/examples/wip/misc/one way collision.js similarity index 100% rename from examples/wip/one way collision.js rename to examples/wip/misc/one way collision.js diff --git a/examples/wip/pausetime.js b/examples/wip/misc/pausetime.js similarity index 100% rename from examples/wip/pausetime.js rename to examples/wip/misc/pausetime.js diff --git a/examples/wip/physics-motion.js b/examples/wip/misc/physics-motion.js similarity index 100% rename from examples/wip/physics-motion.js rename to examples/wip/misc/physics-motion.js diff --git a/examples/wip/pivot.js b/examples/wip/misc/pivot.js similarity index 100% rename from examples/wip/pivot.js rename to examples/wip/misc/pivot.js diff --git a/examples/wip/pixelpick atlas trimmed.js b/examples/wip/misc/pixelpick atlas trimmed.js similarity index 100% rename from examples/wip/pixelpick atlas trimmed.js rename to examples/wip/misc/pixelpick atlas trimmed.js diff --git a/examples/wip/platform.js b/examples/wip/misc/platform.js similarity index 100% rename from examples/wip/platform.js rename to examples/wip/misc/platform.js diff --git a/examples/wip/prerend.js b/examples/wip/misc/prerend.js similarity index 100% rename from examples/wip/prerend.js rename to examples/wip/misc/prerend.js diff --git a/examples/wip/pt.js b/examples/wip/misc/pt.js similarity index 100% rename from examples/wip/pt.js rename to examples/wip/misc/pt.js diff --git a/examples/wip/rabbit map.js b/examples/wip/misc/rabbit map.js similarity index 100% rename from examples/wip/rabbit map.js rename to examples/wip/misc/rabbit map.js diff --git a/examples/wip/rect test.js b/examples/wip/misc/rect test.js similarity index 100% rename from examples/wip/rect test.js rename to examples/wip/misc/rect test.js diff --git a/examples/wip/removeFilter.js b/examples/wip/misc/removeFilter.js similarity index 100% rename from examples/wip/removeFilter.js rename to examples/wip/misc/removeFilter.js diff --git a/examples/wip/rendertexture1.js b/examples/wip/misc/rendertexture1.js similarity index 100% rename from examples/wip/rendertexture1.js rename to examples/wip/misc/rendertexture1.js diff --git a/examples/wip/sat1.js b/examples/wip/misc/sat1.js similarity index 100% rename from examples/wip/sat1.js rename to examples/wip/misc/sat1.js diff --git a/examples/wip/sci-fly2.js b/examples/wip/misc/sci-fly2.js similarity index 100% rename from examples/wip/sci-fly2.js rename to examples/wip/misc/sci-fly2.js diff --git a/examples/wip/snake.js b/examples/wip/misc/snake.js similarity index 100% rename from examples/wip/snake.js rename to examples/wip/misc/snake.js diff --git a/examples/wip/snake2.js b/examples/wip/misc/snake2.js similarity index 100% rename from examples/wip/snake2.js rename to examples/wip/misc/snake2.js diff --git a/examples/wip/sort.js b/examples/wip/misc/sort.js similarity index 100% rename from examples/wip/sort.js rename to examples/wip/misc/sort.js diff --git a/examples/wip/sprite vs sprite.js b/examples/wip/misc/sprite vs sprite.js similarity index 100% rename from examples/wip/sprite vs sprite.js rename to examples/wip/misc/sprite vs sprite.js diff --git a/examples/wip/struck.js b/examples/wip/misc/struck.js similarity index 100% rename from examples/wip/struck.js rename to examples/wip/misc/struck.js diff --git a/examples/wip/supermario.js b/examples/wip/misc/supermario.js similarity index 100% rename from examples/wip/supermario.js rename to examples/wip/misc/supermario.js diff --git a/examples/wip/supermario2.js b/examples/wip/misc/supermario2.js similarity index 100% rename from examples/wip/supermario2.js rename to examples/wip/misc/supermario2.js diff --git a/examples/wip/swap.js b/examples/wip/misc/swap.js similarity index 100% rename from examples/wip/swap.js rename to examples/wip/misc/swap.js diff --git a/examples/wip/text on top.js b/examples/wip/misc/text on top.js similarity index 100% rename from examples/wip/text on top.js rename to examples/wip/misc/text on top.js diff --git a/examples/wip/tilemap poly.js b/examples/wip/misc/tilemap poly.js similarity index 100% rename from examples/wip/tilemap poly.js rename to examples/wip/misc/tilemap poly.js diff --git a/examples/wip/tilemap.js b/examples/wip/misc/tilemap.js similarity index 100% rename from examples/wip/tilemap.js rename to examples/wip/misc/tilemap.js diff --git a/examples/wip/timer simple.js b/examples/wip/misc/timer simple.js similarity index 100% rename from examples/wip/timer simple.js rename to examples/wip/misc/timer simple.js diff --git a/examples/wip/tween-limit.js b/examples/wip/misc/tween-limit.js similarity index 100% rename from examples/wip/tween-limit.js rename to examples/wip/misc/tween-limit.js diff --git a/examples/wip/tween-relative.js b/examples/wip/misc/tween-relative.js similarity index 100% rename from examples/wip/tween-relative.js rename to examples/wip/misc/tween-relative.js diff --git a/examples/wip/wabbits.js b/examples/wip/misc/wabbits.js similarity index 100% rename from examples/wip/wabbits.js rename to examples/wip/misc/wabbits.js diff --git a/examples/wip/wip1.js b/examples/wip/misc/wip1.js similarity index 100% rename from examples/wip/wip1.js rename to examples/wip/misc/wip1.js diff --git a/examples/wip/wip2.js b/examples/wip/misc/wip2.js similarity index 100% rename from examples/wip/wip2.js rename to examples/wip/misc/wip2.js diff --git a/examples/wip/wip3.js b/examples/wip/misc/wip3.js similarity index 100% rename from examples/wip/wip3.js rename to examples/wip/misc/wip3.js diff --git a/examples/wip/wip4.js b/examples/wip/misc/wip4.js similarity index 100% rename from examples/wip/wip4.js rename to examples/wip/misc/wip4.js diff --git a/examples/wip/world.js b/examples/wip/misc/world.js similarity index 100% rename from examples/wip/world.js rename to examples/wip/misc/world.js diff --git a/examples/wip/pixi1.js b/examples/wip/pixi1.js new file mode 100644 index 00000000..c4b3ebb0 --- /dev/null +++ b/examples/wip/pixi1.js @@ -0,0 +1,45 @@ + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('pic', 'assets/pics/backscroll.png'); + +} + +var sprite; +var sprite2; +var g; + +function create() { + + sprite = game.add.sprite(0, 0, 'pic'); + + g = game.add.group(); + + g.create(0, 0, 'pic'); + + g.y = 200; + g.rotation = 0.1; + + // sprite2 = game.add.sprite(0, 300, 'pic'); + + game.input.onDown.add(tint, this); + +} + +function tint() { + + sprite.tint = Math.random() * 0xFFFFFF; + // sprite2.tint = Math.random() * 0xFFFFFF; + +} + +function update() { + + +} + +function render() { + +} diff --git a/src/Phaser.js b/src/Phaser.js index 786bbd48..6cb14044 100644 --- a/src/Phaser.js +++ b/src/Phaser.js @@ -10,7 +10,7 @@ var Phaser = Phaser || { VERSION: '<%= version %>', - DEV_VERSION: '1.1.5', + DEV_VERSION: '1.2', GAMES: [], AUTO: 0, diff --git a/src/core/Group.js b/src/core/Group.js index 5fa52339..0eb47cec 100644 --- a/src/core/Group.js +++ b/src/core/Group.js @@ -10,7 +10,7 @@ * @classdesc A Group is a container for display objects that allows for fast pooling, recycling and collision checks. * @constructor * @param {Phaser.Game} game - A reference to the currently running game. -* @param {*} parent - The parent Group or DisplayObjectContainer that will hold this group, if any. If undefined it will use game.world. +* @param {*} parent - The parent Group, DisplayObject or DisplayObjectContainer that will hold this group. If undefined it will use game.world. * @param {string} [name=group] - A name for this Group. Not used internally but useful for debugging. * @param {boolean} [useStage=false] - Should the DisplayObjectContainer this Group creates be added to the World (default, false) or direct to the Stage (true). */ @@ -31,6 +31,8 @@ Phaser.Group = function (game, parent, name, useStage) { */ this.name = name || 'group'; + PIXI.DisplayObjectContainer.call(this); + if (typeof useStage === 'undefined') { useStage = false; @@ -38,29 +40,26 @@ Phaser.Group = function (game, parent, name, useStage) { if (useStage) { - this._container = this.game.stage._stage; + // this._container = this.game.stage._stage; } else { - this._container = new PIXI.DisplayObjectContainer(); - this._container.name = this.name; - if (parent) { - if (parent instanceof Phaser.Group) - { - parent._container.addChild(this._container); - } - else - { - parent.addChild(this._container); - parent.updateTransform(); - } + // if (parent instanceof Phaser.Group) + // { + // parent.addChild(this); + // } + // else + // { + parent.addChild(this); + // parent.updateTransform(); + // } } else { - this.game.stage._stage.addChild(this._container); - this.game.stage._stage.updateTransform(); + this.game.stage._stage.addChild(this); + // this.game.stage._stage.updateTransform(); } } @@ -77,7 +76,7 @@ Phaser.Group = function (game, parent, name, useStage) { this.alive = true; /** - * @property {boolean} exists - If exists is true the the Group is updated, otherwise it is skipped. + * @property {boolean} exists - If exists is true the Group is updated, otherwise it is skipped. * @default */ this.exists = true; @@ -88,17 +87,17 @@ Phaser.Group = function (game, parent, name, useStage) { this.group = null; // Replaces the PIXI.Point with a slightly more flexible one. - this._container.scale = new Phaser.Point(1, 1); + // this._container.scale = new Phaser.Point(1, 1); /** * @property {Phaser.Point} scale - The scane of the Group container. */ - this.scale = this._container.scale; + // this.scale = this._container.scale; /** * @property {Phaser.Point} pivot - The pivot point of the Group container. */ - this.pivot = this._container.pivot; + // this.pivot = this._container.pivot; /** * The cursor is a simple way to iterate through the objects in a Group using the Group.next and Group.previous functions. @@ -107,8 +106,13 @@ Phaser.Group = function (game, parent, name, useStage) { */ this.cursor = null; + this._cursorIndex = 0; + }; +Phaser.Group.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); +Phaser.Group.prototype.constructor = Phaser.Group; + /** * @constant * @type {number} @@ -139,139 +143,159 @@ Phaser.Group.SORT_ASCENDING = -1; */ Phaser.Group.SORT_DESCENDING = 1; -Phaser.Group.prototype = { +// PIXI.DisplayObjectContainer.prototype.addChildAt = function(child, index) - /** - * Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object. - * The child is automatically added to the top of the Group, so renders on-top of everything else within the Group. If you need to control - * that then see the addAt method. - * - * @see Phaser.Group#create - * @see Phaser.Group#addAt - * @method Phaser.Group#add - * @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object.. - * @return {*} The child that was added to the Group. - */ - add: function (child) { +/** +* Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object. +* The child is automatically added to the top of the Group, so renders on-top of everything else within the Group. If you need to control +* that then see the addAt method. +* +* @see Phaser.Group#create +* @see Phaser.Group#addAt +* @method Phaser.Group#add +* @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object.. +* @return {*} The child that was added to the Group. +*/ +Phaser.Group.prototype.add = function (child) { - if (child.group !== this) + if (child.group !== this) + { + child.group = this; + + this.addChild(child); + + // child.updateTransform(); + + if (child.events) { - if (child.type && child.type === Phaser.GROUP) - { - child.group = this; - - this._container.addChild(child._container); - - child._container.updateTransform(); - } - else - { - child.group = this; - - this._container.addChild(child); - - child.updateTransform(); - - if (child.events) - { - child.events.onAddedToGroup.dispatch(child, this); - } - } - - if (this.cursor === null) - { - this.cursor = child; - } + child.events.onAddedToGroup.dispatch(child, this); } + } - return child; + if (this.cursor === null) + { + this.cursor = child; + } - }, + return child; - /** - * Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object. - * The child is added to the Group at the location specified by the index value, this allows you to control child ordering. - * - * @method Phaser.Group#addAt - * @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object.. - * @param {number} index - The index within the Group to insert the child to. - * @return {*} The child that was added to the Group. - */ - addAt: function (child, index) { +} - if (child.group !== this) +/** +* Adds an existing object to this Group. The object can be an instance of Phaser.Sprite, Phaser.Button or any other display object. +* The child is added to the Group at the location specified by the index value, this allows you to control child ordering. +* +* @method Phaser.Group#addAt +* @param {*} child - An instance of Phaser.Sprite, Phaser.Button or any other display object.. +* @param {number} index - The index within the Group to insert the child to. +* @return {*} The child that was added to the Group. +*/ +Phaser.Group.prototype.addAt = function (child, index) { + + if (child.group !== this) + { + child.group = this; + + this.addChildAt(child, index); + + // child.updateTransform(); + + if (child.events) { - if (child.type && child.type === Phaser.GROUP) - { - child.group = this; - - this._container.addChildAt(child._container, index); - - child._container.updateTransform(); - } - else - { - child.group = this; - - this._container.addChildAt(child, index); - - child.updateTransform(); - - if (child.events) - { - child.events.onAddedToGroup.dispatch(child, this); - } - } - - if (this.cursor === null) - { - this.cursor = child; - } + child.events.onAddedToGroup.dispatch(child, this); } + } - return child; + if (this.cursor === null) + { + this.cursor = child; + } - }, + return child; - /** - * Returns the child found at the given index within this Group. - * - * @method Phaser.Group#getAt - * @param {number} index - The index to return the child from. - * @return {*} The child that was found at the given index. - */ - getAt: function (index) { +} - return this._container.getChildAt(index); +/** +* Returns the child found at the given index within this Group. +* +* @method Phaser.Group#getAt +* @param {number} index - The index to return the child from. +* @return {*} The child that was found at the given index. +*/ +Phaser.Group.prototype.getAt = function (index) { - }, + return this.getChildAt(index); - /** - * Automatically creates a new Phaser.Sprite object and adds it to the top of this Group. - * Useful if you don't need to create the Sprite instances before-hand. - * - * @method Phaser.Group#create - * @param {number} x - The x coordinate to display the newly created Sprite at. The value is in relation to the Group.x point. - * @param {number} y - The y coordinate to display the newly created Sprite at. The value is in relation to the Group.y point. - * @param {string} key - The Game.cache key of the image that this Sprite will use. - * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here. - * @param {boolean} [exists=true] - The default exists state of the Sprite. - * @return {Phaser.Sprite} The child that was created. - */ - create: function (x, y, key, frame, exists) { +} - if (typeof exists === 'undefined') { exists = true; } +/** +* Automatically creates a new Phaser.Sprite object and adds it to the top of this Group. +* Useful if you don't need to create the Sprite instances before-hand. +* +* @method Phaser.Group#create +* @param {number} x - The x coordinate to display the newly created Sprite at. The value is in relation to the Group.x point. +* @param {number} y - The y coordinate to display the newly created Sprite at. The value is in relation to the Group.y point. +* @param {string} key - The Game.cache key of the image that this Sprite will use. +* @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here. +* @param {boolean} [exists=true] - The default exists state of the Sprite. +* @return {Phaser.Sprite} The child that was created. +*/ +Phaser.Group.prototype.create = function (x, y, key, frame, exists) { - var child = new Phaser.Sprite(this.game, x, y, key, frame); + if (typeof exists === 'undefined') { exists = true; } + + var child = new Phaser.Sprite(this.game, x, y, key, frame); + + child.group = this; + child.exists = exists; + child.visible = exists; + child.alive = exists; + + this.addChild(child); + + // child.updateTransform(); + + if (child.events) + { + child.events.onAddedToGroup.dispatch(child, this); + } + + if (this.cursor === null) + { + this.cursor = child; + } + + return child; + +} + +/** +* Automatically creates multiple Phaser.Sprite objects and adds them to the top of this Group. +* Useful if you need to quickly generate a pool of identical sprites, such as bullets. By default the sprites will be set to not exist +* and will be positioned at 0, 0 (relative to the Group.x/y) +* +* @method Phaser.Group#createMultiple +* @param {number} quantity - The number of Sprites to create. +* @param {string} key - The Game.cache key of the image that this Sprite will use. +* @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here. +* @param {boolean} [exists=false] - The default exists state of the Sprite. +*/ +Phaser.Group.prototype.createMultiple = function (quantity, key, frame, exists) { + + if (typeof exists === 'undefined') { exists = false; } + + for (var i = 0; i < quantity; i++) + { + var child = new Phaser.Sprite(this.game, 0, 0, key, frame); child.group = this; child.exists = exists; child.visible = exists; child.alive = exists; - this._container.addChild(child); - - child.updateTransform(); + this.addChild(child); + + // child.updateTransform(); if (child.events) { @@ -283,1180 +307,878 @@ Phaser.Group.prototype = { this.cursor = child; } - return child; - - }, - - /** - * Automatically creates multiple Phaser.Sprite objects and adds them to the top of this Group. - * Useful if you need to quickly generate a pool of identical sprites, such as bullets. By default the sprites will be set to not exist - * and will be positioned at 0, 0 (relative to the Group.x/y) - * - * @method Phaser.Group#createMultiple - * @param {number} quantity - The number of Sprites to create. - * @param {string} key - The Game.cache key of the image that this Sprite will use. - * @param {number|string} [frame] - If the Sprite image contains multiple frames you can specify which one to use here. - * @param {boolean} [exists=false] - The default exists state of the Sprite. - */ - createMultiple: function (quantity, key, frame, exists) { - - if (typeof exists === 'undefined') { exists = false; } - - for (var i = 0; i < quantity; i++) - { - var child = new Phaser.Sprite(this.game, 0, 0, key, frame); - - child.group = this; - child.exists = exists; - child.visible = exists; - child.alive = exists; - - this._container.addChild(child); - - child.updateTransform(); - - if (child.events) - { - child.events.onAddedToGroup.dispatch(child, this); - } - - if (this.cursor === null) - { - this.cursor = child; - } - - } - - }, - - /** - * Advances the Group cursor to the next object in the Group. If it's at the end of the Group it wraps around to the first object. - * - * @method Phaser.Group#next - */ - next: function () { - - if (this.cursor) - { - // Wrap the cursor? - if (this.cursor == this._container.last) - { - this.cursor = this._container._iNext; - } - else - { - this.cursor = this.cursor._iNext; - } - } - - }, - - /** - * Moves the Group cursor to the previous object in the Group. If it's at the start of the Group it wraps around to the last object. - * - * @method Phaser.Group#previous - */ - previous: function () { - - if (this.cursor) - { - // Wrap the cursor? - if (this.cursor == this._container._iNext) - { - this.cursor = this._container.last; - } - else - { - this.cursor = this.cursor._iPrev; - } - } - - }, - - /** - * Internal test. - * - * @method Phaser.Group#childTest - */ - childTest: function (prefix, child) { - - var s = prefix + ' next: '; - - if (child._iNext) - { - s = s + child._iNext.name; - } - else - { - s = s + '-null-'; - } - - s = s + ' ' + prefix + ' prev: '; - - if (child._iPrev) - { - s = s + child._iPrev.name; - } - else - { - s = s + '-null-'; - } - - console.log(s); - - }, - - /** - * Internal test. - * - * @method Phaser.Group#swapIndex - */ - swapIndex: function (index1, index2) { - - var child1 = this.getAt(index1); - var child2 = this.getAt(index2); - - this.swap(child1, child2); - - }, - - /** - * Swaps the position of two children in this Group. Both children must be in this Group. - * You cannot swap a child with itself, or swap un-parented children, doing so will return false. - * - * @method Phaser.Group#swap - * @param {*} child1 - The first child to swap. - * @param {*} child2 - The second child to swap. - * @return {boolean} True if the swap was successful, otherwise false. - */ - swap: function (child1, child2) { - - if (child1 === child2 || !child1.parent || !child2.parent || child1.group !== this || child2.group !== this) - { - return false; - } - - // Cache the values - var child1Prev = child1._iPrev; - var child1Next = child1._iNext; - var child2Prev = child2._iPrev; - var child2Next = child2._iNext; - - var endNode = this._container.last._iNext; - var currentNode = this.game.stage._stage; - - do - { - if (currentNode !== child1 && currentNode !== child2) - { - if (currentNode.first === child1) - { - currentNode.first = child2; - } - else if (currentNode.first === child2) - { - currentNode.first = child1; - } - - if (currentNode.last === child1) - { - currentNode.last = child2; - } - else if (currentNode.last === child2) - { - currentNode.last = child1; - } - } - - currentNode = currentNode._iNext; - } - while (currentNode != endNode) - - if (child1._iNext == child2) - { - // This is a downward (A to B) neighbour swap - child1._iNext = child2Next; - child1._iPrev = child2; - child2._iNext = child1; - child2._iPrev = child1Prev; - - if (child1Prev) { child1Prev._iNext = child2; } - if (child2Next) { child2Next._iPrev = child1; } - - if (child1.__renderGroup) - { - child1.__renderGroup.updateTexture(child1); - } - - if (child2.__renderGroup) - { - child2.__renderGroup.updateTexture(child2); - } - - return true; - } - else if (child2._iNext == child1) - { - // This is an upward (B to A) neighbour swap - child1._iNext = child2; - child1._iPrev = child2Prev; - child2._iNext = child1Next; - child2._iPrev = child1; - - if (child2Prev) { child2Prev._iNext = child1; } - if (child1Next) { child1Next._iPrev = child2; } - - if (child1.__renderGroup) - { - child1.__renderGroup.updateTexture(child1); - } - - if (child2.__renderGroup) - { - child2.__renderGroup.updateTexture(child2); - } - - return true; - } - else - { - // Children are far apart - child1._iNext = child2Next; - child1._iPrev = child2Prev; - child2._iNext = child1Next; - child2._iPrev = child1Prev; - - if (child1Prev) { child1Prev._iNext = child2; } - if (child1Next) { child1Next._iPrev = child2; } - if (child2Prev) { child2Prev._iNext = child1; } - if (child2Next) { child2Next._iPrev = child1; } - - if (child1.__renderGroup) - { - child1.__renderGroup.updateTexture(child1); - } - - if (child2.__renderGroup) - { - child2.__renderGroup.updateTexture(child2); - } - - return true; - } - - return false; - - }, - - /** - * Brings the given child to the top of this Group so it renders above all other children. - * - * @method Phaser.Group#bringToTop - * @param {*} child - The child to bring to the top of this Group. - * @return {*} The child that was moved. - */ - bringToTop: function (child) { - - if (child.group === this) - { - this.remove(child); - this.add(child); - } - - return child; - - }, - - /** - * Get the index position of the given child in this Group. - * - * @method Phaser.Group#getIndex - * @param {*} child - The child to get the index for. - * @return {number} The index of the child or -1 if it's not a member of this Group. - */ - getIndex: function (child) { - - return this._container.children.indexOf(child); - - }, - - /** - * Replaces a child of this Group with the given newChild. The newChild cannot be a member of this Group. - * - * @method Phaser.Group#replace - * @param {*} oldChild - The child in this Group that will be replaced. - * @param {*} newChild - The child to be inserted into this group. - */ - replace: function (oldChild, newChild) { - - if (!this._container.first._iNext) - { - return; - } - - var index = this.getIndex(oldChild); - - if (index != -1) - { - if (newChild.parent !== undefined) - { - newChild.events.onRemovedFromGroup.dispatch(newChild, this); - newChild.parent.removeChild(newChild); - } - - this._container.removeChild(oldChild); - this._container.addChildAt(newChild, index); - - newChild.events.onAddedToGroup.dispatch(newChild, this); - newChild.updateTransform(); - - if (this.cursor == oldChild) - { - this.cursor = this._container._iNext; - } - } - - }, - - /** - * Sets the given property to the given value on the child. The operation controls the assignment of the value. - * - * @method Phaser.Group#setProperty - * @param {*} child - The child to set the property value on. - * @param {array} key - An array of strings that make up the property that will be set. - * @param {*} value - The value that will be set. - * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it. - */ - setProperty: function (child, key, value, operation) { - - operation = operation || 0; - - // As ugly as this approach looks, and although it's limited to a depth of only 4, it's extremely fast. - // Much faster than a for loop or object iteration. There are no checks, so if the key isn't valid then it'll fail - // but as you are likely to call this from inner loops that have to perform well, I'll take that trade off. - - // 0 = Equals - // 1 = Add - // 2 = Subtract - // 3 = Multiply - // 4 = Divide - - var len = key.length; - - if (len == 1) - { - if (operation === 0) { child[key[0]] = value; } - else if (operation == 1) { child[key[0]] += value; } - else if (operation == 2) { child[key[0]] -= value; } - else if (operation == 3) { child[key[0]] *= value; } - else if (operation == 4) { child[key[0]] /= value; } - } - else if (len == 2) - { - if (operation === 0) { child[key[0]][key[1]] = value; } - else if (operation == 1) { child[key[0]][key[1]] += value; } - else if (operation == 2) { child[key[0]][key[1]] -= value; } - else if (operation == 3) { child[key[0]][key[1]] *= value; } - else if (operation == 4) { child[key[0]][key[1]] /= value; } - } - else if (len == 3) - { - if (operation === 0) { child[key[0]][key[1]][key[2]] = value; } - else if (operation == 1) { child[key[0]][key[1]][key[2]] += value; } - else if (operation == 2) { child[key[0]][key[1]][key[2]] -= value; } - else if (operation == 3) { child[key[0]][key[1]][key[2]] *= value; } - else if (operation == 4) { child[key[0]][key[1]][key[2]] /= value; } - } - else if (len == 4) - { - if (operation === 0) { child[key[0]][key[1]][key[2]][key[3]] = value; } - else if (operation == 1) { child[key[0]][key[1]][key[2]][key[3]] += value; } - else if (operation == 2) { child[key[0]][key[1]][key[2]][key[3]] -= value; } - else if (operation == 3) { child[key[0]][key[1]][key[2]][key[3]] *= value; } - else if (operation == 4) { child[key[0]][key[1]][key[2]][key[3]] /= value; } - } - - // TODO - Deep property scane - - }, - - /** - * This function allows you to quickly set a property on a single child of this Group to a new value. - * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication. - * - * @method Phaser.Group#set - * @param {Phaser.Sprite} child - The child to set the property on. - * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x' - * @param {*} value - The value that will be set. - * @param {boolean} [checkAlive=false] - If set then the child will only be updated if alive=true. - * @param {boolean} [checkVisible=false] - If set then the child will only be updated if visible=true. - * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it. - */ - set: function (child, key, value, checkAlive, checkVisible, operation) { - - key = key.split('.'); - - if (typeof checkAlive === 'undefined') { checkAlive = false; } - if (typeof checkVisible === 'undefined') { checkVisible = false; } - - if ((checkAlive === false || (checkAlive && child.alive)) && (checkVisible === false || (checkVisible && child.visible))) - { - this.setProperty(child, key, value, operation); - } - - }, - - /** - * This function allows you to quickly set the same property across all children of this Group to a new value. - * The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication. - * - * @method Phaser.Group#setAll - * @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x' - * @param {*} value - The value that will be set. - * @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. - * @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. - * @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it. - */ - setAll: function (key, value, checkAlive, checkVisible, operation) { - - key = key.split('.'); - - if (typeof checkAlive === 'undefined') { checkAlive = false; } - if (typeof checkVisible === 'undefined') { checkVisible = false; } - - operation = operation || 0; - - if (this._container.children.length > 0 && this._container.first._iNext) - { - var currentNode = this._container.first._iNext; - - do - { - if ((checkAlive === false || (checkAlive && currentNode.alive)) && (checkVisible === false || (checkVisible && currentNode.visible))) - { - this.setProperty(currentNode, key, value, operation); - } - - currentNode = currentNode._iNext; - } - while (currentNode != this._container.last._iNext) - } - - }, - - /** - * Adds the amount to the given property on all children in this Group. - * Group.addAll('x', 10) will add 10 to the child.x value. - * - * @method Phaser.Group#addAll - * @param {string} property - The property to increment, for example 'body.velocity.x' or 'angle'. - * @param {number} amount - The amount to increment the property by. If child.x = 10 then addAll('x', 40) would make child.x = 50. - * @param {boolean} checkAlive - If true the property will only be changed if the child is alive. - * @param {boolean} checkVisible - If true the property will only be changed if the child is visible. - */ - addAll: function (property, amount, checkAlive, checkVisible) { - - this.setAll(property, amount, checkAlive, checkVisible, 1); - - }, - - /** - * Subtracts the amount from the given property on all children in this Group. - * Group.subAll('x', 10) will minus 10 from the child.x value. - * - * @method Phaser.Group#subAll - * @param {string} property - The property to decrement, for example 'body.velocity.x' or 'angle'. - * @param {number} amount - The amount to subtract from the property. If child.x = 50 then subAll('x', 40) would make child.x = 10. - * @param {boolean} checkAlive - If true the property will only be changed if the child is alive. - * @param {boolean} checkVisible - If true the property will only be changed if the child is visible. - */ - subAll: function (property, amount, checkAlive, checkVisible) { - - this.setAll(property, amount, checkAlive, checkVisible, 2); - - }, - - /** - * Multiplies the given property by the amount on all children in this Group. - * Group.multiplyAll('x', 2) will x2 the child.x value. - * - * @method Phaser.Group#multiplyAll - * @param {string} property - The property to multiply, for example 'body.velocity.x' or 'angle'. - * @param {number} amount - The amount to multiply the property by. If child.x = 10 then multiplyAll('x', 2) would make child.x = 20. - * @param {boolean} checkAlive - If true the property will only be changed if the child is alive. - * @param {boolean} checkVisible - If true the property will only be changed if the child is visible. - */ - multiplyAll: function (property, amount, checkAlive, checkVisible) { - - this.setAll(property, amount, checkAlive, checkVisible, 3); - - }, - - /** - * Divides the given property by the amount on all children in this Group. - * Group.divideAll('x', 2) will half the child.x value. - * - * @method Phaser.Group#divideAll - * @param {string} property - The property to divide, for example 'body.velocity.x' or 'angle'. - * @param {number} amount - The amount to divide the property by. If child.x = 100 then divideAll('x', 2) would make child.x = 50. - * @param {boolean} checkAlive - If true the property will only be changed if the child is alive. - * @param {boolean} checkVisible - If true the property will only be changed if the child is visible. - */ - divideAll: function (property, amount, checkAlive, checkVisible) { - - this.setAll(property, amount, checkAlive, checkVisible, 4); - - }, - - /** - * Calls a function on all of the children that have exists=true in this Group. - * After the existsValue parameter you can add as many parameters as you like, which will all be passed to the child callback. - * - * @method Phaser.Group#callAllExists - * @param {function} callback - The function that exists on the children that will be called. - * @param {boolean} existsValue - Only children with exists=existsValue will be called. - * @param {...*} parameter - Additional parameters that will be passed to the callback. - */ - callAllExists: function (callback, existsValue) { - - var args = Array.prototype.splice.call(arguments, 2); - - if (this._container.children.length > 0 && this._container.first._iNext) - { - var currentNode = this._container.first._iNext; - - do - { - if (currentNode.exists == existsValue && currentNode[callback]) - { - currentNode[callback].apply(currentNode, args); - } - - currentNode = currentNode._iNext; - } - while (currentNode != this._container.last._iNext) - - } - - }, - - /** - * Returns a reference to a function that exists on a child of the Group based on the given callback array. - * - * @method Phaser.Group#callbackFromArray - * @param {object} child - The object to inspect. - * @param {array} callback - The array of function names. - * @param {number} length - The size of the array (pre-calculated in callAll). - * @protected - */ - callbackFromArray: function (child, callback, length) { - - // Kinda looks like a Christmas tree - - if (length == 1) - { - if (child[callback[0]]) - { - return child[callback[0]]; - } - } - else if (length == 2) - { - if (child[callback[0]][callback[1]]) - { - return child[callback[0]][callback[1]]; - } - } - else if (length == 3) - { - if (child[callback[0]][callback[1]][callback[2]]) - { - return child[callback[0]][callback[1]][callback[2]]; - } - } - else if (length == 4) - { - if (child[callback[0]][callback[1]][callback[2]][callback[3]]) - { - return child[callback[0]][callback[1]][callback[2]][callback[3]]; - } - } - else - { - if (child[callback]) - { - return child[callback]; - } - } - - return false; - - }, - - /** - * Calls a function on all of the children regardless if they are dead or alive (see callAllExists if you need control over that) - * After the method parameter and context you can add as many extra parameters as you like, which will all be passed to the child. - * - * @method Phaser.Group#callAll - * @param {string} method - A string containing the name of the function that will be called. The function must exist on the child. - * @param {string} [context=null] - A string containing the context under which the method will be executed. Set to null to default to the child. - * @param {...*} parameter - Additional parameters that will be passed to the method. - */ - callAll: function (method, context) { - - if (typeof method === 'undefined') - { - return; - } - - // Extract the method into an array - method = method.split('.'); - - var methodLength = method.length; - - if (typeof context === 'undefined') - { - context = null; - } - else - { - // Extract the context into an array - if (typeof context === 'string') - { - context = context.split('.'); - var contextLength = context.length; - } - } - - var args = Array.prototype.splice.call(arguments, 2); - var callback = null; - var callbackContext = null; - - if (this._container.children.length > 0 && this._container.first._iNext) - { - var child = this._container.first._iNext; - - do - { - callback = this.callbackFromArray(child, method, methodLength); - - if (context && callback) - { - callbackContext = this.callbackFromArray(child, context, contextLength); - - if (callback) - { - callback.apply(callbackContext, args); - } - } - else if (callback) - { - callback.apply(child, args); - } - - child = child._iNext; - } - while (child != this._container.last._iNext) - - } - - }, - - /** - * Allows you to call your own function on each member of this Group. You must pass the callback and context in which it will run. - * After the checkExists parameter you can add as many parameters as you like, which will all be passed to the callback along with the child. - * For example: Group.forEach(awardBonusGold, this, true, 100, 500) - * Note: Currently this will skip any children which are Groups themselves. - * - * @method Phaser.Group#forEach - * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. - * @param {Object} callbackContext - The context in which the function should be called (usually 'this'). - * @param {boolean} checkExists - If set only children with exists=true will be passed to the callback, otherwise all children will be passed. - */ - forEach: function (callback, callbackContext, checkExists) { - - if (typeof checkExists === 'undefined') - { - checkExists = false; - } - - var args = Array.prototype.splice.call(arguments, 3); - args.unshift(null); - - if (this._container.children.length > 0 && this._container.first._iNext) - { - var currentNode = this._container.first._iNext; - - do - { - if (checkExists === false || (checkExists && currentNode.exists)) - { - args[0] = currentNode; - callback.apply(callbackContext, args); - } - - currentNode = currentNode._iNext; - } - while (currentNode != this._container.last._iNext); - - } - - }, - - /** - * Allows you to call your own function on each alive member of this Group (where child.alive=true). You must pass the callback and context in which it will run. - * You can add as many parameters as you like, which will all be passed to the callback along with the child. - * For example: Group.forEachAlive(causeDamage, this, 500) - * - * @method Phaser.Group#forEachAlive - * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. - * @param {Object} callbackContext - The context in which the function should be called (usually 'this'). - */ - forEachExists: function (callback, callbackContext) { - - var args = Array.prototype.splice.call(arguments, 2); - args.unshift(null); - - this.iterate('exists', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args); - - }, - - /** - * Allows you to call your own function on each alive member of this Group (where child.alive=true). You must pass the callback and context in which it will run. - * You can add as many parameters as you like, which will all be passed to the callback along with the child. - * For example: Group.forEachAlive(causeDamage, this, 500) - * - * @method Phaser.Group#forEachAlive - * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. - * @param {Object} callbackContext - The context in which the function should be called (usually 'this'). - */ - forEachAlive: function (callback, callbackContext) { - - var args = Array.prototype.splice.call(arguments, 2); - args.unshift(null); - - this.iterate('alive', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args); - - }, - - /** - * Allows you to call your own function on each dead member of this Group (where alive=false). You must pass the callback and context in which it will run. - * You can add as many parameters as you like, which will all be passed to the callback along with the child. - * For example: Group.forEachDead(bringToLife, this) - * - * @method Phaser.Group#forEachDead - * @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. - * @param {Object} callbackContext - The context in which the function should be called (usually 'this'). - */ - forEachDead: function (callback, callbackContext) { - - var args = Array.prototype.splice.call(arguments, 2); - args.unshift(null); - - this.iterate('alive', false, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args); - - }, - - /** - * Call this function to sort the group according to a particular value and order. - * For example to depth sort Sprites for Zelda-style game you might call `group.sort('y', Phaser.Group.SORT_ASCENDING)` at the bottom of your `State.update()`. - * - * @method Phaser.Group#sort - * @param {string} [index='y'] - The `string` name of the property you want to sort on. - * @param {number} [order=Phaser.Group.SORT_ASCENDING] - The `Group` constant that defines the sort order. Possible values are Phaser.Group.SORT_ASCENDING and Phaser.Group.SORT_DESCENDING. - */ - sort: function (index, order) { - - if (typeof index === 'undefined') { index = 'y'; } - if (typeof order === 'undefined') { order = Phaser.Group.SORT_ASCENDING; } - - var swapped; - var temp; - - do { - - swapped = false; - - for (var i = 0, len = this._container.children.length - 1; i < len; i++) - { - if (order == Phaser.Group.SORT_ASCENDING) - { - if (this._container.children[i][index] > this._container.children[i + 1][index]) - { - this.swap(this.getAt(i), this.getAt(i + 1)); - temp = this._container.children[i]; - this._container.children[i] = this._container.children[i + 1]; - this._container.children[i + 1] = temp; - swapped = true; - } - } - else - { - if (this._container.children[i][index] < this._container.children[i + 1][index]) - { - this.swap(this.getAt(i), this.getAt(i + 1)); - temp = this._container.children[i]; - this._container.children[i] = this._container.children[i + 1]; - this._container.children[i + 1] = temp; - swapped = true; - } - } - } - } while (swapped); - - }, - - /** - * Iterates over the children of the Group. When a child has a property matching key that equals the given value, it is considered as a match. - * Matched children can be sent to the optional callback, or simply returned or counted. - * You can add as many callback parameters as you like, which will all be passed to the callback along with the child, after the callbackContext parameter. - * - * @method Phaser.Group#iterate - * @param {string} key - The child property to check, i.e. 'exists', 'alive', 'health' - * @param {any} value - If child.key === this value it will be considered a match. Note that a strict comparison is used. - * @param {number} returnType - How to return the data from this method. Either Phaser.Group.RETURN_NONE, Phaser.Group.RETURN_TOTAL or Phaser.Group.RETURN_CHILD. - * @param {function} [callback=null] - Optional function that will be called on each matching child. Each child of the Group will be passed to it as its first parameter. - * @param {Object} [callbackContext] - The context in which the function should be called (usually 'this'). - * @return {any} Returns either a numeric total (if RETURN_TOTAL was specified) or the child object. - */ - iterate: function (key, value, returnType, callback, callbackContext, args) { - - if (returnType === Phaser.Group.RETURN_TOTAL && this._container.children.length === 0) - { - return 0; - } - - if (typeof callback === 'undefined') - { - callback = false; - } - - var total = 0; - - if (this._container.children.length > 0 && this._container.first._iNext) - { - var currentNode = this._container.first._iNext; - - do - { - if (currentNode[key] === value) - { - total++; - - if (callback) - { - args[0] = currentNode; - callback.apply(callbackContext, args); - } - - if (returnType === Phaser.Group.RETURN_CHILD) - { - return currentNode; - } - } - - currentNode = currentNode._iNext; - } - while (currentNode != this._container.last._iNext); - } - - if (returnType === Phaser.Group.RETURN_TOTAL) - { - return total; - } - else if (returnType === Phaser.Group.RETURN_CHILD) - { - return null; - } - - }, - - /** - * Call this function to retrieve the first object with exists == (the given state) in the Group. - * - * @method Phaser.Group#getFirstExists - * @param {boolean} state - True or false. - * @return {Any} The first child, or null if none found. - */ - getFirstExists: function (state) { - - if (typeof state !== 'boolean') - { - state = true; - } - - return this.iterate('exists', state, Phaser.Group.RETURN_CHILD); - - }, - - /** - * Call this function to retrieve the first object with alive === true in the group. - * This is handy for checking if everything has been wiped out, or choosing a squad leader, etc. - * - * @method Phaser.Group#getFirstAlive - * @return {Any} The first alive child, or null if none found. - */ - getFirstAlive: function () { - - return this.iterate('alive', true, Phaser.Group.RETURN_CHILD); - - }, - - /** - * Call this function to retrieve the first object with alive === false in the group. - * This is handy for checking if everything has been wiped out, or choosing a squad leader, etc. - * - * @method Phaser.Group#getFirstDead - * @return {Any} The first dead child, or null if none found. - */ - getFirstDead: function () { - - return this.iterate('alive', false, Phaser.Group.RETURN_CHILD); - - }, - - /** - * Call this function to find out how many members of the group are alive. - * - * @method Phaser.Group#countLiving - * @return {number} The number of children flagged as alive. - */ - countLiving: function () { - - return this.iterate('alive', true, Phaser.Group.RETURN_TOTAL); - - }, - - /** - * Call this function to find out how many members of the group are dead. - * - * @method Phaser.Group#countDead - * @return {number} The number of children flagged as dead. - */ - countDead: function () { - - return this.iterate('alive', false, Phaser.Group.RETURN_TOTAL); - - }, - - /** - * Returns a member at random from the group. - * - * @method Phaser.Group#getRandom - * @param {number} startIndex - Optional offset off the front of the array. Default value is 0, or the beginning of the array. - * @param {number} length - Optional restriction on the number of values you want to randomly select from. - * @return {Any} A random child of this Group. - */ - getRandom: function (startIndex, length) { - - if (this._container.children.length === 0) - { - return null; - } - - startIndex = startIndex || 0; - length = length || this._container.children.length; - - return this.game.math.getRandom(this._container.children, startIndex, length); - - }, - - /** - * Removes the given child from this Group and sets its group property to null. - * - * @method Phaser.Group#remove - * @param {Any} child - The child to remove. - * @return {boolean} true if the child was removed from this Group, otherwise false. - */ - remove: function (child) { - - if (child.group !== this) - { - return false; - } - - if (child.events) - { - child.events.onRemovedFromGroup.dispatch(child, this); - } - - // Check it's actually in the container - if (child.parent === this._container) - { - this._container.removeChild(child); - } - - if (this.cursor == child) - { - if (this._container._iNext) - { - this.cursor = this._container._iNext; - } - else - { - this.cursor = null; - } - } - - child.group = null; - - return true; - - }, - - /** - * Removes all children from this Group, setting all group properties to null. - * The Group container remains on the display list. - * - * @method Phaser.Group#removeAll - */ - removeAll: function () { - - if (this._container.children.length === 0) - { - return; - } - - do - { - if (this._container.children[0].events) - { - this._container.children[0].events.onRemovedFromGroup.dispatch(this._container.children[0], this); - } - this._container.removeChild(this._container.children[0]); - } - while (this._container.children.length > 0); - - this.cursor = null; - - }, - - /** - * Removes all children from this Group whos index falls beteen the given startIndex and endIndex values. - * - * @method Phaser.Group#removeBetween - * @param {number} startIndex - The index to start removing children from. - * @param {number} endIndex - The index to stop removing children from. Must be higher than startIndex and less than the length of the Group. - */ - removeBetween: function (startIndex, endIndex) { - - if (this._container.children.length === 0) - { - return; - } - - if (startIndex > endIndex || startIndex < 0 || endIndex > this._container.children.length) - { - return false; - } - - for (var i = startIndex; i < endIndex; i++) - { - var child = this._container.children[i]; - child.events.onRemovedFromGroup.dispatch(child, this); - this._container.removeChild(child); - - if (this.cursor == child) - { - if (this._container._iNext) - { - this.cursor = this._container._iNext; - } - else - { - this.cursor = null; - } - } - } - - }, - - /** - * Destroys this Group. Removes all children, then removes the container from the display list and nulls references. - * - * @method Phaser.Group#destroy - * @param {boolean} [destroyChildren=false] - Should every child of this Group have its destroy method called? - */ - destroy: function (destroyChildren) { - - if (typeof destroyChildren === 'undefined') { destroyChildren = false; } - - if (destroyChildren) - { - if (this._container.children.length > 0) - { - do - { - if (this._container.children[0].group) - { - this._container.children[0].destroy(); - } - } - while (this._container.children.length > 0); - } - } - else - { - this.removeAll(); - } - - this._container.parent.removeChild(this._container); - - this._container = null; - - this.game = null; - - this.exists = false; - - this.cursor = null; - - }, - - validate: function () { - - var testObject = this.game.stage._stage.last._iNext; - var displayObject = this.game.stage._stage; - var nextObject = null; - var prevObject = null; - var count = 0; - - do - { - if (count > 0) - { - // check next - if (displayObject !== nextObject) - { - console.log('check next fail'); - return false; - } - - // check previous - if (displayObject._iPrev !== prevObject) - { - console.log('check previous fail'); - return false; - } - } - - // Set the next object - nextObject = displayObject._iNext; - prevObject = displayObject; - - displayObject = displayObject._iNext; - - count++; - - } - while(displayObject != testObject) - - return true; - } -}; +} -Phaser.Group.prototype.constructor = Phaser.Group; +/** +* Advances the Group cursor to the next object in the Group. If it's at the end of the Group it wraps around to the first object. +* +* @method Phaser.Group#next +*/ +Phaser.Group.prototype.next = function () { + + if (this.cursor) + { + // Wrap the cursor? + if (this._cursorIndex === this.children.length) + { + this._cursorIndex = 0; + } + else + { + this._cursorIndex++; + } + + this.cursor = this.children[this._cursorIndex]; + } + +} + +/** +* Moves the Group cursor to the previous object in the Group. If it's at the start of the Group it wraps around to the last object. +* +* @method Phaser.Group#previous +*/ +Phaser.Group.prototype.previous = function () { + + if (this.cursor) + { + // Wrap the cursor? + if (this._cursorIndex === 0) + { + this._cursorIndex = this.children.length - 1; + } + else + { + this._cursorIndex--; + } + + this.cursor = this.children[this._cursorIndex]; + } + +} + +/** +* Swaps the position of two children in this Group. Both children must be in this Group. +* You cannot swap a child with itself, or swap un-parented children, doing so will return false. +* +* @method Phaser.Group#swap +* @param {*} child1 - The first child to swap. +* @param {*} child2 - The second child to swap. +*/ +Phaser.Group.prototype.swap = function (child1, child2) { + + if (child1 === child2 || !child1.parent || !child2.parent || child1.group !== this || child2.group !== this) + { + return false; + } + + this.swapChildren(child1, child2); + +} + +/** +* Brings the given child to the top of this Group so it renders above all other children. +* +* @method Phaser.Group#bringToTop +* @param {*} child - The child to bring to the top of this Group. +* @return {*} The child that was moved. +*/ +Phaser.Group.prototype.bringToTop = function (child) { + + if (child.group === this) + { + this.remove(child); + this.add(child); + } + + return child; + +} + +/** +* Get the index position of the given child in this Group. +* +* @method Phaser.Group#getIndex +* @param {*} child - The child to get the index for. +* @return {number} The index of the child or -1 if it's not a member of this Group. +*/ +Phaser.Group.prototype.getIndex = function (child) { + + return this.children.indexOf(child); + +} + +/** +* Replaces a child of this Group with the given newChild. The newChild cannot be a member of this Group. +* +* @method Phaser.Group#replace +* @param {*} oldChild - The child in this Group that will be replaced. +* @param {*} newChild - The child to be inserted into this group. +*/ +Phaser.Group.prototype.replace = function (oldChild, newChild) { + + var index = this.getIndex(oldChild); + + if (index !== -1) + { + if (newChild.parent !== undefined) + { + newChild.events.onRemovedFromGroup.dispatch(newChild, this); + newChild.parent.removeChild(newChild); + } + + this.removeChild(oldChild); + this.addChildAt(newChild, index); + + newChild.events.onAddedToGroup.dispatch(newChild, this); + // newChild.updateTransform(); + + if (this.cursor === oldChild) + { + this.cursor = newChild; + } + } + +} + +/** +* Sets the given property to the given value on the child. The operation controls the assignment of the value. +* +* @method Phaser.Group#setProperty +* @param {*} child - The child to set the property value on. +* @param {array} key - An array of strings that make up the property that will be set. +* @param {*} value - The value that will be set. +* @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it. +*/ +Phaser.Group.prototype.setProperty = function (child, key, value, operation) { + + operation = operation || 0; + + // As ugly as this approach looks, and although it's limited to a depth of only 4, it's extremely fast. + // Much faster than a for loop or object iteration. There are no checks, so if the key isn't valid then it'll fail + // but as you are likely to call this from inner loops that have to perform well, I'll take that trade off. + + // 0 = Equals + // 1 = Add + // 2 = Subtract + // 3 = Multiply + // 4 = Divide + + var len = key.length; + + if (len == 1) + { + if (operation === 0) { child[key[0]] = value; } + else if (operation == 1) { child[key[0]] += value; } + else if (operation == 2) { child[key[0]] -= value; } + else if (operation == 3) { child[key[0]] *= value; } + else if (operation == 4) { child[key[0]] /= value; } + } + else if (len == 2) + { + if (operation === 0) { child[key[0]][key[1]] = value; } + else if (operation == 1) { child[key[0]][key[1]] += value; } + else if (operation == 2) { child[key[0]][key[1]] -= value; } + else if (operation == 3) { child[key[0]][key[1]] *= value; } + else if (operation == 4) { child[key[0]][key[1]] /= value; } + } + else if (len == 3) + { + if (operation === 0) { child[key[0]][key[1]][key[2]] = value; } + else if (operation == 1) { child[key[0]][key[1]][key[2]] += value; } + else if (operation == 2) { child[key[0]][key[1]][key[2]] -= value; } + else if (operation == 3) { child[key[0]][key[1]][key[2]] *= value; } + else if (operation == 4) { child[key[0]][key[1]][key[2]] /= value; } + } + else if (len == 4) + { + if (operation === 0) { child[key[0]][key[1]][key[2]][key[3]] = value; } + else if (operation == 1) { child[key[0]][key[1]][key[2]][key[3]] += value; } + else if (operation == 2) { child[key[0]][key[1]][key[2]][key[3]] -= value; } + else if (operation == 3) { child[key[0]][key[1]][key[2]][key[3]] *= value; } + else if (operation == 4) { child[key[0]][key[1]][key[2]][key[3]] /= value; } + } + + // TODO - Deep property scane + +} + +/** +* This function allows you to quickly set a property on a single child of this Group to a new value. +* The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication. +* +* @method Phaser.Group#set +* @param {Phaser.Sprite} child - The child to set the property on. +* @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x' +* @param {*} value - The value that will be set. +* @param {boolean} [checkAlive=false] - If set then the child will only be updated if alive=true. +* @param {boolean} [checkVisible=false] - If set then the child will only be updated if visible=true. +* @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it. +*/ +Phaser.Group.prototype.set = function (child, key, value, checkAlive, checkVisible, operation) { + + key = key.split('.'); + + if (typeof checkAlive === 'undefined') { checkAlive = false; } + if (typeof checkVisible === 'undefined') { checkVisible = false; } + + if ((checkAlive === false || (checkAlive && child.alive)) && (checkVisible === false || (checkVisible && child.visible))) + { + this.setProperty(child, key, value, operation); + } + +} + +/** +* This function allows you to quickly set the same property across all children of this Group to a new value. +* The operation parameter controls how the new value is assigned to the property, from simple replacement to addition and multiplication. +* +* @method Phaser.Group#setAll +* @param {string} key - The property, as a string, to be set. For example: 'body.velocity.x' +* @param {*} value - The value that will be set. +* @param {boolean} [checkAlive=false] - If set then only children with alive=true will be updated. +* @param {boolean} [checkVisible=false] - If set then only children with visible=true will be updated. +* @param {number} [operation=0] - Controls how the value is assigned. A value of 0 replaces the value with the new one. A value of 1 adds it, 2 subtracts it, 3 multiplies it and 4 divides it. +*/ +Phaser.Group.prototype.setAll = function (key, value, checkAlive, checkVisible, operation) { + + key = key.split('.'); + + if (typeof checkAlive === 'undefined') { checkAlive = false; } + if (typeof checkVisible === 'undefined') { checkVisible = false; } + + operation = operation || 0; + + for (var i = 0, len = this.children.length; i < len; i++) + { + if ((!checkAlive || (checkAlive && this.children[i].alive)) && (!checkVisible || (checkVisible && this.children[i].visible))) + { + this.setProperty(this.children[i], key, value, operation); + } + } + +} + +/** +* Adds the amount to the given property on all children in this Group. +* Group.addAll('x', 10) will add 10 to the child.x value. +* +* @method Phaser.Group#addAll +* @param {string} property - The property to increment, for example 'body.velocity.x' or 'angle'. +* @param {number} amount - The amount to increment the property by. If child.x = 10 then addAll('x', 40) would make child.x = 50. +* @param {boolean} checkAlive - If true the property will only be changed if the child is alive. +* @param {boolean} checkVisible - If true the property will only be changed if the child is visible. +*/ +Phaser.Group.prototype.addAll = function (property, amount, checkAlive, checkVisible) { + + this.setAll(property, amount, checkAlive, checkVisible, 1); + +} + +/** +* Subtracts the amount from the given property on all children in this Group. +* Group.subAll('x', 10) will minus 10 from the child.x value. +* +* @method Phaser.Group#subAll +* @param {string} property - The property to decrement, for example 'body.velocity.x' or 'angle'. +* @param {number} amount - The amount to subtract from the property. If child.x = 50 then subAll('x', 40) would make child.x = 10. +* @param {boolean} checkAlive - If true the property will only be changed if the child is alive. +* @param {boolean} checkVisible - If true the property will only be changed if the child is visible. +*/ +Phaser.Group.prototype.subAll = function (property, amount, checkAlive, checkVisible) { + + this.setAll(property, amount, checkAlive, checkVisible, 2); + +} + +/** +* Multiplies the given property by the amount on all children in this Group. +* Group.multiplyAll('x', 2) will x2 the child.x value. +* +* @method Phaser.Group#multiplyAll +* @param {string} property - The property to multiply, for example 'body.velocity.x' or 'angle'. +* @param {number} amount - The amount to multiply the property by. If child.x = 10 then multiplyAll('x', 2) would make child.x = 20. +* @param {boolean} checkAlive - If true the property will only be changed if the child is alive. +* @param {boolean} checkVisible - If true the property will only be changed if the child is visible. +*/ +Phaser.Group.prototype.multiplyAll = function (property, amount, checkAlive, checkVisible) { + + this.setAll(property, amount, checkAlive, checkVisible, 3); + +} + +/** +* Divides the given property by the amount on all children in this Group. +* Group.divideAll('x', 2) will half the child.x value. +* +* @method Phaser.Group#divideAll +* @param {string} property - The property to divide, for example 'body.velocity.x' or 'angle'. +* @param {number} amount - The amount to divide the property by. If child.x = 100 then divideAll('x', 2) would make child.x = 50. +* @param {boolean} checkAlive - If true the property will only be changed if the child is alive. +* @param {boolean} checkVisible - If true the property will only be changed if the child is visible. +*/ +Phaser.Group.prototype.divideAll = function (property, amount, checkAlive, checkVisible) { + + this.setAll(property, amount, checkAlive, checkVisible, 4); + +} + +/** +* Calls a function on all of the children that have exists=true in this Group. +* After the existsValue parameter you can add as many parameters as you like, which will all be passed to the child callback. +* +* @method Phaser.Group#callAllExists +* @param {function} callback - The function that exists on the children that will be called. +* @param {boolean} existsValue - Only children with exists=existsValue will be called. +* @param {...*} parameter - Additional parameters that will be passed to the callback. +*/ +Phaser.Group.prototype.callAllExists = function (callback, existsValue) { + + var args = Array.prototype.splice.call(arguments, 2); + + for (var i = 0, len = this.children.length; i < len; i++) + { + if (this.children[i].exists === existsValue && this.children[i][callback]) + { + this.children[i][callback].apply(this.children[i], args); + } + } + +} + +/** +* Returns a reference to a function that exists on a child of the Group based on the given callback array. +* +* @method Phaser.Group#callbackFromArray +* @param {object} child - The object to inspect. +* @param {array} callback - The array of function names. +* @param {number} length - The size of the array (pre-calculated in callAll). +* @protected +*/ +Phaser.Group.prototype.callbackFromArray = function (child, callback, length) { + + // Kinda looks like a Christmas tree + + if (length == 1) + { + if (child[callback[0]]) + { + return child[callback[0]]; + } + } + else if (length == 2) + { + if (child[callback[0]][callback[1]]) + { + return child[callback[0]][callback[1]]; + } + } + else if (length == 3) + { + if (child[callback[0]][callback[1]][callback[2]]) + { + return child[callback[0]][callback[1]][callback[2]]; + } + } + else if (length == 4) + { + if (child[callback[0]][callback[1]][callback[2]][callback[3]]) + { + return child[callback[0]][callback[1]][callback[2]][callback[3]]; + } + } + else + { + if (child[callback]) + { + return child[callback]; + } + } + + return false; + +} + +/** +* Calls a function on all of the children regardless if they are dead or alive (see callAllExists if you need control over that) +* After the method parameter and context you can add as many extra parameters as you like, which will all be passed to the child. +* +* @method Phaser.Group#callAll +* @param {string} method - A string containing the name of the function that will be called. The function must exist on the child. +* @param {string} [context=null] - A string containing the context under which the method will be executed. Set to null to default to the child. +* @param {...*} parameter - Additional parameters that will be passed to the method. +*/ +Phaser.Group.prototype.callAll = function (method, context) { + + if (typeof method === 'undefined') + { + return; + } + + // Extract the method into an array + method = method.split('.'); + + var methodLength = method.length; + + if (typeof context === 'undefined') + { + context = null; + } + else + { + // Extract the context into an array + if (typeof context === 'string') + { + context = context.split('.'); + var contextLength = context.length; + } + } + + var args = Array.prototype.splice.call(arguments, 2); + var callback = null; + var callbackContext = null; + + for (var i = 0, len = this.children.length; i < len; i++) + { + callback = this.callbackFromArray(this.children[i], method, methodLength); + + if (context && callback) + { + callbackContext = this.callbackFromArray(this.children[i], context, contextLength); + + if (callback) + { + callback.apply(callbackContext, args); + } + } + else if (callback) + { + callback.apply(this.children[i], args); + } + } + +} + +/** +* Allows you to call your own function on each member of this Group. You must pass the callback and context in which it will run. +* After the checkExists parameter you can add as many parameters as you like, which will all be passed to the callback along with the child. +* For example: Group.forEach(awardBonusGold, this, true, 100, 500) +* Note: Currently this will skip any children which are Groups themselves. +* +* @method Phaser.Group#forEach +* @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. +* @param {Object} callbackContext - The context in which the function should be called (usually 'this'). +* @param {boolean} checkExists - If set only children with exists=true will be passed to the callback, otherwise all children will be passed. +*/ +Phaser.Group.prototype.forEach = function (callback, callbackContext, checkExists) { + + if (typeof checkExists === 'undefined') + { + checkExists = false; + } + + var args = Array.prototype.splice.call(arguments, 3); + args.unshift(null); + + for (var i = 0, len = this.children.length; i < len; i++) + { + if (!checkExists || (checkExists && this.children[i].exists)) + { + args[0] = this.children[i]; + callback.apply(callbackContext, args); + } + } + +} + +/** +* Allows you to call your own function on each alive member of this Group (where child.alive=true). You must pass the callback and context in which it will run. +* You can add as many parameters as you like, which will all be passed to the callback along with the child. +* For example: Group.forEachAlive(causeDamage, this, 500) +* +* @method Phaser.Group#forEachAlive +* @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. +* @param {Object} callbackContext - The context in which the function should be called (usually 'this'). +*/ +Phaser.Group.prototype.forEachExists = function (callback, callbackContext) { + + var args = Array.prototype.splice.call(arguments, 2); + args.unshift(null); + + this.iterate('exists', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args); + +} + +/** +* Allows you to call your own function on each alive member of this Group (where child.alive=true). You must pass the callback and context in which it will run. +* You can add as many parameters as you like, which will all be passed to the callback along with the child. +* For example: Group.forEachAlive(causeDamage, this, 500) +* +* @method Phaser.Group#forEachAlive +* @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. +* @param {Object} callbackContext - The context in which the function should be called (usually 'this'). +*/ +Phaser.Group.prototype.forEachAlive = function (callback, callbackContext) { + + var args = Array.prototype.splice.call(arguments, 2); + args.unshift(null); + + this.iterate('alive', true, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args); + +} + +/** +* Allows you to call your own function on each dead member of this Group (where alive=false). You must pass the callback and context in which it will run. +* You can add as many parameters as you like, which will all be passed to the callback along with the child. +* For example: Group.forEachDead(bringToLife, this) +* +* @method Phaser.Group#forEachDead +* @param {function} callback - The function that will be called. Each child of the Group will be passed to it as its first parameter. +* @param {Object} callbackContext - The context in which the function should be called (usually 'this'). +*/ +Phaser.Group.prototype.forEachDead = function (callback, callbackContext) { + + var args = Array.prototype.splice.call(arguments, 2); + args.unshift(null); + + this.iterate('alive', false, Phaser.Group.RETURN_TOTAL, callback, callbackContext, args); + +} + +/** +* Call this function to sort the group according to a particular value and order. +* For example to depth sort Sprites for Zelda-style game you might call `group.sort('y', Phaser.Group.SORT_ASCENDING)` at the bottom of your `State.update()`. +* +* @method Phaser.Group#sort +* @param {string} [index='y'] - The `string` name of the property you want to sort on. +* @param {number} [order=Phaser.Group.SORT_ASCENDING] - The `Group` constant that defines the sort order. Possible values are Phaser.Group.SORT_ASCENDING and Phaser.Group.SORT_DESCENDING. +*/ +Phaser.Group.prototype.sort = function (index, order) { + + if (typeof index === 'undefined') { index = 'y'; } + if (typeof order === 'undefined') { order = Phaser.Group.SORT_ASCENDING; } + + /* + var swapped; + var temp; + + do { + + swapped = false; + + for (var i = 0, len = this._container.children.length - 1; i < len; i++) + { + if (order == Phaser.Group.SORT_ASCENDING) + { + if (this._container.children[i][index] > this._container.children[i + 1][index]) + { + this.swap(this.getAt(i), this.getAt(i + 1)); + temp = this._container.children[i]; + this._container.children[i] = this._container.children[i + 1]; + this._container.children[i + 1] = temp; + swapped = true; + } + } + else + { + if (this._container.children[i][index] < this._container.children[i + 1][index]) + { + this.swap(this.getAt(i), this.getAt(i + 1)); + temp = this._container.children[i]; + this._container.children[i] = this._container.children[i + 1]; + this._container.children[i + 1] = temp; + swapped = true; + } + } + } + } while (swapped); + */ + +} + +/** +* Iterates over the children of the Group. When a child has a property matching key that equals the given value, it is considered as a match. +* Matched children can be sent to the optional callback, or simply returned or counted. +* You can add as many callback parameters as you like, which will all be passed to the callback along with the child, after the callbackContext parameter. +* +* @method Phaser.Group#iterate +* @param {string} key - The child property to check, i.e. 'exists', 'alive', 'health' +* @param {any} value - If child.key === this value it will be considered a match. Note that a strict comparison is used. +* @param {number} returnType - How to return the data from this method. Either Phaser.Group.RETURN_NONE, Phaser.Group.RETURN_TOTAL or Phaser.Group.RETURN_CHILD. +* @param {function} [callback=null] - Optional function that will be called on each matching child. Each child of the Group will be passed to it as its first parameter. +* @param {Object} [callbackContext] - The context in which the function should be called (usually 'this'). +* @return {any} Returns either a numeric total (if RETURN_TOTAL was specified) or the child object. +*/ +Phaser.Group.prototype.iterate = function (key, value, returnType, callback, callbackContext, args) { + + if (returnType === Phaser.Group.RETURN_TOTAL && this.children.length === 0) + { + return 0; + } + + if (typeof callback === 'undefined') + { + callback = false; + } + + var total = 0; + + for (var i = 0, len = this.children.length; i < len; i++) + { + if (this.children[i][key] === value) + { + total++; + + if (callback) + { + args[0] = this.children[i]; + callback.apply(callbackContext, args); + } + + if (returnType === Phaser.Group.RETURN_CHILD) + { + return this.children[i]; + } + } + } + + if (returnType === Phaser.Group.RETURN_TOTAL) + { + return total; + } + else if (returnType === Phaser.Group.RETURN_CHILD) + { + return null; + } + +} + +/** +* Call this function to retrieve the first object with exists == (the given state) in the Group. +* +* @method Phaser.Group#getFirstExists +* @param {boolean} state - True or false. +* @return {Any} The first child, or null if none found. +*/ +Phaser.Group.prototype.getFirstExists = function (state) { + + if (typeof state !== 'boolean') + { + state = true; + } + + return this.iterate('exists', state, Phaser.Group.RETURN_CHILD); + +} + +/** +* Call this function to retrieve the first object with alive === true in the group. +* This is handy for checking if everything has been wiped out, or choosing a squad leader, etc. +* +* @method Phaser.Group#getFirstAlive +* @return {Any} The first alive child, or null if none found. +*/ +Phaser.Group.prototype.getFirstAlive = function () { + + return this.iterate('alive', true, Phaser.Group.RETURN_CHILD); + +} + +/** +* Call this function to retrieve the first object with alive === false in the group. +* This is handy for checking if everything has been wiped out, or choosing a squad leader, etc. +* +* @method Phaser.Group#getFirstDead +* @return {Any} The first dead child, or null if none found. +*/ +Phaser.Group.prototype.getFirstDead = function () { + + return this.iterate('alive', false, Phaser.Group.RETURN_CHILD); + +} + +/** +* Call this function to find out how many members of the group are alive. +* +* @method Phaser.Group#countLiving +* @return {number} The number of children flagged as alive. +*/ +Phaser.Group.prototype.countLiving = function () { + + return this.iterate('alive', true, Phaser.Group.RETURN_TOTAL); + +} + +/** +* Call this function to find out how many members of the group are dead. +* +* @method Phaser.Group#countDead +* @return {number} The number of children flagged as dead. +*/ +Phaser.Group.prototype.countDead = function () { + + return this.iterate('alive', false, Phaser.Group.RETURN_TOTAL); + +} + +/** +* Returns a member at random from the group. +* +* @method Phaser.Group#getRandom +* @param {number} startIndex - Optional offset off the front of the array. Default value is 0, or the beginning of the array. +* @param {number} length - Optional restriction on the number of values you want to randomly select from. +* @return {Any} A random child of this Group. +*/ +Phaser.Group.prototype.getRandom = function (startIndex, length) { + + if (this.children.length === 0) + { + return null; + } + + startIndex = startIndex || 0; + length = length || this.children.length; + + return this.game.math.getRandom(this.children, startIndex, length); + +} + +/** +* Removes the given child from this Group and sets its group property to null. +* +* @method Phaser.Group#remove +* @param {Any} child - The child to remove. +* @return {boolean} true if the child was removed from this Group, otherwise false. +*/ +Phaser.Group.prototype.remove = function (child) { + + if (child.group !== this) + { + return false; + } + + if (child.events) + { + child.events.onRemovedFromGroup.dispatch(child, this); + } + + // Check it's actually in the container + if (child.parent === this) + { + this.removeChild(child); + } + + if (this.cursor === child) + { + this.next(); + } + + child.group = null; + + return true; + +} + +/** +* Removes all children from this Group, setting all group properties to null. +* The Group container remains on the display list. +* +* @method Phaser.Group#removeAll +*/ +Phaser.Group.prototype.removeAll = function () { + + if (this.children.length === 0) + { + return; + } + + do + { + if (this.children[0].events) + { + this.children[0].events.onRemovedFromGroup.dispatch(this.children[0], this); + } + this.removeChild(this.children[0]); + } + while (this.children.length > 0); + + this.cursor = null; + +} + +/** +* Removes all children from this Group whos index falls beteen the given startIndex and endIndex values. +* +* @method Phaser.Group#removeBetween +* @param {number} startIndex - The index to start removing children from. +* @param {number} endIndex - The index to stop removing children from. Must be higher than startIndex and less than the length of the Group. +*/ +Phaser.Group.prototype.removeBetween = function (startIndex, endIndex) { + + if (this.children.length === 0) + { + return; + } + + if (startIndex > endIndex || startIndex < 0 || endIndex > this.children.length) + { + return false; + } + + for (var i = startIndex; i < endIndex; i++) + { + var child = this.children[i]; + child.events.onRemovedFromGroup.dispatch(child, this); + this.removeChild(child); + + if (this.cursor === child) + { + this.cursor = null; + } + } + +} + +/** +* Destroys this Group. Removes all children, then removes the container from the display list and nulls references. +* +* @method Phaser.Group#destroy +* @param {boolean} [destroyChildren=false] - Should every child of this Group have its destroy method called? +*/ +Phaser.Group.prototype.destroy = function (destroyChildren) { + + if (typeof destroyChildren === 'undefined') { destroyChildren = false; } + + if (destroyChildren) + { + if (this.children.length > 0) + { + do + { + if (this.children[0].group) + { + this.children[0].destroy(); + } + } + while (this.children.length > 0); + } + } + else + { + this.removeAll(); + } + + this.parent.removeChild(this); + + this.game = null; + + this.exists = false; + + this.cursor = null; + +} /** * @name Phaser.Group#total @@ -1467,14 +1189,7 @@ Object.defineProperty(Phaser.Group.prototype, "total", { get: function () { - if (this._container) - { - return this.iterate('exists', true, Phaser.Group.RETURN_TOTAL); - } - else - { - return 0; - } + return this.iterate('exists', true, Phaser.Group.RETURN_TOTAL); } @@ -1489,55 +1204,12 @@ Object.defineProperty(Phaser.Group.prototype, "length", { get: function () { - if (this._container) - { - return this._container.children.length; - } - else - { - return 0; - } + return this.children.length; } }); -/** -* The x coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates. -* This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position. -* @name Phaser.Group#x -* @property {number} x - The x coordinate of the Group container. -*/ -Object.defineProperty(Phaser.Group.prototype, "x", { - - get: function () { - return this._container.position.x; - }, - - set: function (value) { - this._container.position.x = value; - } - -}); - -/** -* The y coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates. -* This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position. -* @name Phaser.Group#y -* @property {number} y - The y coordinate of the Group container. -*/ -Object.defineProperty(Phaser.Group.prototype, "y", { - - get: function () { - return this._container.position.y; - }, - - set: function (value) { - this._container.position.y = value; - } - -}); - /** * The angle of rotation of the Group container. This will adjust the Group container itself by modifying its rotation. * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position. @@ -1547,61 +1219,44 @@ Object.defineProperty(Phaser.Group.prototype, "y", { Object.defineProperty(Phaser.Group.prototype, "angle", { get: function() { - return Phaser.Math.radToDeg(this._container.rotation); + return Phaser.Math.radToDeg(this.rotation); }, set: function(value) { - this._container.rotation = Phaser.Math.degToRad(value); + this.rotation = Phaser.Math.degToRad(value); } }); +// Documentation stubs + +/** +* The x coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates. +* This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position. +* @name Phaser.Group#x +* @property {number} x - The x coordinate of the Group container. +*/ + +/** +* The y coordinate of the Group container. You can adjust the Group container itself by modifying its coordinates. +* This will have no impact on the x/y coordinates of its children, but it will update their worldTransform and on-screen position. +* @name Phaser.Group#y +* @property {number} y - The y coordinate of the Group container. +*/ + /** * The angle of rotation of the Group container. This will adjust the Group container itself by modifying its rotation. * This will have no impact on the rotation value of its children, but it will update their worldTransform and on-screen position. * @name Phaser.Group#rotation * @property {number} rotation - The angle of rotation given in radians. */ -Object.defineProperty(Phaser.Group.prototype, "rotation", { - - get: function () { - return this._container.rotation; - }, - - set: function (value) { - this._container.rotation = value; - } - -}); /** * @name Phaser.Group#visible * @property {boolean} visible - The visible state of the Group. Non-visible Groups and all of their children are not rendered. */ -Object.defineProperty(Phaser.Group.prototype, "visible", { - - get: function () { - return this._container.visible; - }, - - set: function (value) { - this._container.visible = value; - } - -}); /** * @name Phaser.Group#alpha * @property {number} alpha - The alpha value of the Group container. */ -Object.defineProperty(Phaser.Group.prototype, "alpha", { - - get: function () { - return this._container.alpha; - }, - - set: function (value) { - this._container.alpha = value; - } - -}); diff --git a/src/core/World.js b/src/core/World.js index 0bb15ddd..8a341a02 100644 --- a/src/core/World.js +++ b/src/core/World.js @@ -54,38 +54,28 @@ Phaser.World.prototype.boot = function () { this.camera = new Phaser.Camera(this.game, 0, 0, 0, this.game.width, this.game.height); - this.camera.displayObject = this._container; + this.camera.displayObject = this; this.game.camera = this.camera; + this.game.stage._stage.addChild(this); + } /** * This is called automatically after the plugins preUpdate and before the State.update. * Most objects have preUpdate methods and it's where initial movement, drawing and calculations are done. * -* @method Phaser.World#update +* @method Phaser.World#preUpdate */ Phaser.World.prototype.preUpdate = function () { - if (this.game.stage._stage.first._iNext) + for (var i = 0, len = this.children.length; i < len; i++) { - var currentNode = this.game.stage._stage.first._iNext; - - do + if (this.children[i]['preUpdate']) { - // If preUpdate exists, and it returns false, skip PIXI child objects - if (currentNode['preUpdate'] && !currentNode.preUpdate()) - { - currentNode = currentNode.last._iNext; - } - else - { - currentNode = currentNode._iNext; - } - + this.children[i].preUpdate(); } - while (currentNode != this.game.stage._stage.last._iNext) } } @@ -98,26 +88,12 @@ Phaser.World.prototype.preUpdate = function () { */ Phaser.World.prototype.update = function () { - this.currentRenderOrderID = 0; - - if (this.game.stage._stage.first._iNext) + for (var i = 0, len = this.children.length; i < len; i++) { - var currentNode = this.game.stage._stage.first._iNext; - - do + if (this.children[i]['update']) { - // If update exists, and it returns false, skip PIXI child objects - if (currentNode['update'] && !currentNode.update()) - { - currentNode = currentNode.last._iNext; - } - else - { - currentNode = currentNode._iNext; - } - + this.children[i].update(); } - while (currentNode != this.game.stage._stage.last._iNext) } } @@ -138,40 +114,24 @@ Phaser.World.prototype.postUpdate = function () { this.camera.update(); - if (this.game.stage._stage.first._iNext) + for (var i = 0, len = this.children.length; i < len; i++) { - var currentNode = this.game.stage._stage.first._iNext; - - do + if (this.children[i]['postUpdate']) { - if (currentNode['postUpdate'] && currentNode !== this.camera.target) - { - currentNode.postUpdate(); - } - - currentNode = currentNode._iNext; + this.children[i].postUpdate(); } - while (currentNode != this.game.stage._stage.last._iNext) } } else { this.camera.update(); - if (this.game.stage._stage.first._iNext) + for (var i = 0, len = this.children.length; i < len; i++) { - var currentNode = this.game.stage._stage.first._iNext; - - do + if (this.children[i]['postUpdate']) { - if (currentNode['postUpdate']) - { - currentNode.postUpdate(); - } - - currentNode = currentNode._iNext; + this.children[i].postUpdate(); } - while (currentNode != this.game.stage._stage.last._iNext) } } @@ -327,18 +287,3 @@ Object.defineProperty(Phaser.World.prototype, "randomY", { }); -/** -* @name Phaser.World#visible -* @property {boolean} visible - Gets or sets the visible state of the World. -*/ -Object.defineProperty(Phaser.World.prototype, "visible", { - - get: function () { - return this._container.visible; - }, - - set: function (value) { - this._container.visible = value; - } - -}); diff --git a/src/gameobjects/RenderTexture.js b/src/gameobjects/RenderTexture.js index 0c98b577..b6eab596 100644 --- a/src/gameobjects/RenderTexture.js +++ b/src/gameobjects/RenderTexture.js @@ -85,11 +85,6 @@ Phaser.RenderTexture.prototype.render = function(displayObject, position, clear, if (typeof clear === 'undefined') { clear = false; } if (typeof renderHidden === 'undefined') { renderHidden = false; } - if (displayObject instanceof Phaser.Group) - { - displayObject = displayObject._container; - } - if (PIXI.gl) { this.renderWebGL(displayObject, position, clear, renderHidden); diff --git a/src/particles/arcade/Emitter.js b/src/particles/arcade/Emitter.js index 444d30fe..e31e59ef 100644 --- a/src/particles/arcade/Emitter.js +++ b/src/particles/arcade/Emitter.js @@ -519,7 +519,6 @@ Phaser.Particles.Arcade.Emitter.prototype.at = function (object) { * The emitters alpha value. * @name Phaser.Particles.Arcade.Emitter#alpha * @property {number} alpha - Gets or sets the alpha value of the Emitter. -*/ Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "alpha", { get: function () { @@ -531,12 +530,12 @@ Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "alpha", { } }); +*/ /** * The emitter visible state. * @name Phaser.Particles.Arcade.Emitter#visible * @property {boolean} visible - Gets or sets the Emitter visible state. -*/ Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "visible", { get: function () { @@ -548,6 +547,7 @@ Object.defineProperty(Phaser.Particles.Arcade.Emitter.prototype, "visible", { } }); +*/ /** * @name Phaser.Particles.Arcade.Emitter#x diff --git a/src/physics/arcade/ArcadePhysics.js b/src/physics/arcade/ArcadePhysics.js index 9e73a67c..96bbff5a 100644 --- a/src/physics/arcade/ArcadePhysics.js +++ b/src/physics/arcade/ArcadePhysics.js @@ -636,15 +636,15 @@ Phaser.Physics.Arcade.prototype = { return; } - var len = group._container.children.length; + var len = group.children.length; for (var i = 0; i < len; i++) { for (var j = i + 1; j <= len; j++) { - if (group._container.children[i] && group._container.children[j] && group._container.children[i].exists && group._container.children[j].exists) + if (group.children[i] && group.children[j] && group.children[i].exists && group.children[j].exists) { - this.collideSpriteVsSprite(group._container.children[i], group._container.children[j], collideCallback, processCallback, callbackContext, overlapOnly); + this.collideSpriteVsSprite(group.children[i], group.children[j], collideCallback, processCallback, callbackContext, overlapOnly); } } } @@ -664,19 +664,12 @@ Phaser.Physics.Arcade.prototype = { return; } - if (group1._container.first._iNext) + for (var i = 0, len = group1.children.length; i < len; i++) { - var currentNode = group1._container.first._iNext; - - do + if (group1.children[i].exists) { - if (currentNode.exists) - { - this.collideSpriteVsGroup(currentNode, group2, collideCallback, processCallback, callbackContext, overlapOnly); - } - currentNode = currentNode._iNext; + this.collideSpriteVsGroup(group1.children[i], group2, collideCallback, processCallback, callbackContext, overlapOnly); } - while (currentNode != group1._container.last._iNext); } }, @@ -746,19 +739,12 @@ Phaser.Physics.Arcade.prototype = { return; } - if (group._container.first._iNext) + for (var i = 0, len = group.children.length; i < len; i++) { - var currentNode = group._container.first._iNext; - - do + if (group.children[i].exists) { - if (currentNode.exists) - { - this.collideSpriteVsTilemapLayer(currentNode, tilemapLayer, collideCallback, processCallback, callbackContext); - } - currentNode = currentNode._iNext; + this.collideSpriteVsTilemapLayer(group.children[i], tilemapLayer, collideCallback, processCallback, callbackContext); } - while (currentNode != group._container.last._iNext); } },