diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 6adac87f..16d87575 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -48,6 +48,11 @@ module Phaser.Components.Sprite { */ public priorityID:number = 0; + /** + * The index of this Input component entry in the Game.Input manager. + */ + public indexID:number = 0; + private _dragPoint: Point; private _draggedPointerID: number; public dragOffset: Point; @@ -58,6 +63,7 @@ module Phaser.Components.Sprite { public allowHorizontalDrag: bool = true; public allowVerticalDrag: bool = true; + public bringToTop: bool = false; public snapOnDrag: bool = false; public snapOnRelease: bool = false; @@ -245,11 +251,26 @@ module Phaser.Components.Sprite { { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this.sprite); + this.game.input.removeGameObject(this.indexID); } } + /** + * Clean up memory. + */ + public destroy() { + + if (this.enabled) + { + this.game.input.removeGameObject(this.indexID); + } + + } + + /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ public checkPointerOver(pointer: Phaser.Pointer): bool { if (this.enabled == false || this.sprite.visible == false) @@ -258,7 +279,7 @@ module Phaser.Components.Sprite { } else { - return RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); + return SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); } } @@ -279,7 +300,7 @@ module Phaser.Components.Sprite { } else if (this._pointerData[pointer.id].isOver == true) { - if (RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) + if (SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) { this._pointerData[pointer.id].x = pointer.x - this.sprite.x; this._pointerData[pointer.id].y = pointer.y - this.sprite.y; @@ -350,6 +371,11 @@ module Phaser.Components.Sprite { this.startDrag(pointer); } + if (this.bringToTop) + { + this.sprite.group.bringToTop(this.sprite); + } + } // Consume the event? @@ -493,16 +519,18 @@ module Phaser.Components.Sprite { * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - public enableDrag(lockCenter:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Phaser.Sprite = null):void + public enableDrag(lockCenter:bool = false, bringToTop:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Phaser.Sprite = null):void { this._dragPoint = new Point; this.draggable = true; + this.bringToTop = bringToTop; this.dragOffset = new Point; this.dragFromCenter = lockCenter; @@ -559,6 +587,11 @@ module Phaser.Components.Sprite { this.updateDrag(pointer); + if (this.bringToTop) + { + this.sprite.group.bringToTop(this.sprite); + } + } /** diff --git a/Phaser/core/Group.ts b/Phaser/core/Group.ts index ad9397d7..812b0791 100644 --- a/Phaser/core/Group.ts +++ b/Phaser/core/Group.ts @@ -583,6 +583,14 @@ module Phaser { } + /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ public swap(child1, child2, sort?: bool = true): bool { if (child1.group.ID != this.ID || child2.group.ID != this.ID || child1 === child2) @@ -604,6 +612,43 @@ module Phaser { } + public bringToTop(child): bool { + + // If child not in this group, or is already at the top of the group, return false + if (child.group.ID != this.ID || child.z == this._zCounter) + { + return false; + } + + this.sort(); + + // What's the z index of the top most child? + var tempZ: number = child.z; + var childIndex: number = this._zCounter; + + this._i = 0; + + while (this._i < this.length) + { + this._member = this.members[this._i++]; + + if (this._i > childIndex) + { + this._member.z--; + } + else if (this._member.z == child.z) + { + childIndex = this._i; + this._member.z = this._zCounter; + } + } + + this.sort(); + + return true; + + } + /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 74d2176d..488bf62f 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -40,7 +40,6 @@ module Phaser { this.z = -1; this.group = null; - // No dependencies this.animations = new Phaser.Components.AnimationManager(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -74,6 +73,11 @@ module Phaser { this.transform.setCache(); + // Handy proxies + this.scale = this.transform.scale; + this.alpha = this.texture.alpha; + this.origin = this.transform.origin; + } /** @@ -194,6 +198,23 @@ module Phaser { this.transform.rotation = this.game.math.wrap(value, 360, 0); } + /** + * The scale of the Sprite. A value of 1 is original scale. 0.5 is half size. 2 is double the size. + * This is a reference to Sprite.transform.scale + */ + public scale: Phaser.Vec2; + + /** + * The alpha of the Sprite between 0 and 1, a value of 1 being fully opaque. + */ + public alpha: number; + + /** + * The origin of the Sprite around which rotation and positioning takes place. + * This is a reference to Sprite.transform.origin + */ + public origin: Phaser.Vec2; + /** * Set the animation frame by frame number. */ @@ -318,8 +339,7 @@ module Phaser { */ public destroy() { - //this.input.destroy(); - + this.input.destroy(); } diff --git a/Phaser/input/Input.ts b/Phaser/input/Input.ts index 6c76469d..32ed80cd 100644 --- a/Phaser/input/Input.ts +++ b/Phaser/input/Input.ts @@ -455,22 +455,46 @@ module Phaser { public inputObjects = []; public totalTrackedObjects: number = 0; - // Add Input Enabled array + add/remove methods and then iterate and update them during the main update - // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed - + /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ public addGameObject(object) { - // Lots more checks here + // Find a spare slot + for (var i = 0; i < this.inputObjects.length; i++) + { + if (this.inputObjects[i] == null) + { + this.inputObjects[i] = object; + object.input.indexID = i; + this.totalTrackedObjects++; + return; + } + } + + // If we got this far we need to push a new entry into the array + object.input.indexID = this.inputObjects.length; + this.inputObjects.push(object); + this.totalTrackedObjects++; + } - public removeGameObject(object) { - // TODO + /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + public removeGameObject(index: number) { + + if (this.inputObjects[index]) + { + this.inputObjects[index] = null; + } + } - - /** * Updates the Input Manager. Called by the core Game loop. * @method update @@ -521,7 +545,7 @@ module Phaser { if (this.pointer10) { this.pointer10.reset(); } this.currentPointers = 0; - + this._game.stage.canvas.style.cursor = "default"; if (hard == true) @@ -618,7 +642,7 @@ module Phaser { * @param {Any} event The event data from the Touch event * @return {Pointer} The Pointer object that was started or null if no Pointer object is available **/ - public startPointer(event):Pointer { + public startPointer(event): Pointer { if (this.maxPointers < 10 && this.totalActivePointers == this.maxPointers) { @@ -677,7 +701,7 @@ module Phaser { * @param {Any} event The event data from the Touch event * @return {Pointer} The Pointer object that was updated or null if no Pointer object is available **/ - public updatePointer(event):Pointer { + public updatePointer(event): Pointer { // Unrolled for speed if (this.pointer1.active == true && this.pointer1.identifier == event.identifier) @@ -731,7 +755,7 @@ module Phaser { * @param {Any} event The event data from the Touch event * @return {Pointer} The Pointer object that was stopped or null if no Pointer object is available **/ - public stopPointer(event):Pointer { + public stopPointer(event): Pointer { // Unrolled for speed if (this.pointer1.active == true && this.pointer1.identifier == event.identifier) diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index 7b89d213..b854a1ce 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -422,7 +422,7 @@ module Phaser { for (var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if (this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) + if (this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { _highestRenderID = this.game.input.inputObjects[i].renderOrderID; _highestRenderObject = i; @@ -510,7 +510,7 @@ module Phaser { for (var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if (this.game.input.inputObjects[i].input.enabled) + if (this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.enabled) { this.game.input.inputObjects[i].input._releasedHandler(this); } diff --git a/Phaser/loader/Cache.ts b/Phaser/loader/Cache.ts index 4cd8a1dc..94ef30b8 100644 --- a/Phaser/loader/Cache.ts +++ b/Phaser/loader/Cache.ts @@ -261,6 +261,57 @@ module Phaser { } + /** + * Returns an array containing all of the keys of Images in the Cache. + * @return {Array} The string based keys in the Cache. + */ + public getImageKeys() { + + var output = []; + + for (var item in this._images) + { + output.push(item); + } + + return output; + + } + + /** + * Returns an array containing all of the keys of Sounds in the Cache. + * @return {Array} The string based keys in the Cache. + */ + public getSoundKeys() { + + var output = []; + + for (var item in this._sounds) + { + output.push(item); + } + + return output; + + } + + /** + * Returns an array containing all of the keys of Text Files in the Cache. + * @return {Array} The string based keys in the Cache. + */ + public getTextKeys() { + + var output = []; + + for (var item in this._text) + { + output.push(item); + } + + return output; + + } + /** * Clean up cache memory. */ diff --git a/README.md b/README.md index bdc6655a..eefeff1e 100644 --- a/README.md +++ b/README.md @@ -33,18 +33,15 @@ TODO: * If the Camera is larger than the Stage size then the rotation offset isn't correct * Texture Repeat doesn't scroll, because it's part of the camera not the world, need to think about this more * Bug: Sprite x/y gets shifted if dynamic from the original value -* Input CSS cursor those little 4-way arrows on drag? * Stage CSS3 transforms!!! Color tints, sepia, greyscale, all of those cool things :) * Add JSON Texture Atlas object support. * Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones * Pointer.getWorldX(camera) needs to take camera scale into consideration -* Add a 'click to bring to top' demo (+ Group feature?) * If stage.clear set to false and game pauses, when it unpauses you still see the pause arrow - resolve this * Add clip support + shape options to Texture Component. * Make sure I'm using Point and not Vec2 when it's not a directional vector I need * Bug with setting scale or anything on a Sprite inside a Group, or maybe group.addNewSprite issue -* Make input check use the rotated sprite check * Sprite collision events * See which functions in the input component can move elsewhere (utils) * Move all of the renderDebugInfo methods to the DebugUtils class @@ -113,6 +110,8 @@ V1.0.0 * Camera.inCamera check now uses the Sprite.worldView which finally accurately updates regardless of scale, rotation or rotation origin. * Added Math.Mat3 for Matrix3 operations (which Sprite.Transform uses) and Math.Mat3Utils for lots of use Mat3 related methods. * Added SpriteUtils.overlapsXY and overlapsPoint to check if a point is within a sprite, taking scale and rotation into account. +* Added Cache.getImageKeys (and similar) to return an array of all the keys for all currently cached objects. +* Added Group.bringToTop feature. Will sort the Group, move the given sprites z-index to the top and shift the rest down by one. diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 7d503fff..a4bdc215 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -85,6 +85,10 @@ swap children.ts + + + bring to top.ts + drag sprite 1.ts @@ -121,6 +125,10 @@ point in rotated sprite.ts + + + rotated sprites.ts + snap 1.ts @@ -274,8 +282,6 @@ boot screen.ts - - - + \ No newline at end of file diff --git a/Tests/demoscene/ballmover.js b/Tests/demoscene/ballmover.js deleted file mode 100644 index e45c4c6d..00000000 --- a/Tests/demoscene/ballmover.js +++ /dev/null @@ -1,18 +0,0 @@ -/// -/// -(function () { - var game = new Phaser.Game(this, 'demo1', 320, 200, init, create, update); - function init() { - game.load.image('balls', '../assets/sprites/balls.png'); - game.load.start(); - } - var scroller; - function create() { - scroller = game.add.scrollZone('balls', 0, 0, 800, 612); - game.math.sinCosGenerator(256, 4, 4, 2); - } - function update() { - scroller.currentRegion.scrollSpeed.x = game.math.shiftSinTable(); - scroller.currentRegion.scrollSpeed.y = game.math.shiftCosTable(); - } -})(); diff --git a/Tests/demoscene/ballmover.ts b/Tests/demoscene/ballmover.ts deleted file mode 100644 index d1775dae..00000000 --- a/Tests/demoscene/ballmover.ts +++ /dev/null @@ -1,31 +0,0 @@ -/// -/// - -(function () { - - var game = new Phaser.Game(this, 'demo1', 320, 200, init, create, update); - - function init() { - - game.load.image('balls', '../assets/sprites/balls.png'); - game.load.start(); - - } - - var scroller: Phaser.ScrollZone; - - function create() { - - scroller = game.add.scrollZone('balls', 0, 0, 800, 612); - game.math.sinCosGenerator(256, 4, 4, 2); - - } - - function update() { - - scroller.currentRegion.scrollSpeed.x = game.math.shiftSinTable(); - scroller.currentRegion.scrollSpeed.y = game.math.shiftCosTable(); - - } - -})(); diff --git a/Tests/demoscene/colorwhirl.js b/Tests/demoscene/colorwhirl.js deleted file mode 100644 index 51595fdd..00000000 --- a/Tests/demoscene/colorwhirl.js +++ /dev/null @@ -1,22 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('swirl', '../assets/pics/color_wheel_swirl.png'); - game.load.start(); - } - var swirl; - function create() { - // Here we'll assign the new sprite to the local swirl variable - swirl = game.add.sprite(game.stage.centerX, game.stage.centerY, 'swirl'); - // Increase the size of the sprite a little so it covers the edges of the stage - swirl.scale.setTo(1.4, 1.4); - // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); - // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) - game.add.tween(swirl).to({ - angle: 360 - }, 2000, Phaser.Easing.Linear.None, true, 0, true); - } -})(); diff --git a/Tests/demoscene/colorwhirl.ts b/Tests/demoscene/colorwhirl.ts deleted file mode 100644 index e4fa1a7e..00000000 --- a/Tests/demoscene/colorwhirl.ts +++ /dev/null @@ -1,33 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('swirl', '../assets/pics/color_wheel_swirl.png'); - game.load.start(); - - } - - var swirl: Phaser.Sprite; - - function create() { - - // Here we'll assign the new sprite to the local swirl variable - swirl = game.add.sprite(game.stage.centerX, game.stage.centerY, 'swirl'); - - // Increase the size of the sprite a little so it covers the edges of the stage - swirl.scale.setTo(1.4, 1.4); - - // Set the origin to the middle of the Sprite to get the effect we need - swirl.origin.setTo(swirl.frameBounds.halfWidth, swirl.frameBounds.halfHeight); - - // Create a tween that rotates a full 306 degrees and then repeats (loop set to true) - game.add.tween(swirl).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - - } - -})(); diff --git a/Tests/demoscene/fruitfall.js b/Tests/demoscene/fruitfall.js deleted file mode 100644 index 7487c527..00000000 --- a/Tests/demoscene/fruitfall.js +++ /dev/null @@ -1,44 +0,0 @@ -var __extends = this.__extends || function (d, b) { - function __() { this.constructor = d; } - __.prototype = b.prototype; - d.prototype = new __(); -}; -/// -/// -/// -var fruitParticle = (function (_super) { - __extends(fruitParticle, _super); - function fruitParticle(game) { - _super.call(this, game); - var s = [ - 'carrot', - 'melon', - 'eggplant', - 'mushroom', - 'pineapple' - ]; - this.texture.loadImage(game.math.getRandom(s)); - } - return fruitParticle; -})(Phaser.Particle); -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - var emitter; - function init() { - game.load.image('carrot', '../assets/sprites/carrot.png'); - game.load.image('melon', '../assets/sprites/melon.png'); - game.load.image('eggplant', '../assets/sprites/eggplant.png'); - game.load.image('mushroom', '../assets/sprites/mushroom.png'); - game.load.image('pineapple', '../assets/sprites/pineapple.png'); - game.load.start(); - } - function create() { - emitter = game.add.emitter(game.stage.centerX, 50); - emitter.gravity = 100; - // Here we tell the emitter to use our customParticle class - // The customParticle needs to extend Particle and must take game:Game as the first constructor parameter, otherwise it's free as a bird - emitter.particleClass = fruitParticle; - emitter.makeParticles(null, 50, false, 0); - emitter.start(false, 10, 0.05); - } -})(); diff --git a/Tests/demoscene/fruitfall.ts b/Tests/demoscene/fruitfall.ts deleted file mode 100644 index 19ed08b7..00000000 --- a/Tests/demoscene/fruitfall.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// -/// -/// - -class fruitParticle extends Phaser.Particle { - - constructor(game:Phaser.Game) { - - super(game); - - var s = ['carrot', 'melon', 'eggplant', 'mushroom', 'pineapple']; - - this.texture.loadImage(game.math.getRandom(s)); - } - -} - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - var emitter: Phaser.Emitter; - - function init() { - - game.load.image('carrot', '../assets/sprites/carrot.png'); - game.load.image('melon', '../assets/sprites/melon.png'); - game.load.image('eggplant', '../assets/sprites/eggplant.png'); - game.load.image('mushroom', '../assets/sprites/mushroom.png'); - game.load.image('pineapple', '../assets/sprites/pineapple.png'); - - game.load.start(); - - } - - function create() { - - emitter = game.add.emitter(game.stage.centerX, 50); - emitter.gravity = 100; - - // Here we tell the emitter to use our customParticle class - // The customParticle needs to extend Particle and must take game:Game as the first constructor parameter, otherwise it's free as a bird - emitter.particleClass = fruitParticle; - - emitter.makeParticles(null, 50, false, 0); - emitter.start(false, 10, 0.05); - - } - -})(); diff --git a/Tests/demoscene/fujiboink.js b/Tests/demoscene/fujiboink.js deleted file mode 100644 index 3817e311..00000000 --- a/Tests/demoscene/fujiboink.js +++ /dev/null @@ -1,42 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('fuji', '../assets/pics/atari_fujilogo.png'); - game.load.start(); - } - var fuji; - var tweenUp; - var tweenDown; - function create() { - game.stage.backgroundColor = 'rgb(0,0,100)'; - // Here we'll assign the new sprite to the local fuji variable - fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); - // The sprite is 320 x 200 pixels in size - // Here we set the origin to the center of the sprite again, so we can rotate and scale it at the same time - fuji.origin.setTo(160, 100); - game.add.tween(fuji).to({ - angle: 360 - }, 2000, Phaser.Easing.Linear.None, true, 0, true); - tweenUp = game.add.tween(fuji.scale); - tweenUp.onComplete.add(scaleDown, this); - tweenDown = game.add.tween(fuji.scale); - tweenDown.onComplete.add(scaleUp, this); - scaleUp(); - } - function scaleUp() { - tweenUp.to({ - x: 2, - y: 2 - }, 1000, Phaser.Easing.Elastic.Out); - tweenUp.start(); - } - function scaleDown() { - tweenDown.to({ - x: 0.5, - y: 0.5 - }, 1000, Phaser.Easing.Elastic.Out); - tweenDown.start(); - } -})(); diff --git a/Tests/demoscene/fujiboink.ts b/Tests/demoscene/fujiboink.ts deleted file mode 100644 index 7f8ec442..00000000 --- a/Tests/demoscene/fujiboink.ts +++ /dev/null @@ -1,56 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.image('fuji', '../assets/pics/atari_fujilogo.png'); - game.load.start(); - - } - - var fuji: Phaser.Sprite; - var tweenUp: Phaser.Tween; - var tweenDown: Phaser.Tween; - - function create() { - - game.stage.backgroundColor = 'rgb(0,0,100)'; - - // Here we'll assign the new sprite to the local fuji variable - fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); - - // The sprite is 320 x 200 pixels in size - // Here we set the origin to the center of the sprite again, so we can rotate and scale it at the same time - fuji.origin.setTo(160, 100); - - game.add.tween(fuji).to({ angle: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); - - tweenUp = game.add.tween(fuji.scale); - tweenUp.onComplete.add(scaleDown, this); - - tweenDown = game.add.tween(fuji.scale); - tweenDown.onComplete.add(scaleUp, this); - - scaleUp(); - - } - - function scaleUp() { - - tweenUp.to({ x: 2, y: 2 }, 1000, Phaser.Easing.Elastic.Out); - tweenUp.start(); - - } - - function scaleDown() { - - tweenDown.to({ x: 0.5, y: 0.5 }, 1000, Phaser.Easing.Elastic.Out); - tweenDown.start(); - - } - -})(); diff --git a/Tests/demoscene/index.html b/Tests/demoscene/index.html deleted file mode 100644 index f36772f0..00000000 --- a/Tests/demoscene/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Phaser does DemoScene - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Tests/demoscene/metalslug.js b/Tests/demoscene/metalslug.js deleted file mode 100644 index 09d42f06..00000000 --- a/Tests/demoscene/metalslug.js +++ /dev/null @@ -1,22 +0,0 @@ -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.spritesheet('monster', '../assets/sprites/metalslug_monster39x40.png', 39, 40); - game.load.start(); - } - var monster; - function create() { - game.stage.backgroundColor = 'rgb(50,10,10)'; - // Notice the use of 'stage.centerX' - this places the sprite in the middle of the stage without needing to do any extra math - monster = game.add.sprite(100, 50, 'monster'); - // For this animation we pass 'null' for the frames, because we're going to use them all - // And we set the frame rate (30) and loop status (true) when we add the animation - // If the frame rate and looping is never going to change then it's easier to do it here - monster.animations.add('walk', null, 30, true); - // Then you can just call 'play' on its own with no other values to start things going - monster.animations.play('walk'); - monster.scale.setTo(3, 3); - } -})(); diff --git a/Tests/demoscene/metalslug.ts b/Tests/demoscene/metalslug.ts deleted file mode 100644 index 020973ca..00000000 --- a/Tests/demoscene/metalslug.ts +++ /dev/null @@ -1,36 +0,0 @@ -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - // Using Phasers asset loader we load up a PNG from the assets folder - game.load.spritesheet('monster', '../assets/sprites/metalslug_monster39x40.png', 39, 40); - game.load.start(); - - } - - var monster: Phaser.Sprite; - - function create() { - - game.stage.backgroundColor = 'rgb(50,10,10)'; - - // Notice the use of 'stage.centerX' - this places the sprite in the middle of the stage without needing to do any extra math - monster = game.add.sprite(100, 50, 'monster'); - - // For this animation we pass 'null' for the frames, because we're going to use them all - // And we set the frame rate (30) and loop status (true) when we add the animation - // If the frame rate and looping is never going to change then it's easier to do it here - monster.animations.add('walk', null, 30, true); - - // Then you can just call 'play' on its own with no other values to start things going - monster.animations.play('walk'); - - monster.scale.setTo(3, 3); - - } - -})(); diff --git a/Tests/demoscene/scroller1.js b/Tests/demoscene/scroller1.js deleted file mode 100644 index d43079cd..00000000 --- a/Tests/demoscene/scroller1.js +++ /dev/null @@ -1,12 +0,0 @@ -/// -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - game.load.image('crystal', '../assets/pics/jim_sachs_time_crystal.png'); - game.load.start(); - } - function create() { - game.add.scrollZone('crystal').setSpeed(4, 2); - } -})(); diff --git a/Tests/demoscene/scroller1.ts b/Tests/demoscene/scroller1.ts deleted file mode 100644 index 6bf30f32..00000000 --- a/Tests/demoscene/scroller1.ts +++ /dev/null @@ -1,21 +0,0 @@ -/// -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - game.load.image('crystal', '../assets/pics/jim_sachs_time_crystal.png'); - game.load.start(); - - } - - function create() { - - game.add.scrollZone('crystal').setSpeed(4, 2); - - } - -})(); diff --git a/Tests/demoscene/starray.js b/Tests/demoscene/starray.js deleted file mode 100644 index 44c4601a..00000000 --- a/Tests/demoscene/starray.js +++ /dev/null @@ -1,31 +0,0 @@ -/// -/// -(function () { - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - function init() { - game.load.image('starray', '../assets/pics/auto_scroll_landscape.png'); - game.load.start(); - } - function create() { - var zone = game.add.scrollZone('starray'); - // Hide the default region (the full image) - zone.currentRegion.visible = false; - var y = 0; - var speed = 16; - // The image consists of 10px high scrolling layers, this creates them quickly (top = fastest, getting slower as we move down) - for(var z = 0; z < 32; z++) { - zone.addRegion(0, y, 640, 10, speed); - if(z <= 15) { - speed -= 1; - } else { - speed += 1; - } - if(z == 15) { - y = 240; - speed += 1; - } else { - y += 10; - } - } - } -})(); diff --git a/Tests/demoscene/starray.ts b/Tests/demoscene/starray.ts deleted file mode 100644 index dc61ab98..00000000 --- a/Tests/demoscene/starray.ts +++ /dev/null @@ -1,53 +0,0 @@ -/// -/// - -(function () { - - var game = new Phaser.Game(this, 'game', 320, 200, init, create); - - function init() { - - game.load.image('starray', '../assets/pics/auto_scroll_landscape.png'); - - game.load.start(); - - } - - function create() { - - var zone: Phaser.ScrollZone = game.add.scrollZone('starray'); - - // Hide the default region (the full image) - zone.currentRegion.visible = false; - - var y:number = 0; - var speed:number = 16; - - // The image consists of 10px high scrolling layers, this creates them quickly (top = fastest, getting slower as we move down) - for (var z:number = 0; z < 32; z++) - { - zone.addRegion(0, y, 640, 10, speed); - - if (z <= 15) - { - speed -= 1; - } - else - { - speed += 1; - } - - if (z == 15) - { - y = 240; - speed += 1; - } - else - { - y += 10; - } - } - - } - -})(); diff --git a/Tests/input/bring to top.js b/Tests/input/bring to top.js new file mode 100644 index 00000000..4052a34f --- /dev/null +++ b/Tests/input/bring to top.js @@ -0,0 +1,28 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + function init() { + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('atari4', 'assets/sprites/atari800.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.image('duck', 'assets/sprites/darkwing_crazy.png'); + game.load.image('firstaid', 'assets/sprites/firstaid.png'); + game.load.image('diamond', 'assets/sprites/diamond.png'); + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + game.load.start(); + } + function create() { + // This returns an array of all the image keys in the cache + var images = game.cache.getImageKeys(); + // Now let's create some random sprites and enable them all for drag and 'bring to top' + for(var i = 0; i < 20; i++) { + var tempSprite = game.add.sprite(game.stage.randomX, game.stage.randomY, game.rnd.pick(images)); + tempSprite.input.start(i, false, true); + tempSprite.input.enableDrag(false, true); + } + } + function render() { + game.input.renderDebugInfo(32, 32); + } +})(); diff --git a/Tests/input/bring to top.ts b/Tests/input/bring to top.ts new file mode 100644 index 00000000..4c647472 --- /dev/null +++ b/Tests/input/bring to top.ts @@ -0,0 +1,40 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + + function init() { + + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('atari4', 'assets/sprites/atari800.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.image('duck', 'assets/sprites/darkwing_crazy.png'); + game.load.image('firstaid', 'assets/sprites/firstaid.png'); + game.load.image('diamond', 'assets/sprites/diamond.png'); + game.load.image('mushroom', 'assets/sprites/mushroom2.png'); + game.load.start(); + + } + + function create() { + + // This returns an array of all the image keys in the cache + var images = game.cache.getImageKeys() + + // Now let's create some random sprites and enable them all for drag and 'bring to top' + for (var i = 0; i < 20; i++) + { + var tempSprite: Phaser.Sprite = game.add.sprite(game.stage.randomX, game.stage.randomY, game.rnd.pick(images)); + tempSprite.input.start(i, false, true); + tempSprite.input.enableDrag(false, true); + } + + } + + function render() { + game.input.renderDebugInfo(32, 32); + } + +})(); diff --git a/Tests/input/rotated sprites.js b/Tests/input/rotated sprites.js new file mode 100644 index 00000000..48d927e6 --- /dev/null +++ b/Tests/input/rotated sprites.js @@ -0,0 +1,33 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + function init() { + // Using Phasers asset loader we load up a PNG from the assets folder + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.start(); + } + var atari1; + var atari2; + var sonic; + function create() { + atari1 = game.add.sprite(200, 200, 'atari1'); + atari2 = game.add.sprite(500, 400, 'atari2'); + sonic = game.add.sprite(400, 500, 'sonic'); + atari1.origin.setTo(0.5, 0.5); + atari1.rotation = 35; + atari2.origin.setTo(1, 1); + atari2.rotation = 80; + sonic.rotation = 140; + atari1.input.start(0, false, true); + atari2.input.start(1, false, true); + sonic.input.start(2, false, true); + atari1.input.enableDrag(); + atari2.input.enableDrag(); + sonic.input.enableDrag(); + } + function render() { + game.input.renderDebugInfo(32, 32); + } +})(); diff --git a/Tests/input/rotated sprites.ts b/Tests/input/rotated sprites.ts new file mode 100644 index 00000000..d965dbe8 --- /dev/null +++ b/Tests/input/rotated sprites.ts @@ -0,0 +1,49 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 800, 600, init, create, null, render); + + function init() { + + // Using Phasers asset loader we load up a PNG from the assets folder + game.load.image('atari1', 'assets/sprites/atari130xe.png'); + game.load.image('atari2', 'assets/sprites/atari800xl.png'); + game.load.image('sonic', 'assets/sprites/sonic_havok_sanity.png'); + game.load.start(); + + } + + var atari1: Phaser.Sprite; + var atari2: Phaser.Sprite; + var sonic: Phaser.Sprite; + + function create() { + + atari1 = game.add.sprite(200, 200, 'atari1'); + atari2 = game.add.sprite(500, 400, 'atari2'); + sonic = game.add.sprite(400, 500, 'sonic'); + + atari1.origin.setTo(0.5, 0.5); + atari1.rotation = 35; + + atari2.origin.setTo(1, 1); + atari2.rotation = 80; + + sonic.rotation = 140; + + atari1.input.start(0, false, true); + atari2.input.start(1, false, true); + sonic.input.start(2, false, true); + + atari1.input.enableDrag(); + atari2.input.enableDrag(); + sonic.input.enableDrag(); + + } + + function render() { + game.input.renderDebugInfo(32, 32); + } + +})(); diff --git a/Tests/phaser.js b/Tests/phaser.js index 5895e09e..6826f466 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -3310,10 +3310,15 @@ var Phaser; * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ this.priorityID = 0; + /** + * The index of this Input component entry in the Game.Input manager. + */ + this.indexID = 0; this.isDragged = false; this.dragPixelPerfect = false; this.allowHorizontalDrag = true; this.allowVerticalDrag = true; + this.bringToTop = false; this.snapOnDrag = false; this.snapOnRelease = false; this.snapX = 0; @@ -3497,14 +3502,25 @@ var Phaser; } else { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this.sprite); + this.game.input.removeGameObject(this.indexID); } }; - Input.prototype.checkPointerOver = function (pointer) { + Input.prototype.destroy = /** + * Clean up memory. + */ + function () { + if(this.enabled) { + this.game.input.removeGameObject(this.indexID); + } + }; + Input.prototype.checkPointerOver = /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ + function (pointer) { if(this.enabled == false || this.sprite.visible == false) { return false; } else { - return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); + return Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); } }; Input.prototype.update = /** @@ -3517,7 +3533,7 @@ var Phaser; if(this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { + if(Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) { this._pointerData[pointer.id].x = pointer.x - this.sprite.x; this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; @@ -3561,6 +3577,9 @@ var Phaser; if(this.draggable && this.isDragged == false) { this.startDrag(pointer); } + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } } // Consume the event? return this.consumePointerEvent; @@ -3674,19 +3693,22 @@ var Phaser; * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { + function (lockCenter, bringToTop, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { if (typeof lockCenter === "undefined") { lockCenter = false; } + if (typeof bringToTop === "undefined") { bringToTop = false; } if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } if (typeof boundsRect === "undefined") { boundsRect = null; } if (typeof boundsSprite === "undefined") { boundsSprite = null; } this._dragPoint = new Phaser.Point(); this.draggable = true; + this.bringToTop = bringToTop; this.dragOffset = new Phaser.Point(); this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; @@ -3725,6 +3747,9 @@ var Phaser; this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); } this.updateDrag(pointer); + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } }; Input.prototype.stopDrag = /** * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. @@ -4450,7 +4475,6 @@ var Phaser; this.y = y; this.z = -1; this.group = null; - // No dependencies this.animations = new Phaser.Components.AnimationManager(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -4472,6 +4496,10 @@ var Phaser; this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); this.transform.setCache(); + // Handy proxies + this.scale = this.transform.scale; + this.alpha = this.texture.alpha; + this.origin = this.transform.origin; } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4608,8 +4636,8 @@ var Phaser; * Clean up memory. */ function () { - //this.input.destroy(); - }; + this.input.destroy(); + }; Sprite.prototype.kill = /** * Handy for "killing" game objects. * Default behavior is to flag them as nonexistent AND dead. @@ -4750,62 +4778,6 @@ var Phaser; this.getScreenXY(this._point, camera); - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size into account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); } @@ -4825,52 +4797,32 @@ var Phaser; if(sprite.transform.rotation == 0) { return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); } - //var ex: number = sprite.transform.upperRight.x - sprite.transform.upperLeft.x; - //var ey: number = sprite.transform.upperRight.y - sprite.transform.upperLeft.y; - //var fx: number = sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x; - //var fy: number = sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y; - //if ((x-ax)*ex+(y-ay)*ey<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-bx)*ex+(y-by)*ey>0.0) return false; if((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) { return false; } - //if ((x-ax)*fx+(y-ay)*fy<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-dx)*fx+(y-dy)*fy>0.0) return false; if((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) { return false; } return true; }; SpriteUtils.overlapsPoint = /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. * * @return Whether or not the point overlaps this object. */ - function overlapsPoint(sprite, point, inScreenSpace, camera) { - if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } - if (typeof camera === "undefined") { camera = null; } - if(!inScreenSpace) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); - } - if(camera == null) { - camera = sprite.game.camera; - } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; - //this.getScreenXY(this._point, camera); - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); - }; + function overlapsPoint(sprite, point) { + return SpriteUtils.overlapsXY(sprite, point.x, point.y); + }; SpriteUtils.onScreen = /** * Check and see if this object is currently on screen. * @@ -4940,15 +4892,6 @@ var Phaser; sprite.body.position.x = x; sprite.body.position.y = y; }; - SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { - if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } - if (typeof fromBody === "undefined") { fromBody = false; } - if(fromFrameBounds) { - sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); - } else if(fromBody) { - sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - }; SpriteUtils.setBounds = /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) @@ -5535,7 +5478,15 @@ var Phaser; this.members[this._i] = newObject; return newObject; }; - Group.prototype.swap = function (child1, child2, sort) { + Group.prototype.swap = /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ + function (child1, child2, sort) { if (typeof sort === "undefined") { sort = true; } if(child1.group.ID != this.ID || child2.group.ID != this.ID || child1 === child2) { return false; @@ -5548,6 +5499,28 @@ var Phaser; } return true; }; + Group.prototype.bringToTop = function (child) { + // If child not in this group, or is already at the top of the group, return false + if(child.group.ID != this.ID || child.z == this._zCounter) { + return false; + } + this.sort(); + // What's the z index of the top most child? + var tempZ = child.z; + var childIndex = this._zCounter; + this._i = 0; + while(this._i < this.length) { + this._member = this.members[this._i++]; + if(this._i > childIndex) { + this._member.z--; + } else if(this._member.z == child.z) { + childIndex = this._i; + this._member.z = this._zCounter; + } + } + this.sort(); + return true; + }; Group.prototype.sort = /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call @@ -6832,6 +6805,13 @@ var Phaser; } return null; }; + Cache.prototype.getImageKeys = function () { + var output = []; + for(var item in this._images) { + output.push(item); + } + return output; + }; Cache.prototype.destroy = /** * Clean up cache memory. */ @@ -14951,7 +14931,7 @@ var Phaser; var _highestRenderID = -1; var _highestRenderObject = -1; for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { _highestRenderID = this.game.input.inputObjects[i].renderOrderID; _highestRenderObject = i; } @@ -15010,7 +14990,7 @@ var Phaser; this.game.input.currentPointers--; } for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.enabled) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.enabled) { this.game.input.inputObjects[i].input._releasedHandler(this); } } @@ -16055,16 +16035,34 @@ var Phaser; this.gestures.start(); this.mousePointer.active = true; }; - Input.prototype.addGameObject = // Add Input Enabled array + add/remove methods and then iterate and update them during the main update - // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + Input.prototype.addGameObject = /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ function (object) { - // Lots more checks here + // Find a spare slot + for(var i = 0; i < this.inputObjects.length; i++) { + if(this.inputObjects[i] == null) { + this.inputObjects[i] = object; + object.input.indexID = i; + this.totalTrackedObjects++; + return; + } + } + // If we got this far we need to push a new entry into the array + object.input.indexID = this.inputObjects.length; this.inputObjects.push(object); this.totalTrackedObjects++; }; - Input.prototype.removeGameObject = function (object) { - // TODO - }; + Input.prototype.removeGameObject = /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + function (index) { + if(this.inputObjects[index]) { + this.inputObjects[index] = null; + } + }; Input.prototype.update = /** * Updates the Input Manager. Called by the core Game loop. * @method update diff --git a/Tests/scrollzones/blasteroids.js b/Tests/scrollzones/blasteroids.js index 474a7023..580e2761 100644 --- a/Tests/scrollzones/blasteroids.js +++ b/Tests/scrollzones/blasteroids.js @@ -36,7 +36,7 @@ bullets.add(tempBullet); } ship = game.add.sprite(game.stage.centerX, game.stage.centerY, 'nashwan', Phaser.Types.BODY_DYNAMIC); - Phaser.SpriteUtils.setOriginToCenter(ship); + ship.transform.origin.setTo(0.5, 0.5); // We do this because the ship was drawn facing up, but 0 degrees is pointing to the right ship.transform.rotationOffset = 90; game.input.onDown.add(test, this); diff --git a/Tests/scrollzones/blasteroids.ts b/Tests/scrollzones/blasteroids.ts index 2877fed1..84bad9e4 100644 --- a/Tests/scrollzones/blasteroids.ts +++ b/Tests/scrollzones/blasteroids.ts @@ -53,7 +53,7 @@ } ship = game.add.sprite(game.stage.centerX, game.stage.centerY, 'nashwan', Phaser.Types.BODY_DYNAMIC); - Phaser.SpriteUtils.setOriginToCenter(ship); + ship.transform.origin.setTo(0.5, 0.5); // We do this because the ship was drawn facing up, but 0 degrees is pointing to the right ship.transform.rotationOffset = 90; diff --git a/Tests/sprites/scale sprite 1.js b/Tests/sprites/scale sprite 1.js index 33b0e381..5cec160e 100644 --- a/Tests/sprites/scale sprite 1.js +++ b/Tests/sprites/scale sprite 1.js @@ -12,9 +12,9 @@ smallBunny = game.add.sprite(0, 0, 'bunny'); // And now let's scale the sprite by half // You can do either: - // smallBunny.transform.scale.x = 0.5; - // smallBunny.transform.scale.y = 0.5; + //smallBunny.scale.x = 0.5; + //smallBunny.scale.y = 0.5; // Or you can set them both at the same time using setTo: - smallBunny.transform.scale.setTo(0.5, 0.5); + smallBunny.scale.setTo(0.5, 0.5); } })(); diff --git a/Tests/sprites/scale sprite 1.ts b/Tests/sprites/scale sprite 1.ts index bc04c51e..3c182607 100644 --- a/Tests/sprites/scale sprite 1.ts +++ b/Tests/sprites/scale sprite 1.ts @@ -22,11 +22,11 @@ // And now let's scale the sprite by half // You can do either: - // smallBunny.transform.scale.x = 0.5; - // smallBunny.transform.scale.y = 0.5; + //smallBunny.scale.x = 0.5; + //smallBunny.scale.y = 0.5; // Or you can set them both at the same time using setTo: - smallBunny.transform.scale.setTo(0.5, 0.5); + smallBunny.scale.setTo(0.5, 0.5); } diff --git a/Tests/sprites/sprite origin 3.js b/Tests/sprites/sprite origin 3.js index 907f6a1b..20ea3979 100644 --- a/Tests/sprites/sprite origin 3.js +++ b/Tests/sprites/sprite origin 3.js @@ -14,7 +14,7 @@ fuji = game.add.sprite(game.stage.centerX, game.stage.centerY, 'fuji'); // The sprite is 320 x 200 pixels in size // Here we set the origin to be the bottom-right of the sprite - fuji.transform.origin.setTo(320, 200); + fuji.origin.setTo(320, 200); game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); diff --git a/Tests/sprites/sprite origin 3.ts b/Tests/sprites/sprite origin 3.ts index ba966bff..c61f1a3a 100644 --- a/Tests/sprites/sprite origin 3.ts +++ b/Tests/sprites/sprite origin 3.ts @@ -24,7 +24,7 @@ // The sprite is 320 x 200 pixels in size // Here we set the origin to be the bottom-right of the sprite - fuji.transform.origin.setTo(320, 200); + fuji.origin.setTo(320, 200); game.add.tween(fuji).to({ rotation: 360 }, 2000, Phaser.Easing.Linear.None, true, 0, true); diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 768901fe..8584ca5c 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -2039,6 +2039,10 @@ module Phaser.Components.Sprite { * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ public priorityID: number; + /** + * The index of this Input component entry in the Game.Input manager. + */ + public indexID: number; private _dragPoint; private _draggedPointerID; public dragOffset: Point; @@ -2048,6 +2052,7 @@ module Phaser.Components.Sprite { public dragPixelPerfectAlpha: number; public allowHorizontalDrag: bool; public allowVerticalDrag: bool; + public bringToTop: bool; public snapOnDrag: bool; public snapOnRelease: bool; public snapOffset: Point; @@ -2148,6 +2153,13 @@ module Phaser.Components.Sprite { public start(priority?: number, checkBody?: bool, useHandCursor?: bool): Sprite; public reset(): void; public stop(): void; + /** + * Clean up memory. + */ + public destroy(): void; + /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ public checkPointerOver(pointer: Pointer): bool; /** * Update @@ -2200,12 +2212,13 @@ module Phaser.Components.Sprite { * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - public enableDrag(lockCenter?: bool, pixelPerfect?: bool, alphaThreshold?: number, boundsRect?: Rectangle, boundsSprite?: Sprite): void; + public enableDrag(lockCenter?: bool, bringToTop?: bool, pixelPerfect?: bool, alphaThreshold?: number, boundsRect?: Rectangle, boundsSprite?: Sprite): void; /** * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. */ @@ -2670,6 +2683,20 @@ module Phaser { */ public rotation : number; /** + * The scale of the Sprite. A value of 1 is original scale. 0.5 is half size. 2 is double the size. + * This is a reference to Sprite.transform.scale + */ + public scale: Vec2; + /** + * The alpha of the Sprite between 0 and 1, a value of 1 being fully opaque. + */ + public alpha: number; + /** + * The origin of the Sprite around which rotation and positioning takes place. + * This is a reference to Sprite.transform.origin + */ + public origin: Vec2; + /** * Get the animation frame number. */ /** @@ -2746,15 +2773,15 @@ module Phaser { */ static overlapsXY(sprite: Sprite, x: number, y: number): bool; /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. * * @return Whether or not the point overlaps this object. */ - static overlapsPoint(sprite: Sprite, point: Point, inScreenSpace?: bool, camera?: Camera): bool; + static overlapsPoint(sprite: Sprite, point: Point): bool; /** * Check and see if this object is currently on screen. * @@ -2780,7 +2807,6 @@ module Phaser { * @param y {number} The new Y position of this object. */ static reset(sprite: Sprite, x: number, y: number): void; - static setOriginToCenter(sprite: Sprite, fromFrameBounds?: bool, fromBody?: bool): void; /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) @@ -3139,7 +3165,16 @@ module Phaser { * @return {Basic} The new object. */ public replace(oldObject, newObject); + /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ public swap(child1, child2, sort?: bool): bool; + public bringToTop(child): bool; /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call @@ -3797,6 +3832,7 @@ module Phaser { * @return {object} The text data you want. */ public getText(key: string); + public getImageKeys(): any[]; /** * Clean up cache memory. */ @@ -8656,8 +8692,16 @@ module Phaser { public boot(): void; public inputObjects: any[]; public totalTrackedObjects: number; + /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ public addGameObject(object): void; - public removeGameObject(object): void; + /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + public removeGameObject(index: number): void; /** * Updates the Input Manager. Called by the core Game loop. * @method update diff --git a/build/phaser.js b/build/phaser.js index 5895e09e..6826f466 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -3310,10 +3310,15 @@ var Phaser; * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ this.priorityID = 0; + /** + * The index of this Input component entry in the Game.Input manager. + */ + this.indexID = 0; this.isDragged = false; this.dragPixelPerfect = false; this.allowHorizontalDrag = true; this.allowVerticalDrag = true; + this.bringToTop = false; this.snapOnDrag = false; this.snapOnRelease = false; this.snapX = 0; @@ -3497,14 +3502,25 @@ var Phaser; } else { // De-register, etc this.enabled = false; - this.game.input.removeGameObject(this.sprite); + this.game.input.removeGameObject(this.indexID); } }; - Input.prototype.checkPointerOver = function (pointer) { + Input.prototype.destroy = /** + * Clean up memory. + */ + function () { + if(this.enabled) { + this.game.input.removeGameObject(this.indexID); + } + }; + Input.prototype.checkPointerOver = /** + * Checks if the given pointer is over this Sprite. All checks are done in world coordinates. + */ + function (pointer) { if(this.enabled == false || this.sprite.visible == false) { return false; } else { - return Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY()); + return Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); } }; Input.prototype.update = /** @@ -3517,7 +3533,7 @@ var Phaser; if(this.draggable && this._draggedPointerID == pointer.id) { return this.updateDrag(pointer); } else if(this._pointerData[pointer.id].isOver == true) { - if(Phaser.RectangleUtils.contains(this.sprite.worldView, pointer.worldX(), pointer.worldY())) { + if(Phaser.SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) { this._pointerData[pointer.id].x = pointer.x - this.sprite.x; this._pointerData[pointer.id].y = pointer.y - this.sprite.y; return true; @@ -3561,6 +3577,9 @@ var Phaser; if(this.draggable && this.isDragged == false) { this.startDrag(pointer); } + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } } // Consume the event? return this.consumePointerEvent; @@ -3674,19 +3693,22 @@ var Phaser; * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. + * @param bringToTop If true the Sprite will be bought to the top of the rendering list in its current Group. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere * @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here */ - function (lockCenter, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { + function (lockCenter, bringToTop, pixelPerfect, alphaThreshold, boundsRect, boundsSprite) { if (typeof lockCenter === "undefined") { lockCenter = false; } + if (typeof bringToTop === "undefined") { bringToTop = false; } if (typeof pixelPerfect === "undefined") { pixelPerfect = false; } if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } if (typeof boundsRect === "undefined") { boundsRect = null; } if (typeof boundsSprite === "undefined") { boundsSprite = null; } this._dragPoint = new Phaser.Point(); this.draggable = true; + this.bringToTop = bringToTop; this.dragOffset = new Phaser.Point(); this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; @@ -3725,6 +3747,9 @@ var Phaser; this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); } this.updateDrag(pointer); + if(this.bringToTop) { + this.sprite.group.bringToTop(this.sprite); + } }; Input.prototype.stopDrag = /** * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. @@ -4450,7 +4475,6 @@ var Phaser; this.y = y; this.z = -1; this.group = null; - // No dependencies this.animations = new Phaser.Components.AnimationManager(this); this.input = new Phaser.Components.Sprite.Input(this); this.events = new Phaser.Components.Sprite.Events(this); @@ -4472,6 +4496,10 @@ var Phaser; this.worldView = new Phaser.Rectangle(x, y, this.width, this.height); this.cameraView = new Phaser.Rectangle(x, y, this.width, this.height); this.transform.setCache(); + // Handy proxies + this.scale = this.transform.scale; + this.alpha = this.texture.alpha; + this.origin = this.transform.origin; } Object.defineProperty(Sprite.prototype, "rotation", { get: /** @@ -4608,8 +4636,8 @@ var Phaser; * Clean up memory. */ function () { - //this.input.destroy(); - }; + this.input.destroy(); + }; Sprite.prototype.kill = /** * Handy for "killing" game objects. * Default behavior is to flag them as nonexistent AND dead. @@ -4750,62 +4778,6 @@ var Phaser; this.getScreenXY(this._point, camera); - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && - (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); - } - */ - /** - * Checks to see if this GameObject were located at the given position, would it overlap the GameObject or Group? - * This is distinct from overlapsPoint(), which just checks that point, rather than taking the object's size into account. - * WARNING: Currently tilemaps do NOT support screen space overlap checks! - * - * @param X {number} The X position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param Y {number} The Y position you want to check. Pretends this object (the caller, not the parameter) is located here. - * @param objectOrGroup {object} The object or group being tested. - * @param inScreenSpace {boolean} Whether to take scroll factors numbero account when checking for overlap. Default is false, or "only compare in world space." - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. - * - * @return {boolean} Whether or not the two objects overlap. - */ - /* - static overlapsAt(X: number, Y: number, objectOrGroup, inScreenSpace: bool = false, camera: Camera = null): bool { - - if (objectOrGroup.isGroup) - { - var results: bool = false; - var basic; - var i: number = 0; - var members = objectOrGroup.members; - - while (i < length) - { - if (this.overlapsAt(X, Y, members[i++], inScreenSpace, camera)) - { - results = true; - } - } - - return results; - } - - if (!inScreenSpace) - { - return (objectOrGroup.x + objectOrGroup.width > X) && (objectOrGroup.x < X + this.width) && - (objectOrGroup.y + objectOrGroup.height > Y) && (objectOrGroup.y < Y + this.height); - } - - if (camera == null) - { - camera = this._game.camera; - } - - var objectScreenPos: Point = objectOrGroup.getScreenXY(null, Camera); - - this._point.x = X - camera.scroll.x * this.transform.scrollFactor.x; //copied from getScreenXY() - this._point.y = Y - camera.scroll.y * this.transform.scrollFactor.y; - this._point.x += (this._point.x > 0) ? 0.0000001 : -0.0000001; - this._point.y += (this._point.y > 0) ? 0.0000001 : -0.0000001; - return (objectScreenPos.x + objectOrGroup.width > this._point.x) && (objectScreenPos.x < this._point.x + this.width) && (objectScreenPos.y + objectOrGroup.height > this._point.y) && (objectScreenPos.y < this._point.y + this.height); } @@ -4825,52 +4797,32 @@ var Phaser; if(sprite.transform.rotation == 0) { return Phaser.RectangleUtils.contains(sprite.cameraView, x, y); } - //var ex: number = sprite.transform.upperRight.x - sprite.transform.upperLeft.x; - //var ey: number = sprite.transform.upperRight.y - sprite.transform.upperLeft.y; - //var fx: number = sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x; - //var fy: number = sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y; - //if ((x-ax)*ex+(y-ay)*ey<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-bx)*ex+(y-by)*ey>0.0) return false; if((x - sprite.transform.upperRight.x) * (sprite.transform.upperRight.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperRight.y) * (sprite.transform.upperRight.y - sprite.transform.upperLeft.y) > 0) { return false; } - //if ((x-ax)*fx+(y-ay)*fy<0.0) return false; if((x - sprite.transform.upperLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.upperLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) < 0) { return false; } - //if ((x-dx)*fx+(y-dy)*fy>0.0) return false; if((x - sprite.transform.bottomLeft.x) * (sprite.transform.bottomLeft.x - sprite.transform.upperLeft.x) + (y - sprite.transform.bottomLeft.y) * (sprite.transform.bottomLeft.y - sprite.transform.upperLeft.y) > 0) { return false; } return true; }; SpriteUtils.overlapsPoint = /** - * Checks to see if a point in 2D world space overlaps this GameObject. + * Checks to see if the given point overlaps this Sprite, taking scaling and rotation into account. + * The point must be given in world space, not local or camera space. * + * @param sprite {Sprite} The Sprite to check. It will take scaling and rotation into account. * @param point {Point} The point in world space you want to check. - * @param inScreenSpace {boolean} Whether to take scroll factors into account when checking for overlap. - * @param camera {Camera} Specify which game camera you want. If null getScreenXY() will just grab the first global camera. * * @return Whether or not the point overlaps this object. */ - function overlapsPoint(sprite, point, inScreenSpace, camera) { - if (typeof inScreenSpace === "undefined") { inScreenSpace = false; } - if (typeof camera === "undefined") { camera = null; } - if(!inScreenSpace) { - return Phaser.RectangleUtils.containsPoint(sprite.body.bounds, point); - //return (point.x > sprite.x) && (point.x < sprite.x + sprite.width) && (point.y > sprite.y) && (point.y < sprite.y + sprite.height); - } - if(camera == null) { - camera = sprite.game.camera; - } - //var x: number = point.x - camera.scroll.x; - //var y: number = point.y - camera.scroll.y; - //this.getScreenXY(this._point, camera); - //return (x > this._point.x) && (X < this._point.x + this.width) && (Y > this._point.y) && (Y < this._point.y + this.height); - }; + function overlapsPoint(sprite, point) { + return SpriteUtils.overlapsXY(sprite, point.x, point.y); + }; SpriteUtils.onScreen = /** * Check and see if this object is currently on screen. * @@ -4940,15 +4892,6 @@ var Phaser; sprite.body.position.x = x; sprite.body.position.y = y; }; - SpriteUtils.setOriginToCenter = function setOriginToCenter(sprite, fromFrameBounds, fromBody) { - if (typeof fromFrameBounds === "undefined") { fromFrameBounds = true; } - if (typeof fromBody === "undefined") { fromBody = false; } - if(fromFrameBounds) { - sprite.transform.origin.setTo(sprite.width / 2, sprite.height / 2); - } else if(fromBody) { - sprite.transform.origin.setTo(sprite.body.bounds.halfWidth, sprite.body.bounds.halfHeight); - } - }; SpriteUtils.setBounds = /** * Set the world bounds that this GameObject can exist within. By default a GameObject can exist anywhere * in the world. But by setting the bounds (which are given in world dimensions, not screen dimensions) @@ -5535,7 +5478,15 @@ var Phaser; this.members[this._i] = newObject; return newObject; }; - Group.prototype.swap = function (child1, child2, sort) { + Group.prototype.swap = /** + * Swaps two existing game object in this Group with each other. + * + * @param {Basic} child1 The first object to swap. + * @param {Basic} child2 The second object to swap. + * + * @return {Basic} True if the two objects successfully swapped position. + */ + function (child1, child2, sort) { if (typeof sort === "undefined") { sort = true; } if(child1.group.ID != this.ID || child2.group.ID != this.ID || child1 === child2) { return false; @@ -5548,6 +5499,28 @@ var Phaser; } return true; }; + Group.prototype.bringToTop = function (child) { + // If child not in this group, or is already at the top of the group, return false + if(child.group.ID != this.ID || child.z == this._zCounter) { + return false; + } + this.sort(); + // What's the z index of the top most child? + var tempZ = child.z; + var childIndex = this._zCounter; + this._i = 0; + while(this._i < this.length) { + this._member = this.members[this._i++]; + if(this._i > childIndex) { + this._member.z--; + } else if(this._member.z == child.z) { + childIndex = this._i; + this._member.z = this._zCounter; + } + } + this.sort(); + return true; + }; Group.prototype.sort = /** * Call this function to sort the group according to a particular value and order. * For example, to sort game objects for Zelda-style overlaps you might call @@ -6832,6 +6805,13 @@ var Phaser; } return null; }; + Cache.prototype.getImageKeys = function () { + var output = []; + for(var item in this._images) { + output.push(item); + } + return output; + }; Cache.prototype.destroy = /** * Clean up cache memory. */ @@ -14951,7 +14931,7 @@ var Phaser; var _highestRenderID = -1; var _highestRenderObject = -1; for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.checkPointerOver(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) { _highestRenderID = this.game.input.inputObjects[i].renderOrderID; _highestRenderObject = i; } @@ -15010,7 +14990,7 @@ var Phaser; this.game.input.currentPointers--; } for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.enabled) { + if(this.game.input.inputObjects[i] !== null && this.game.input.inputObjects[i].input.enabled) { this.game.input.inputObjects[i].input._releasedHandler(this); } } @@ -16055,16 +16035,34 @@ var Phaser; this.gestures.start(); this.mousePointer.active = true; }; - Input.prototype.addGameObject = // Add Input Enabled array + add/remove methods and then iterate and update them during the main update - // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + Input.prototype.addGameObject = /** + * Adds a new game object to be tracked by the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method addGameObject + **/ function (object) { - // Lots more checks here + // Find a spare slot + for(var i = 0; i < this.inputObjects.length; i++) { + if(this.inputObjects[i] == null) { + this.inputObjects[i] = object; + object.input.indexID = i; + this.totalTrackedObjects++; + return; + } + } + // If we got this far we need to push a new entry into the array + object.input.indexID = this.inputObjects.length; this.inputObjects.push(object); this.totalTrackedObjects++; }; - Input.prototype.removeGameObject = function (object) { - // TODO - }; + Input.prototype.removeGameObject = /** + * Removes a game object from the Input Manager. Called by the Sprite.Input component, should not usually be called directly. + * @method removeGameObject + **/ + function (index) { + if(this.inputObjects[index]) { + this.inputObjects[index] = null; + } + }; Input.prototype.update = /** * Updates the Input Manager. Called by the core Game loop. * @method update