From dcce99ec602bbd05d3e07c9d271b4de9c74dc095 Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Fri, 12 Jul 2013 03:28:46 +0100 Subject: [PATCH] Added the new Button game object and various other input and tilemap fixes. --- Phaser/Game.ts | 59 +- Phaser/Phaser.csproj | 4 + Phaser/Statics.ts | 1 + Phaser/cameras/Camera.ts | 3 + Phaser/components/animation/Animation.ts | 9 +- .../components/animation/AnimationManager.ts | 28 +- Phaser/components/sprite/Events.ts | 31 +- Phaser/components/sprite/Input.ts | 148 ++--- Phaser/gameobjects/Button.ts | 211 ++++++++ Phaser/gameobjects/DynamicTexture.ts | 30 +- Phaser/gameobjects/GameObjectFactory.ts | 18 + Phaser/gameobjects/IGameObject.ts | 15 + Phaser/gameobjects/Sprite.ts | 21 +- Phaser/gameobjects/Tilemap.ts | 3 + Phaser/input/Input.ts | 6 +- Phaser/input/Pointer.ts | 80 ++- Phaser/loader/AnimationLoader.ts | 1 + Phaser/loader/Cache.ts | 16 + Phaser/loader/Loader.ts | 10 +- Phaser/renderers/CanvasRenderer.ts | 2 +- README.md | 18 +- Tests/Tests.csproj | 16 + Tests/assets/buttons/button_sprite_sheet.png | Bin 0 -> 30907 bytes .../assets/buttons/button_texture_atlas.json | 36 ++ Tests/assets/buttons/button_texture_atlas.png | Bin 0 -> 32739 bytes Tests/assets/psds/button.psd | Bin 0 -> 213280 bytes Tests/assets/psds/down.png | Bin 0 -> 5761 bytes Tests/assets/psds/out.png | Bin 0 -> 13928 bytes Tests/assets/psds/over.png | Bin 0 -> 14080 bytes Tests/buttons/basic button 2.js | 33 ++ Tests/buttons/basic button 2.ts | 49 ++ Tests/buttons/basic button.js | 34 ++ Tests/buttons/basic button.ts | 50 ++ Tests/buttons/rotated buttons.js | 37 ++ Tests/buttons/rotated buttons.ts | 56 ++ Tests/phaser.js | 512 ++++++++++++++---- Tests/sprites/alpha.js | 15 + Tests/sprites/alpha.ts | 25 + Tests/sprites/create sprite 1.js | 1 - Tests/sprites/create sprite 1.ts | 2 - build/phaser.d.ts | 169 +++++- build/phaser.js | 512 ++++++++++++++---- 42 files changed, 1898 insertions(+), 363 deletions(-) create mode 100644 Phaser/gameobjects/Button.ts create mode 100644 Tests/assets/buttons/button_sprite_sheet.png create mode 100644 Tests/assets/buttons/button_texture_atlas.json create mode 100644 Tests/assets/buttons/button_texture_atlas.png create mode 100644 Tests/assets/psds/button.psd create mode 100644 Tests/assets/psds/down.png create mode 100644 Tests/assets/psds/out.png create mode 100644 Tests/assets/psds/over.png create mode 100644 Tests/buttons/basic button 2.js create mode 100644 Tests/buttons/basic button 2.ts create mode 100644 Tests/buttons/basic button.js create mode 100644 Tests/buttons/basic button.ts create mode 100644 Tests/buttons/rotated buttons.js create mode 100644 Tests/buttons/rotated buttons.ts create mode 100644 Tests/sprites/alpha.js create mode 100644 Tests/sprites/alpha.ts diff --git a/Phaser/Game.ts b/Phaser/Game.ts index 469069f5..c996087f 100644 --- a/Phaser/Game.ts +++ b/Phaser/Game.ts @@ -130,17 +130,35 @@ module Phaser { public onCreateCallback = null; /** - * This will be called when update states. + * This will be called when State is updated, this doesn't happen during load (see onLoadUpdateCallback) * @type {function} */ public onUpdateCallback = null; /** - * This will be called when render states. + * This will be called when the State is rendered, this doesn't happen during load (see onLoadRenderCallback) * @type {function} */ public onRenderCallback = null; + /** + * This will be called before the State is rendered and before the stage is cleared + * @type {function} + */ + public onPreRenderCallback = null; + + /** + * This will be called when the State is updated but only during the load process + * @type {function} + */ + public onLoadUpdateCallback = null; + + /** + * This will be called when the State is rendered but only during the load process + * @type {function} + */ + public onLoadRenderCallback = null; + /** * This will be called when states paused. * @type {function} @@ -351,9 +369,7 @@ module Phaser { * Called when the load has finished after init was run. */ private loadComplete() { - this._loadComplete = true; - } /** @@ -398,15 +414,28 @@ module Phaser { { this.onUpdateCallback.call(this.callbackContext); } + else if (this._loadComplete == false && this.onLoadUpdateCallback) + { + this.onLoadUpdateCallback.call(this.callbackContext); + } this.world.postUpdate(); + if (this._loadComplete && this.onPreRenderCallback) + { + this.onPreRenderCallback.call(this.callbackContext); + } + this.renderer.render(); if (this._loadComplete && this.onRenderCallback) { this.onRenderCallback.call(this.callbackContext); } + else if (this._loadComplete == false && this.onLoadRenderCallback) + { + this.onLoadRenderCallback.call(this.callbackContext); + } } @@ -446,7 +475,7 @@ module Phaser { } /** - * Set all state callbacks (init, create, update, render). + * Set the most common state callbacks (init, create, update, render). * @param initCallback {function} Init callback invoked when init state. * @param createCallback {function} Create callback invoked when create state. * @param updateCallback {function} Update callback invoked when update state. @@ -497,9 +526,12 @@ module Phaser { this.callbackContext = this.state; this.onInitCallback = null; + this.onLoadRenderCallback = null; + this.onLoadUpdateCallback = null; this.onCreateCallback = null; this.onUpdateCallback = null; this.onRenderCallback = null; + this.onPreRenderCallback = null; this.onPausedCallback = null; this.onDestroyCallback = null; @@ -509,6 +541,16 @@ module Phaser { this.onInitCallback = this.state['init']; } + if (this.state['loadRender']) + { + this.onLoadRenderCallback = this.state['loadRender']; + } + + if (this.state['loadUpdate']) + { + this.onLoadUpdateCallback = this.state['loadUpdate']; + } + if (this.state['create']) { this.onCreateCallback = this.state['create']; @@ -519,6 +561,11 @@ module Phaser { this.onUpdateCallback = this.state['update']; } + if (this.state['preRender']) + { + this.onPreRenderCallback = this.state['preRender']; + } + if (this.state['render']) { this.onRenderCallback = this.state['render']; @@ -562,6 +609,8 @@ module Phaser { this.callbackContext = null; this.onInitCallback = null; + this.onLoadRenderCallback = null; + this.onLoadUpdateCallback = null; this.onCreateCallback = null; this.onUpdateCallback = null; this.onRenderCallback = null; diff --git a/Phaser/Phaser.csproj b/Phaser/Phaser.csproj index 9776fa7a..9c479ee7 100644 --- a/Phaser/Phaser.csproj +++ b/Phaser/Phaser.csproj @@ -92,6 +92,10 @@ CameraFX.ts + + + Button.ts + DynamicTexture.ts diff --git a/Phaser/Statics.ts b/Phaser/Statics.ts index ff6d5006..8eb0656c 100644 --- a/Phaser/Statics.ts +++ b/Phaser/Statics.ts @@ -17,6 +17,7 @@ module Phaser { static EMITTER: number = 4; static TILEMAP: number = 5; static SCROLLZONE: number = 6; + static BUTTON: number = 7; static GEOM_POINT: number = 0; static GEOM_CIRCLE: number = 1; diff --git a/Phaser/cameras/Camera.ts b/Phaser/cameras/Camera.ts index 0d873f81..4bfab567 100644 --- a/Phaser/cameras/Camera.ts +++ b/Phaser/cameras/Camera.ts @@ -36,6 +36,9 @@ module Phaser { this.ID = id; this.z = id; + width = this.game.math.clamp(width, this.game.stage.width, 1); + height = this.game.math.clamp(height, this.game.stage.height, 1); + // The view into the world we wish to render (by default the full game world size) // The size of this Rect is the same as screenView, but the values are all in world coordinates instead of screen coordinates this.worldView = new Rectangle(0, 0, width, height); diff --git a/Phaser/components/animation/Animation.ts b/Phaser/components/animation/Animation.ts index 95495b05..7f7bf59a 100644 --- a/Phaser/components/animation/Animation.ts +++ b/Phaser/components/animation/Animation.ts @@ -171,8 +171,13 @@ module Phaser { this._timeNextFrame = this._game.time.now + this.delay; this._frameIndex = 0; + this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + this._parent.events.onAnimationStart.dispatch(this._parent, this); + + return this; + } /** @@ -216,6 +221,7 @@ module Phaser { { this._frameIndex = 0; this.currentFrame = this._frameData.getFrame(this._frames[this._frameIndex]); + this._parent.events.onAnimationLoop.dispatch(this._parent, this); } else { @@ -258,7 +264,8 @@ module Phaser { this.isPlaying = false; this.isFinished = true; - // callback goes here + + this._parent.events.onAnimationComplete.dispatch(this._parent, this); } diff --git a/Phaser/components/animation/AnimationManager.ts b/Phaser/components/animation/AnimationManager.ts index 3615fe89..aa4a860a 100644 --- a/Phaser/components/animation/AnimationManager.ts +++ b/Phaser/components/animation/AnimationManager.ts @@ -25,18 +25,18 @@ module Phaser.Components { constructor(parent: Phaser.Sprite) { this._parent = parent; - this._game = parent.game; + this.game = parent.game; this._anims = {}; } /** - * Local private reference to game. + * Reference to Phaser.Game */ - private _game: Game; + public game: Game; /** - * Local private reference to its owner sprite. + * Local private reference to its parent game object. */ private _parent: Phaser.Sprite; @@ -103,6 +103,14 @@ module Phaser.Components { return; } + // Create the signals the AnimationManager will emit + if (this._parent.events.onAnimationStart == null) + { + this._parent.events.onAnimationStart = new Phaser.Signal; + this._parent.events.onAnimationComplete = new Phaser.Signal; + this._parent.events.onAnimationLoop = new Phaser.Signal; + } + if (frames == null) { frames = this._frameData.getFrameIndexes(); @@ -121,7 +129,7 @@ module Phaser.Components { frames = this._frameData.getFrameIndexesByName(frames); } - this._anims[name] = new Animation(this._game, this._parent, this._frameData, name, frames, frameRate, loop); + this._anims[name] = new Animation(this.game, this._parent, this._frameData, name, frames, frameRate, loop); this.currentAnim = this._anims[name]; this.currentFrame = this.currentAnim.currentFrame; @@ -166,7 +174,7 @@ module Phaser.Components { * @param frameRate {number} FrameRate you want to specify instead of using default. * @param loop {boolean} Whether or not the animation is looped or just plays once. */ - public play(name: string, frameRate?: number = null, loop?: bool) { + public play(name: string, frameRate?: number = null, loop?: bool): Animation { if (this._anims[name]) { @@ -174,13 +182,13 @@ module Phaser.Components { { if (this.currentAnim.isPlaying == false) { - this.currentAnim.play(frameRate, loop); + return this.currentAnim.play(frameRate, loop); } } else { this.currentAnim = this._anims[name]; - this.currentAnim.play(frameRate, loop); + return this.currentAnim.play(frameRate, loop); } } @@ -236,7 +244,7 @@ module Phaser.Components { public set frame(value: number) { - if (this._frameData.getFrame(value) !== null) + if (this._frameData && this._frameData.getFrame(value) !== null) { this.currentFrame = this._frameData.getFrame(value); @@ -260,7 +268,7 @@ module Phaser.Components { public set frameName(value: string) { - if (this._frameData.getFrameByName(value) !== null) + if (this._frameData.getFrameByName(value)) { this.currentFrame = this._frameData.getFrameByName(value); diff --git a/Phaser/components/sprite/Events.ts b/Phaser/components/sprite/Events.ts index b8e2e3d9..d1619f65 100644 --- a/Phaser/components/sprite/Events.ts +++ b/Phaser/components/sprite/Events.ts @@ -11,27 +11,19 @@ module Phaser.Components.Sprite { export class Events { /** - * The Events component is a collection of events fired by the parent Sprite and its other components. - * @param parent The Sprite using this Input component + * The Events component is a collection of events fired by the parent game object and its components. + * @param parent The game object using this Input component */ constructor(parent: Phaser.Sprite) { this.game = parent.game; - this.sprite = parent; + this._parent = parent; this.onAddedToGroup = new Phaser.Signal; this.onRemovedFromGroup = new Phaser.Signal; this.onKilled = new Phaser.Signal; this.onRevived = new Phaser.Signal; - // Only create these if Sprite input is enabled? - this.onInputOver = new Phaser.Signal; - this.onInputOut = new Phaser.Signal; - this.onInputDown = new Phaser.Signal; - this.onInputUp = new Phaser.Signal; - this.onDragStart = new Phaser.Signal; - this.onDragStop = new Phaser.Signal; - } /** @@ -40,9 +32,9 @@ module Phaser.Components.Sprite { public game: Game; /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + * Local private reference to its parent game object. */ - private sprite: Phaser.Sprite; + private _parent: Phaser.Sprite; /** * Dispatched by the Group this Sprite is added to. @@ -94,7 +86,20 @@ module Phaser.Components.Sprite { */ public onDragStop: Phaser.Signal; + /** + * Dispatched by the Animation component when the Sprite starts being animated + */ + public onAnimationStart: Phaser.Signal; + /** + * Dispatched by the Animation component when the Sprite animation completes + */ + public onAnimationComplete: Phaser.Signal; + + /** + * Dispatched by the Animation component when the Sprite animation loops + */ + public onAnimationLoop: Phaser.Signal; public onOutOfBounds: Phaser.Signal; diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 2c36f72a..94bbd9ca 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -20,7 +20,7 @@ module Phaser.Components.Sprite { constructor(parent: Phaser.Sprite) { this.game = parent.game; - this.sprite = parent; + this._parent = parent; this.enabled = false; } @@ -31,9 +31,9 @@ module Phaser.Components.Sprite { public game: Game; /** - * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. + * Local private reference to its parent game object. */ - private sprite: Phaser.Sprite; + private _parent: Phaser.Sprite; private _pointerData; @@ -104,6 +104,13 @@ module Phaser.Components.Sprite { */ public useHandCursor: bool; + /** + * If this object is set to consume the pointer event then it will stop all propogation from this object on. + * For example if you had a stack of 6 sprites with the same priority IDs and one consumed the event, none of the others would receive it. + * @type {Boolean} + */ + public consumePointerEvent: bool = false; + /** * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. * This value is only set when the pointer is over this Sprite. @@ -222,10 +229,22 @@ module Phaser.Components.Sprite { this.snapOffset = new Point; this.enabled = true; - this.game.input.addGameObject(this.sprite); + this.game.input.addGameObject(this._parent); + + // Create the signals the Input component will emit + if (this._parent.events.onInputOver == null) + { + this._parent.events.onInputOver = new Phaser.Signal; + this._parent.events.onInputOut = new Phaser.Signal; + this._parent.events.onInputDown = new Phaser.Signal; + this._parent.events.onInputUp = new Phaser.Signal; + this._parent.events.onDragStart = new Phaser.Signal; + this._parent.events.onDragStop = new Phaser.Signal; + } + } - return this.sprite; + return this._parent; } @@ -274,13 +293,13 @@ module Phaser.Components.Sprite { */ public checkPointerOver(pointer: Phaser.Pointer): bool { - if (this.enabled == false || this.sprite.visible == false) + if (this.enabled == false || this._parent.visible == false) { return false; } else { - return SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY()); + return SpriteUtils.overlapsXY(this._parent, pointer.worldX(), pointer.worldY()); } } @@ -290,7 +309,7 @@ module Phaser.Components.Sprite { */ public update(pointer: Phaser.Pointer): bool { - if (this.enabled == false || this.sprite.visible == false) + if (this.enabled == false || this._parent.visible == false) { return false; } @@ -301,10 +320,10 @@ module Phaser.Components.Sprite { } else if (this._pointerData[pointer.id].isOver == true) { - if (SpriteUtils.overlapsXY(this.sprite, pointer.worldX(), pointer.worldY())) + if (SpriteUtils.overlapsXY(this._parent, pointer.worldX(), pointer.worldY())) { - this._pointerData[pointer.id].x = pointer.x - this.sprite.x; - this._pointerData[pointer.id].y = pointer.y - this.sprite.y; + this._pointerData[pointer.id].x = pointer.x - this._parent.x; + this._pointerData[pointer.id].y = pointer.y - this._parent.y; return true; } else @@ -325,15 +344,15 @@ module Phaser.Components.Sprite { this._pointerData[pointer.id].isOver = true; this._pointerData[pointer.id].isOut = false; this._pointerData[pointer.id].timeOver = this.game.time.now; - this._pointerData[pointer.id].x = pointer.x - this.sprite.x; - this._pointerData[pointer.id].y = pointer.y - this.sprite.y; + this._pointerData[pointer.id].x = pointer.x - this._parent.x; + this._pointerData[pointer.id].y = pointer.y - this._parent.y; if (this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { this.game.stage.canvas.style.cursor = "pointer"; } - this.sprite.events.onInputOver.dispatch(this.sprite, pointer); + this._parent.events.onInputOver.dispatch(this._parent, pointer); } } @@ -349,12 +368,10 @@ module Phaser.Components.Sprite { this.game.stage.canvas.style.cursor = "default"; } - this.sprite.events.onInputOut.dispatch(this.sprite, pointer); + this._parent.events.onInputOut.dispatch(this._parent, pointer); } - public consumePointerEvent: bool = false; - public _touchedHandler(pointer: Pointer): bool { if (this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) @@ -363,7 +380,7 @@ module Phaser.Components.Sprite { this._pointerData[pointer.id].isUp = false; this._pointerData[pointer.id].timeDown = this.game.time.now; - this.sprite.events.onInputDown.dispatch(this.sprite, pointer); + this._parent.events.onInputDown.dispatch(this._parent, pointer); // Start drag //if (this.draggable && this.isDragged == false && pointer.targetObject == null) @@ -374,7 +391,7 @@ module Phaser.Components.Sprite { if (this.bringToTop) { - this.sprite.group.bringToTop(this.sprite); + this._parent.group.bringToTop(this._parent); } } @@ -386,7 +403,7 @@ module Phaser.Components.Sprite { public _releasedHandler(pointer: Pointer) { - // If was previously touched by this Pointer, check if still is + // If was previously touched by this Pointer, check if still is AND still over this item if (this._pointerData[pointer.id].isDown && pointer.isUp) { this._pointerData[pointer.id].isDown = false; @@ -394,7 +411,19 @@ module Phaser.Components.Sprite { this._pointerData[pointer.id].timeUp = this.game.time.now; this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; - this.sprite.events.onInputUp.dispatch(this.sprite, pointer); + // Only release the InputUp signal if the pointer is still over this sprite + if (SpriteUtils.overlapsXY(this._parent, pointer.worldX(), pointer.worldY())) + { + this._parent.events.onInputUp.dispatch(this._parent, pointer); + } + else + { + // Pointer outside the sprite? Reset the cursor + if (this.useHandCursor) + { + this.game.stage.canvas.style.cursor = "default"; + } + } // Stop drag if (this.draggable && this.isDragged && this._draggedPointerID == pointer.id) @@ -402,10 +431,6 @@ module Phaser.Components.Sprite { this.stopDrag(pointer); } - if (this.useHandCursor) - { - this.game.stage.canvas.style.cursor = "default"; - } } } @@ -423,12 +448,12 @@ module Phaser.Components.Sprite { if (this.allowHorizontalDrag) { - this.sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; + this._parent.x = pointer.x + this._dragPoint.x + this.dragOffset.x; } if (this.allowVerticalDrag) { - this.sprite.y = pointer.y + this._dragPoint.y + this.dragOffset.y; + this._parent.y = pointer.y + this._dragPoint.y + this.dragOffset.y; } if (this.boundsRect) @@ -443,8 +468,8 @@ module Phaser.Components.Sprite { if (this.snapOnDrag) { - this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; - this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; + this._parent.x = Math.floor(this._parent.x / this.snapX) * this.snapX; + this._parent.y = Math.floor(this._parent.y / this.snapY) * this.snapY; } return true; @@ -579,23 +604,23 @@ module Phaser.Components.Sprite { if (this.dragFromCenter) { // Move the sprite to the middle of the pointer - //this._dragPoint.setTo(-this.sprite.worldView.halfWidth, -this.sprite.worldView.halfHeight); - //this._dragPoint.setTo(this.sprite.transform.center.x, this.sprite.transform.center.y); - this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); + //this._dragPoint.setTo(-this._parent.worldView.halfWidth, -this._parent.worldView.halfHeight); + //this._dragPoint.setTo(this._parent.transform.center.x, this._parent.transform.center.y); + this._dragPoint.setTo(this._parent.x - pointer.x, this._parent.y - pointer.y); } else { - this._dragPoint.setTo(this.sprite.x - pointer.x, this.sprite.y - pointer.y); + this._dragPoint.setTo(this._parent.x - pointer.x, this._parent.y - pointer.y); } this.updateDrag(pointer); if (this.bringToTop) { - this.sprite.group.bringToTop(this.sprite); + this._parent.group.bringToTop(this._parent); } - this.sprite.events.onDragStart.dispatch(this.sprite, pointer); + this._parent.events.onDragStart.dispatch(this._parent, pointer); } @@ -610,11 +635,12 @@ module Phaser.Components.Sprite { if (this.snapOnRelease) { - this.sprite.x = Math.floor(this.sprite.x / this.snapX) * this.snapX; - this.sprite.y = Math.floor(this.sprite.y / this.snapY) * this.snapY; + this._parent.x = Math.floor(this._parent.x / this.snapX) * this.snapX; + this._parent.y = Math.floor(this._parent.y / this.snapY) * this.snapY; } - this.sprite.events.onDragStop.dispatch(this.sprite, pointer); + this._parent.events.onDragStop.dispatch(this._parent, pointer); + this._parent.events.onInputUp.dispatch(this._parent, pointer); } /** @@ -660,22 +686,22 @@ module Phaser.Components.Sprite { */ private checkBoundsRect():void { - if (this.sprite.x < this.boundsRect.left) + if (this._parent.x < this.boundsRect.left) { - this.sprite.x = this.boundsRect.x; + this._parent.x = this.boundsRect.x; } - else if ((this.sprite.x + this.sprite.width) > this.boundsRect.right) + else if ((this._parent.x + this._parent.width) > this.boundsRect.right) { - this.sprite.x = this.boundsRect.right - this.sprite.width; + this._parent.x = this.boundsRect.right - this._parent.width; } - if (this.sprite.y < this.boundsRect.top) + if (this._parent.y < this.boundsRect.top) { - this.sprite.y = this.boundsRect.top; + this._parent.y = this.boundsRect.top; } - else if ((this.sprite.y + this.sprite.height) > this.boundsRect.bottom) + else if ((this._parent.y + this._parent.height) > this.boundsRect.bottom) { - this.sprite.y = this.boundsRect.bottom - this.sprite.height; + this._parent.y = this.boundsRect.bottom - this._parent.height; } } @@ -684,22 +710,22 @@ module Phaser.Components.Sprite { */ private checkBoundsSprite():void { - if (this.sprite.x < this.boundsSprite.x) + if (this._parent.x < this.boundsSprite.x) { - this.sprite.x = this.boundsSprite.x; + this._parent.x = this.boundsSprite.x; } - else if ((this.sprite.x + this.sprite.width) > (this.boundsSprite.x + this.boundsSprite.width)) + else if ((this._parent.x + this._parent.width) > (this.boundsSprite.x + this.boundsSprite.width)) { - this.sprite.x = (this.boundsSprite.x + this.boundsSprite.width) - this.sprite.width; + this._parent.x = (this.boundsSprite.x + this.boundsSprite.width) - this._parent.width; } - if (this.sprite.y < this.boundsSprite.y) + if (this._parent.y < this.boundsSprite.y) { - this.sprite.y = this.boundsSprite.y; + this._parent.y = this.boundsSprite.y; } - else if ((this.sprite.y + this.sprite.height) > (this.boundsSprite.y + this.boundsSprite.height)) + else if ((this._parent.y + this._parent.height) > (this.boundsSprite.y + this.boundsSprite.height)) { - this.sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this.sprite.height; + this._parent.y = (this.boundsSprite.y + this.boundsSprite.height) - this._parent.height; } } @@ -711,13 +737,13 @@ module Phaser.Components.Sprite { */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this.sprite.texture.context.font = '14px Courier'; - this.sprite.texture.context.fillStyle = color; - this.sprite.texture.context.fillText('Sprite Input: (' + this.sprite.worldView.width + ' x ' + this.sprite.worldView.height + ')', x, y); - this.sprite.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); - this.sprite.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); - this.sprite.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); - this.sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); + this._parent.texture.context.font = '14px Courier'; + this._parent.texture.context.fillStyle = color; + this._parent.texture.context.fillText('Sprite Input: (' + this._parent.worldView.width + ' x ' + this._parent.worldView.height + ')', x, y); + this._parent.texture.context.fillText('x: ' + this.pointerX().toFixed(1) + ' y: ' + this.pointerY().toFixed(1), x, y + 14); + this._parent.texture.context.fillText('over: ' + this.pointerOver() + ' duration: ' + this.overDuration().toFixed(0), x, y + 28); + this._parent.texture.context.fillText('down: ' + this.pointerDown() + ' duration: ' + this.downDuration().toFixed(0), x, y + 42); + this._parent.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 56); } diff --git a/Phaser/gameobjects/Button.ts b/Phaser/gameobjects/Button.ts new file mode 100644 index 00000000..c435935a --- /dev/null +++ b/Phaser/gameobjects/Button.ts @@ -0,0 +1,211 @@ +/// +/// +/// +/// +/// +/// +/// +/// + +/** +* Phaser - Button +*/ + +module Phaser { + + export class Button extends Sprite { + + /** + * Create a new Button object. + * + * @param game {Phaser.Game} Current game instance. + * @param [x] {number} the initial x position of the button. + * @param [y] {number} the initial y position of the button. + * @param [key] {string} Key of the graphic you want to load for this button. + */ + constructor(game: Game, x?: number = 0, y?: number = 0, key?: string = null, callback? = null, callbackContext? = null, overFrame? = null, outFrame? = null, downFrame? = null) { + + super(game, x, y, key, outFrame); + + this.type = Phaser.Types.BUTTON; + + if (typeof overFrame == 'string') + { + this._onOverFrameName = overFrame; + } + else + { + this._onOverFrameID = overFrame; + } + + if (typeof outFrame == 'string') + { + this._onOutFrameName = outFrame; + this._onUpFrameName = outFrame; + } + else + { + this._onOutFrameID = outFrame; + this._onUpFrameID = outFrame; + } + + if (typeof downFrame == 'string') + { + this._onDownFrameName = downFrame; + } + else + { + this._onDownFrameID = downFrame; + } + + // These are the signals the game will subscribe to + this.onInputOver = new Phaser.Signal; + this.onInputOut = new Phaser.Signal; + this.onInputDown = new Phaser.Signal; + this.onInputUp = new Phaser.Signal; + + // Set a default signal for them + if (callback) + { + this.onInputUp.add(callback, callbackContext); + } + + this.input.start(0, false, true); + + // Redirect the input events to here so we can handle animation updates, etc + this.events.onInputOver.add(this.onInputOverHandler, this); + this.events.onInputOut.add(this.onInputOutHandler, this); + this.events.onInputDown.add(this.onInputDownHandler, this); + this.events.onInputUp.add(this.onInputUpHandler, this); + + // By default we'll position it using screen space, not world space. + this.transform.scrollFactor.setTo(0, 0); + + } + + private _onOverFrameName = null; + private _onOutFrameName = null; + private _onDownFrameName = null; + private _onUpFrameName = null; + private _onOverFrameID = null; + private _onOutFrameID = null; + private _onDownFrameID = null; + private _onUpFrameID = null; + + /** + * Dispatched when a pointer moves over an Input enabled sprite. + */ + public onInputOver: Phaser.Signal; + + /** + * Dispatched when a pointer moves out of an Input enabled sprite. + */ + public onInputOut: Phaser.Signal; + + /** + * Dispatched when a pointer is pressed down on an Input enabled sprite. + */ + public onInputDown: Phaser.Signal; + + /** + * Dispatched when a pointer is released over an Input enabled sprite + */ + public onInputUp: Phaser.Signal; + + // TODO + //public tabIndex: number; + //public tabEnabled: bool; + + // ENTER or SPACE can activate this button if it has focus + + private onInputOverHandler(pointer:Phaser.Pointer) { + + if (this._onOverFrameName != null) + { + this.frameName = this._onOverFrameName; + } + else if (this._onOverFrameID != null) + { + this.frame = this._onOverFrameID; + } + + if (this.onInputOver) + { + this.onInputOver.dispatch(this, pointer); + } + + } + + private onInputOutHandler(pointer:Phaser.Pointer) { + + if (this._onOutFrameName != null) + { + this.frameName = this._onOutFrameName; + } + else if (this._onOutFrameID != null) + { + this.frame = this._onOutFrameID; + } + + if (this.onInputOut) + { + this.onInputOut.dispatch(this, pointer); + } + + } + + private onInputDownHandler(pointer:Phaser.Pointer) { + + if (this._onDownFrameName != null) + { + this.frameName = this._onDownFrameName; + } + else if (this._onDownFrameID != null) + { + this.frame = this._onDownFrameID; + } + + if (this.onInputDown) + { + this.onInputDown.dispatch(this, pointer); + } + + } + + private onInputUpHandler(pointer:Phaser.Pointer) { + + if (this._onUpFrameName != null) + { + this.frameName = this._onUpFrameName; + } + else if (this._onUpFrameID != null) + { + this.frame = this._onUpFrameID; + } + + if (this.onInputUp) + { + this.onInputUp.dispatch(this, pointer); + } + + } + + public set priorityID(value: number) { + this.input.priorityID = value; + } + + public get priorityID(): number { + return this.input.priorityID; + } + + public set useHandCursor(value: bool) { + this.input.useHandCursor = value; + } + + public get useHandCursor(): bool { + return this.input.useHandCursor; + } + + } + +} \ No newline at end of file diff --git a/Phaser/gameobjects/DynamicTexture.ts b/Phaser/gameobjects/DynamicTexture.ts index 2b77407d..579eadcd 100644 --- a/Phaser/gameobjects/DynamicTexture.ts +++ b/Phaser/gameobjects/DynamicTexture.ts @@ -77,6 +77,14 @@ module Phaser { */ public context: CanvasRenderingContext2D; + /** + * You can set a globalCompositeOperation that will be applied before the render method is called on this Sprite. + * This is useful if you wish to apply an effect like 'lighten'. + * If this value is set it will call a canvas context save and restore before and after the render pass, so use it sparingly. + * Set to null to disable. + */ + public globalCompositeOperation: string = null; + /** * Get a color of a specific pixel. * @param x {number} X position of the pixel in this texture. @@ -252,12 +260,15 @@ module Phaser { * Given an array of Sprites it will update each of them so that their canvas/contexts reference this DynamicTexture * @param objects {Array} An array of GameObjects, or objects that inherit from it such as Sprites */ - public assignCanvasToGameObjects(objects: IGameObject[]) { + public assignCanvasToGameObjects(objects) { for (var i = 0; i < objects.length; i++) { - objects[i].texture.canvas = this.canvas; - objects[i].texture.context = this.context; + if (objects[i].texture) + { + objects[i].texture.canvas = this.canvas; + objects[i].texture.context = this.context; + } } } @@ -278,7 +289,20 @@ module Phaser { * @param y {number} The Y coordinate to render on the stage to (given in screen coordinates, not world) */ public render(x?: number = 0, y?: number = 0) { + + if (this.globalCompositeOperation) + { + this.game.stage.context.save(); + this.game.stage.context.globalCompositeOperation = this.globalCompositeOperation; + } + this.game.stage.context.drawImage(this.canvas, x, y); + + if (this.globalCompositeOperation) + { + this.game.stage.context.restore(); + } + } public get width(): number { diff --git a/Phaser/gameobjects/GameObjectFactory.ts b/Phaser/gameobjects/GameObjectFactory.ts index dc9e071f..e6251ada 100644 --- a/Phaser/gameobjects/GameObjectFactory.ts +++ b/Phaser/gameobjects/GameObjectFactory.ts @@ -3,6 +3,7 @@ /// /// /// +/// /// /// /// @@ -62,6 +63,23 @@ module Phaser { // return this._world.group.add(new GeomSprite(this._game, x, y)); //} + /** + * Create a new Button game object. + * + * @param [x] {number} X position of the button. + * @param [y] {number} Y position of the button. + * @param [key] {string} The image key as defined in the Game.Cache to use as the texture for this button. + * @param [callback] {function} The function to call when this button is pressed + * @param [callbackContext] {object} The context in which the callback will be called (usually 'this') + * @param [overFrame] {string|number} This is the frame or frameName that will be set when this button is in an over state. Give either a number to use a frame ID or a string for a frame name. + * @param [outFrame] {string|number} This is the frame or frameName that will be set when this button is in an out state. Give either a number to use a frame ID or a string for a frame name. + * @param [downFrame] {string|number} This is the frame or frameName that will be set when this button is in a down state. Give either a number to use a frame ID or a string for a frame name. + * @returns {Button} The newly created button object. + */ + public button(x?: number = 0, y?: number = 0, key?: string = null, callback? = null, callbackContext? = null, overFrame? = null, outFrame? = null, downFrame? = null): Button { + return