diff --git a/Docs/box-01.png b/Docs/box-01.png new file mode 100644 index 00000000..09ae319a Binary files /dev/null and b/Docs/box-01.png differ diff --git a/Docs/box-02.png b/Docs/box-02.png new file mode 100644 index 00000000..e6dcceb2 Binary files /dev/null and b/Docs/box-02.png differ diff --git a/Phaser/Phaser.csproj b/Phaser/Phaser.csproj index 8238d8c1..098fdfbd 100644 --- a/Phaser/Phaser.csproj +++ b/Phaser/Phaser.csproj @@ -170,6 +170,10 @@ CanvasRenderer.ts + + + OrientationScreen.ts + CircleUtils.ts diff --git a/Phaser/Stage.ts b/Phaser/Stage.ts index 8754c1f0..d38f84da 100644 --- a/Phaser/Stage.ts +++ b/Phaser/Stage.ts @@ -3,6 +3,7 @@ /// /// /// +/// /** * Phaser - Stage @@ -32,7 +33,7 @@ module Phaser { this.canvas.width = width; this.canvas.height = height; - if (document.getElementById(parent)) + if ((parent !== '' || parent !== null) && document.getElementById(parent)) { document.getElementById(parent).appendChild(this.canvas); document.getElementById(parent).style.overflow = 'hidden'; @@ -51,12 +52,13 @@ module Phaser { this.context = this.canvas.getContext('2d'); - this.offset = this.getOffset(this.canvas); - this.bounds = new Rectangle(this.offset.x, this.offset.y, width, height); - this.aspectRatio = width / height; this.scaleMode = StageScaleMode.NO_SCALE; this.scale = new StageScaleMode(this._game); + this.getOffset(this.canvas); + this.bounds = new Rectangle(this.offset.x, this.offset.y, width, height); + this.aspectRatio = width / height; + document.addEventListener('visibilitychange', (event) => this.visibilityChange(event), false); document.addEventListener('webkitvisibilitychange', (event) => this.visibilityChange(event), false); window.onblur = (event) => this.visibilityChange(event); @@ -70,22 +72,28 @@ module Phaser { private _game: Game; /** - * Background color of the stage (defaults to black) + * Background color of the stage (defaults to black). Set via the public backgroundColor property. * @type {string} */ - private _bgColor: string = 'rgb(0,0,0)'; + private _backgroundColor: string = 'rgb(0,0,0)'; /** * This will be displayed when Phaser is started without any default functions or State * @type {BootScreen} */ - private _bootScreen; + public bootScreen; /** * This will be displayed whenever the game loses focus or the player switches to another browser tab. * @type {PauseScreen} */ - private _pauseScreen; + public pauseScreen; + + /** + * This will be displayed whenever the device is turned to an unsupported orientation. + * @type {OrientationScreen} + */ + public orientationScreen; /** * Bound of this stage. @@ -155,8 +163,9 @@ module Phaser { */ public boot() { - this._bootScreen = new BootScreen(this._game); - this._pauseScreen = new PauseScreen(this._game, this.width, this.height); + this.bootScreen = new BootScreen(this._game); + this.pauseScreen = new PauseScreen(this._game, this.width, this.height); + this.orientationScreen = new OrientationScreen(this._game); } @@ -174,16 +183,23 @@ module Phaser { this.context.clearRect(0, 0, this.width, this.height); } - if (this._game.isRunning == false && this.disableBootScreen == false) + if (this._game.paused && this.scale.incorrectOrientation) { - this._bootScreen.update(); - this._bootScreen.render(); + this.orientationScreen.update(); + this.orientationScreen.render(); + return; } - if (this._game.paused == true && this.disablePauseScreen == false) + if (this._game.isRunning == false && this.disableBootScreen == false) { - this._pauseScreen.update(); - this._pauseScreen.render(); + this.bootScreen.update(); + this.bootScreen.render(); + } + + if (this._game.paused && this.disablePauseScreen == false) + { + this.pauseScreen.update(); + this.pauseScreen.render(); } } @@ -215,9 +231,35 @@ module Phaser { } + public enableOrientationCheck(forceLandscape: bool, forcePortrait: bool, imageKey?: string = '') { + + this.scale.forceLandscape = forceLandscape; + this.scale.forcePortrait = forcePortrait; + this.orientationScreen.enable(forceLandscape, forcePortrait, imageKey); + + if (forceLandscape || forcePortrait) + { + if ((this.scale.isLandscape && forcePortrait) || (this.scale.isPortrait && forceLandscape)) + { + // They are in the wrong orientation right now + this._game.paused = true; + this.scale.incorrectOrientation = true; + } + else + { + this.scale.incorrectOrientation = false; + } + } + + } + public pauseGame() { - this._pauseScreen.onPaused(); + if (this.disablePauseScreen == false) + { + this.pauseScreen.onPaused(); + } + this.saveCanvasValues(); this._game.paused = true; @@ -225,7 +267,11 @@ module Phaser { public resumeGame() { - this._pauseScreen.onResume(); + if (this.disablePauseScreen == false) + { + this.pauseScreen.onResume(); + } + this.restoreCanvasValues(); this._game.paused = false; @@ -234,7 +280,7 @@ module Phaser { /** * Get the DOM offset values of the given element */ - private getOffset(element): Point { + public getOffset(element, populateOffset: bool = true): Point { var box = element.getBoundingClientRect(); @@ -243,7 +289,15 @@ module Phaser { var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop; var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft; - return new Point(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop); + if (populateOffset) + { + this.offset = new Point(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop); + return this.offset; + } + else + { + return new Point(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop); + } } @@ -289,10 +343,11 @@ module Phaser { public set backgroundColor(color: string) { this.canvas.style.backgroundColor = color; + this._backgroundColor = color; } public get backgroundColor(): string { - return this._bgColor; + return this._backgroundColor; } public get x(): number { diff --git a/Phaser/components/animation/Frame.ts b/Phaser/components/animation/Frame.ts index 1c00d486..aa74a684 100644 --- a/Phaser/components/animation/Frame.ts +++ b/Phaser/components/animation/Frame.ts @@ -22,7 +22,7 @@ module Phaser { */ constructor(x: number, y: number, width: number, height: number, name: string) { - console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); + //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); this.x = x; this.y = y; diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 26cf776b..91a9f89a 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -258,7 +258,7 @@ module Phaser.Components { } else { - return RectangleUtils.contains(this._sprite.frameBounds, pointer.x, pointer.y); + return RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY); } } @@ -279,10 +279,10 @@ module Phaser.Components { } else if (this._pointerData[pointer.id].isOver == true) { - if (RectangleUtils.contains(this._sprite.frameBounds, pointer.x, pointer.y)) + if (RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY)) { - 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.scaledX - this._sprite.x; + this._pointerData[pointer.id].y = pointer.scaledY - this._sprite.y; return true; } else @@ -335,9 +335,11 @@ module Phaser.Components { public _touchedHandler(pointer: Pointer): bool { + console.log('touched handler', this._pointerData[pointer.id]); + if (this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { - console.log('touchDown on', this._sprite.texture.cacheKey,this._sprite.frameName, this._sprite.frameBounds.width,this._sprite.frameBounds.height); + //console.log('touchDown on', this._sprite.texture.cacheKey,this._sprite.frameName, this._sprite.frameBounds.width,this._sprite.frameBounds.height); this._pointerData[pointer.id].isDown = true; this._pointerData[pointer.id].isUp = false; this._pointerData[pointer.id].timeDown = this.game.time.now; @@ -360,6 +362,8 @@ module Phaser.Components { public _releasedHandler(pointer: Pointer) { + console.log('release handler'); + // If was previously touched by this Pointer, check if still is if (this._pointerData[pointer.id].isDown && pointer.isUp) { @@ -674,13 +678,13 @@ module Phaser.Components { */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this._sprite.texture.context.font = '14px Courier'; + this._sprite.texture.context.font = '16px Courier'; this._sprite.texture.context.fillStyle = color; this._sprite.texture.context.fillText('Sprite Input: (' + this._sprite.frameBounds.width + ' x ' + this._sprite.frameBounds.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._sprite.texture.context.fillText('x: ' + this.pointerX(1).toFixed(1) + ' y: ' + this.pointerY(1).toFixed(1), x, y + 14); + this._sprite.texture.context.fillText('over: ' + this.pointerOver(1) + ' duration: ' + this.overDuration(1).toFixed(0), x, y + 28); + this._sprite.texture.context.fillText('down: ' + this.pointerDown(1) + ' duration: ' + this.downDuration(1).toFixed(0), x, y + 42); + this._sprite.texture.context.fillText('just over: ' + this.justOver(1) + ' just out: ' + this.justOut(1), x, y + 56); } diff --git a/Phaser/input/Input.ts b/Phaser/input/Input.ts index 9cd629e0..7ba45d64 100644 --- a/Phaser/input/Input.ts +++ b/Phaser/input/Input.ts @@ -513,17 +513,9 @@ module Phaser { if (this.pointer10) { this.pointer10.reset(); } this.currentPointers = 0; - - for (var i = 0; i < this.totalTrackedObjects; i++) - { - this.inputObjects[i].input.reset(); - } - + this._game.stage.canvas.style.cursor = "default"; - this.inputObjects.length = 0; - this.totalTrackedObjects = 0; - if (hard == true) { this.onDown.dispose(); @@ -535,6 +527,14 @@ module Phaser { this.onUp = new Phaser.Signal(); this.onTap = new Phaser.Signal(); this.onHold = new Phaser.Signal(); + + for (var i = 0; i < this.totalTrackedObjects; i++) + { + this.inputObjects[i].input.reset(); + } + + this.inputObjects.length = 0; + this.totalTrackedObjects = 0; } } @@ -904,7 +904,7 @@ module Phaser { */ public renderDebugInfo(x: number, y: number, color?: string = 'rgb(255,255,255)') { - this._game.stage.context.font = '14px Courier'; + this._game.stage.context.font = '24px Courier'; this._game.stage.context.fillStyle = color; this._game.stage.context.fillText('Input', x, y); this._game.stage.context.fillText('Screen X: ' + this.x + ' Screen Y: ' + this.y, x, y + 14); diff --git a/Phaser/input/Mouse.ts b/Phaser/input/Mouse.ts index f3dcac19..d1df7f7b 100644 --- a/Phaser/input/Mouse.ts +++ b/Phaser/input/Mouse.ts @@ -13,6 +13,7 @@ module Phaser { constructor(game: Game) { this._game = game; + this.callbackContext = this._game; } @@ -34,6 +35,15 @@ module Phaser { */ public disabled: bool = false; + /** + * Custom callback useful for hooking into a 3rd party library. Will be passed the mouse event as the only parameter. + * Callbacks are fired even if this component is disabled and before the event propagation is disabled. + */ + public callbackContext; + public mouseDownCallback = null; + public mouseMoveCallback = null; + public mouseUpCallback = null; + /** * Starts the event listeners running * @method start @@ -51,6 +61,11 @@ module Phaser { */ public onMouseDown(event: MouseEvent) { + if (this.mouseDownCallback) + { + this.mouseDownCallback.call(this.callbackContext, event); + } + if (this._game.input.disabled || this.disabled) { return; @@ -67,6 +82,11 @@ module Phaser { */ public onMouseMove(event: MouseEvent) { + if (this.mouseMoveCallback) + { + this.mouseMoveCallback.call(this.callbackContext, event); + } + if (this._game.input.disabled || this.disabled) { return; @@ -83,6 +103,11 @@ module Phaser { */ public onMouseUp(event: MouseEvent) { + if (this.mouseUpCallback) + { + this.mouseUpCallback.call(this.callbackContext, event); + } + if (this._game.input.disabled || this.disabled) { return; diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index 7cf4a944..bd66bc01 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -282,6 +282,22 @@ module Phaser { } + /** + * Gets the X value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + public get scaledX():number { + return Math.floor(this.x * this.game.input.scaleX); + } + + /** + * Gets the Y value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + public get scaledY():number { + return Math.floor(this.y * this.game.input.scaleY); + } + /** * Called when the Pointer is pressed onto the touchscreen * @method start @@ -298,7 +314,7 @@ module Phaser { } // Fix to stop rogue browser plugins from blocking the visibility state event - if (this.game.paused == true) + if (this.game.paused == true && this.game.stage.scale.incorrectOrientation == false) { this.game.stage.resumeGame(); return this; @@ -495,11 +511,9 @@ module Phaser { } } - //console.log('pointer move', _highestRenderID); - if (_highestRenderObject !== -1) { - console.log('setting target'); + //console.log('setting target'); this.targetObject = this.game.input.inputObjects[_highestRenderObject]; this.targetObject.input._pointerOverHandler(this); } @@ -650,6 +664,12 @@ module Phaser { this._holdSent = false; this._history.length = 0; this._stateReset = true; + + if (this.targetObject) + { + this.targetObject.input._releasedHandler(this); + } + this.targetObject = null; } diff --git a/Phaser/input/Touch.ts b/Phaser/input/Touch.ts index 7ddad452..8d46b706 100644 --- a/Phaser/input/Touch.ts +++ b/Phaser/input/Touch.ts @@ -23,6 +23,7 @@ module Phaser { constructor(game: Game) { this._game = game; + this.callbackContext = this._game; } @@ -40,6 +41,18 @@ module Phaser { */ public disabled: bool = false; + /** + * Custom callback useful for hooking into a 3rd party library. Will be passed the touch event as the only parameter. + * Callbacks are fired even if this component is disabled and before the event propogation is disabled. + */ + public callbackContext; + public touchStartCallback = null; + public touchMoveCallback = null; + public touchEndCallback = null; + public touchEnterCallback = null; + public touchLeaveCallback = null; + public touchCancelCallback = null; + /** * Starts the event listeners running * @method start @@ -78,6 +91,11 @@ module Phaser { **/ private onTouchStart(event) { + if (this.touchStartCallback) + { + this.touchStartCallback.call(this.callbackContext, event); + } + if (this._game.input.disabled || this.disabled) { return; @@ -103,6 +121,11 @@ module Phaser { **/ private onTouchCancel(event) { + if (this.touchCancelCallback) + { + this.touchCancelCallback.call(this.callbackContext, event); + } + if (this._game.input.disabled || this.disabled) { return; @@ -127,6 +150,11 @@ module Phaser { **/ private onTouchEnter(event) { + if (this.touchEnterCallback) + { + this.touchEnterCallback.call(this.callbackContext, event); + } + if (this._game.input.disabled || this.disabled) { return; @@ -136,7 +164,7 @@ module Phaser { for (var i = 0; i < event.changedTouches.length; i++) { - console.log('touch enter'); + //console.log('touch enter'); } } @@ -149,11 +177,16 @@ module Phaser { **/ private onTouchLeave(event) { + if (this.touchLeaveCallback) + { + this.touchLeaveCallback.call(this.callbackContext, event); + } + event.preventDefault(); for (var i = 0; i < event.changedTouches.length; i++) { - console.log('touch leave'); + //console.log('touch leave'); } } @@ -165,6 +198,11 @@ module Phaser { **/ private onTouchMove(event) { + if (this.touchMoveCallback) + { + this.touchMoveCallback.call(this.callbackContext, event); + } + event.preventDefault(); for (var i = 0; i < event.changedTouches.length; i++) @@ -181,6 +219,11 @@ module Phaser { **/ private onTouchEnd(event) { + if (this.touchEndCallback) + { + this.touchEndCallback.call(this.callbackContext, event); + } + event.preventDefault(); // For touch end its a list of the touch points that have been removed from the surface diff --git a/Phaser/system/StageScaleMode.ts b/Phaser/system/StageScaleMode.ts index 637c8822..bddfaa89 100644 --- a/Phaser/system/StageScaleMode.ts +++ b/Phaser/system/StageScaleMode.ts @@ -38,6 +38,9 @@ module Phaser { } } + this.scaleFactor = new Vec2(1, 1); + this.aspectRatio = 0; + window.addEventListener('orientationchange', (event) => this.checkOrientation(event), false); window.addEventListener('resize', (event) => this.checkResize(event), false); @@ -74,6 +77,24 @@ module Phaser { */ public static SHOW_ALL: number = 2; + /** + * If the game should be forced to use Landscape mode, this is set to true by Game.Stage + * @type {Boolean} + */ + public forceLandscape: bool = false; + + /** + * If the game should be forced to use Portrait mode, this is set to true by Game.Stage + * @type {Boolean} + */ + public forcePortrait: bool = false; + + /** + * If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true. + * @type {Boolean} + */ + public incorrectOrientation: bool = false; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} @@ -113,23 +134,36 @@ module Phaser { public height: number = 0; /** - * Window orientation angle (90 and -90 are landscape, 0 is portrait) + * Asperct ratio of the scaled game size (width / height) + * @type {number} + */ + public aspectRatio: number; + + /** + * The scale factor of the scaled game width + * @type {Vec2} + */ + public scaleFactor: Vec2; + + /** + * Window orientation angle (90 and -90 are landscape, 0 and 80 are portrait) * @type {number} */ public orientation: number; /** - * A Signal that is dispatched when the device enters landscape mode from portrait + * A Signal that is dispatched when the device enters landscape orientation from portrait * @type {Signal} */ public enterLandscape: Phaser.Signal; /** - * A Signal that is dispatched when the device enters portrait mode from landscape + * A Signal that is dispatched when the device enters portrait orientation from landscape * @type {Signal} */ public enterPortrait: Phaser.Signal; + // Full Screen API calls public get isFullScreen(): bool { if (document['fullscreenElement'] === null|| document['mozFullScreenElement'] === null|| document['webkitFullscreenElement'] === null) @@ -192,10 +226,41 @@ module Phaser { this.refresh(); } + if (this.forceLandscape || this.forcePortrait) + { + this.checkOrientationState(); + } + + } + + private checkOrientationState() { + + // They are in the wrong orientation + if (this.incorrectOrientation) + { + if ((this.forceLandscape && window.innerWidth > window.innerHeight) || (this.forcePortrait && window.innerHeight > window.innerWidth)) + { + // Back to normal + this._game.paused = false; + this.incorrectOrientation = false; + this.refresh(); + } + } + else + { + if ((this.forceLandscape && window.innerWidth < window.innerHeight) || (this.forcePortrait && window.innerHeight < window.innerWidth)) + { + // Show orientation screen + this._game.paused = true; + this.incorrectOrientation = true; + this.refresh(); + } + } + } public get isPortrait(): bool { - return this.orientation == 0; + return this.orientation == 0 || this.orientation == 180; } public get isLandscape(): bool { @@ -211,11 +276,11 @@ module Phaser { if (this.isLandscape) { - this.enterLandscape.dispatch(this.orientation); + this.enterLandscape.dispatch(this.orientation, true, false); } else { - this.enterPortrait.dispatch(this.orientation); + this.enterPortrait.dispatch(this.orientation, false, true); } if (this._game.stage.scaleMode !== StageScaleMode.NO_SCALE) @@ -241,11 +306,11 @@ module Phaser { if (this.isLandscape) { - this.enterLandscape.dispatch(this.orientation); + this.enterLandscape.dispatch(this.orientation, true, false); } else { - this.enterPortrait.dispatch(this.orientation); + this.enterPortrait.dispatch(this.orientation, false, true); } if (this._game.stage.scaleMode !== StageScaleMode.NO_SCALE) @@ -281,6 +346,7 @@ module Phaser { { this._iterations = 40; this._check = window.setInterval(() => this.setScreenSize(), 10); + this.setScreenSize(); } } @@ -309,49 +375,20 @@ module Phaser { // Set minimum height of content to new window height document.documentElement.style.minHeight = window.innerHeight + 'px'; - if (this._game.stage.scaleMode == StageScaleMode.EXACT_FIT) + if (this.incorrectOrientation == true) { - if (this.maxWidth && window.innerWidth > this.maxWidth) - { - this.width = this.maxWidth; - } - else - { - this.width = window.innerWidth; - } - - if (this.maxHeight && window.innerHeight > this.maxHeight) - { - this.height = this.maxHeight; - } - else - { - this.height = window.innerHeight; - } + this.setMaximum(); + } + else if (this._game.stage.scaleMode == StageScaleMode.EXACT_FIT) + { + this.setExactFit(); } else if (this._game.stage.scaleMode == StageScaleMode.SHOW_ALL) { - var multiplier = Math.min((window.innerHeight / this._game.stage.height), (window.innerWidth / this._game.stage.width)); - - this.width = Math.round(this._game.stage.width * multiplier); - this.height = Math.round(this._game.stage.height * multiplier); - - if (this.maxWidth && this.width > this.maxWidth) - { - this.width = this.maxWidth; - } - - if (this.maxHeight && this.height > this.maxHeight) - { - this.height = this.maxHeight; - } + this.setShowAll(); } - this._game.stage.canvas.style.width = this.width + 'px'; - this._game.stage.canvas.style.height = this.height + 'px'; - - this._game.input.scaleX = this._game.stage.width / this.width; - this._game.input.scaleY = this._game.stage.height / this.height; + this.setSize(); clearInterval(this._check); @@ -361,6 +398,82 @@ module Phaser { } + private setSize() { + + if (this.maxWidth && this.width > this.maxWidth) + { + this.width = this.maxWidth; + } + + if (this.maxHeight && this.height > this.maxHeight) + { + this.height = this.maxHeight; + } + + if (this.minWidth && this.width < this.minWidth) + { + this.width = this.minWidth; + } + + if (this.minHeight && this.height < this.minHeight) + { + this.height = this.minHeight; + } + + this._game.stage.canvas.style.width = this.width + 'px'; + this._game.stage.canvas.style.height = this.height + 'px'; + + this._game.input.scaleX = this._game.stage.width / this.width; + this._game.input.scaleY = this._game.stage.height / this.height; + + this._game.stage.getOffset(this._game.stage.canvas); + + this.aspectRatio = this.width / this.height; + this.scaleFactor.x = this._game.stage.width / this.width; + this.scaleFactor.y = this._game.stage.height / this.height; + //this.scaleFactor.x = this.width / this._game.stage.width; + //this.scaleFactor.y = this.height / this._game.stage.height; + + } + + private setMaximum() { + + this.width = window.innerWidth; + this.height = window.innerHeight; + + } + + private setShowAll() { + + var multiplier = Math.min((window.innerHeight / this._game.stage.height), (window.innerWidth / this._game.stage.width)); + + this.width = Math.round(this._game.stage.width * multiplier); + this.height = Math.round(this._game.stage.height * multiplier); + + } + + private setExactFit() { + + if (this.maxWidth && window.innerWidth > this.maxWidth) + { + this.width = this.maxWidth; + } + else + { + this.width = window.innerWidth; + } + + if (this.maxHeight && window.innerHeight > this.maxHeight) + { + this.height = this.maxHeight; + } + else + { + this.height = window.innerHeight; + } + + } + } } \ No newline at end of file diff --git a/Phaser/system/screens/OrientationScreen.ts b/Phaser/system/screens/OrientationScreen.ts new file mode 100644 index 00000000..1dac73dd --- /dev/null +++ b/Phaser/system/screens/OrientationScreen.ts @@ -0,0 +1,79 @@ +/// + +/** +* Phaser - OrientationScreen +* +* The Orientation Screen is displayed whenever the device is turned to an unsupported orientation. +*/ + +module Phaser { + + export class OrientationScreen { + + /** + * OrientationScreen constructor + * Create a new OrientationScreen with specific width and height. + * + * @param width {number} Screen canvas width. + * @param height {number} Screen canvas height. + */ + constructor(game: Game) { + this.game = game; + } + + /** + * Local reference to game. + */ + public game: Game; + + private _showOnLandscape: bool = false; + private _showOnPortrait: bool = false; + + /** + * Landscape Image. If you only want your game to work in Portrait mode, and display an image when in Landscape, + * then set this to be the key of an image previously loaded into the Game.Cache. + * @type {Cache Reference} + */ + public landscapeImage; + + /** + * Portrait Image. If you only want your game to work in Landscape mode, and display an image when in Portrait, + * then set this to be the key of an image previously loaded into the Game.Cache. + * @type {Cache Reference} + */ + public portraitImage; + + public enable(onLandscape: bool, onPortrait: bool, imageKey: string) { + + this._showOnLandscape = onLandscape; + this._showOnPortrait = onPortrait; + this.landscapeImage = this.game.cache.getImage(imageKey); + this.portraitImage = this.game.cache.getImage(imageKey); + + } + + /** + * Update + */ + public update() { + } + + /** + * Render + */ + public render() { + + if (this._showOnLandscape) + { + this.game.stage.context.drawImage(this.landscapeImage, 0, 0, this.landscapeImage.width, this.landscapeImage.height, 0, 0, this.game.stage.width, this.game.stage.height); + } + else if (this._showOnPortrait) + { + this.game.stage.context.drawImage(this.portraitImage, 0, 0, this.portraitImage.width, this.portraitImage.height, 0, 0, this.game.stage.width, this.game.stage.height); + } + + } + + } + +} diff --git a/README.md b/README.md index a33e99f8..a6e071e0 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ TODO: * Added JSON Texture Atlas object support. * Bug in AnimationManager set frame/frameName - the width/height are trimmed and wrong * RenderOrderID won't work across cameras - but then neither do Pointers yet anyway - +* Swap to using time based motion (like the tweens) rather than delta timer - it just doesn't work well on slow phones V1.0.0 @@ -82,6 +82,15 @@ V1.0.0 * Fixed issue in Camera.inCamera check where it wouldn't take into consideration the Sprites scrollFactor. * Fixed issue with JSON Atlas loader incorrectly parsing the frames array. * Fixed bug in FrameData.getFrameByName where the first frame of the array would always be skipped. +* Fixed bug where the Stage.backgroundColor property wasn't being saved correctly. +* Made Stage.bootScreen and Stage.pauseScreen public so you can override them with your own States now. +* Added the new OrientationScreen and Stage.enableOrientationCheck to allow for easy 'portrait/landscape only' game handling. +* Added fix to StageScaleMode for 180 degree portrait orientation on iPad. +* Added fix to orientation check so that it updates the input offsets correctly on rotation. +* Added support for minWidth and minHeight to game scale size, so it can never go below those values when scaling. +* Vastly improved orientation detection and response speed. +* Added custom callback support for all Touch and Mouse Events so you can easily hook events to custom APIs. + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 3e9c47aa..00cc3f81 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -115,6 +115,10 @@ world drag.ts + + + sprite test 1.ts + graphic emitter.ts diff --git a/Tests/mobile/fullscreen.html b/Tests/mobile/fullscreen.html new file mode 100644 index 00000000..0c669898 --- /dev/null +++ b/Tests/mobile/fullscreen.html @@ -0,0 +1,62 @@ + + + + + + Phaser Mobile Fullscreen Test + + + + + +
+ + + + + \ No newline at end of file diff --git a/Tests/mobile/sprite test 1.js b/Tests/mobile/sprite test 1.js new file mode 100644 index 00000000..7462e943 --- /dev/null +++ b/Tests/mobile/sprite test 1.js @@ -0,0 +1,48 @@ +/// +(function () { + var game = new Phaser.Game(this, 'game', 320, 400, init, create); + var emitter; + function init() { + game.loader.addImageFile('backdrop1', 'assets/pics/atari_fujilogo.png'); + game.loader.addImageFile('backdrop2', 'assets/pics/acryl_bladerunner.png'); + game.loader.addImageFile('jet', 'assets/sprites/carrot.png'); + game.loader.load(); + // This can help a lot on crappy old Android phones :) + //game.framerate = 30; + game.stage.backgroundColor = 'rgb(0,0,0)'; + //game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL; + game.stage.scaleMode = Phaser.StageScaleMode.EXACT_FIT; + //game.stage.scaleMode = Phaser.StageScaleMode.NO_SCALE; + } + var pic1; + var pic2; + function create() { + console.log('created now'); + game.stage.enableOrientationCheck(false, true, 'backdrop2'); + pic1 = game.add.sprite(0, 0, 'backdrop1'); + pic2 = game.add.sprite(0, 0, 'backdrop2'); + // Creates a basic emitter, bursting out 50 default sprites (i.e. 16x16 white boxes) + emitter = game.add.emitter(game.stage.centerX, game.stage.centerY); + emitter.makeParticles('jet', 50, false, 0); + emitter.setRotation(0, 0); + emitter.start(false, 10, 0.1); + // Make sure the camera doesn't clip anything + game.camera.disableClipping = true; + game.stage.scale.enterLandscape.add(goneLandscape, this); + game.stage.scale.enterPortrait.add(gonePortrait, this); + game.onRenderCallback = render; + } + function goneLandscape() { + pic1.visible = true; + pic2.visible = false; + } + function gonePortrait() { + pic1.visible = false; + pic2.visible = true; + } + function render() { + game.stage.context.fillStyle = 'rgb(255,0,0)'; + game.stage.context.font = '20px Arial'; + //game.stage.context.fillText("ttc: " + game._raf.timeToCall.toString(), 0, 64); + } +})(); diff --git a/Tests/mobile/sprite test 1.ts b/Tests/mobile/sprite test 1.ts new file mode 100644 index 00000000..33766eca --- /dev/null +++ b/Tests/mobile/sprite test 1.ts @@ -0,0 +1,77 @@ +/// + +(function () { + + var game = new Phaser.Game(this, 'game', 320, 400, init, create); + + var emitter: Phaser.Emitter; + + function init() { + + game.loader.addImageFile('backdrop1', 'assets/pics/atari_fujilogo.png'); + game.loader.addImageFile('backdrop2', 'assets/pics/acryl_bladerunner.png'); + game.loader.addImageFile('jet', 'assets/sprites/carrot.png'); + + game.loader.load(); + + // This can help a lot on crappy old Android phones :) + //game.framerate = 30; + + game.stage.backgroundColor = 'rgb(0,0,0)'; + //game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL; + game.stage.scaleMode = Phaser.StageScaleMode.EXACT_FIT; + //game.stage.scaleMode = Phaser.StageScaleMode.NO_SCALE; + + } + + var pic1; + var pic2; + + function create() { + + console.log('created now'); + + game.stage.enableOrientationCheck(false, true, 'backdrop2'); + + pic1 = game.add.sprite(0, 0, 'backdrop1'); + pic2 = game.add.sprite(0, 0, 'backdrop2'); + + // Creates a basic emitter, bursting out 50 default sprites (i.e. 16x16 white boxes) + emitter = game.add.emitter(game.stage.centerX, game.stage.centerY); + emitter.makeParticles('jet', 50, false, 0); + emitter.setRotation(0, 0); + emitter.start(false, 10, 0.1); + + // Make sure the camera doesn't clip anything + game.camera.disableClipping = true; + + game.stage.scale.enterLandscape.add(goneLandscape, this); + game.stage.scale.enterPortrait.add(gonePortrait, this); + + game.onRenderCallback = render; + + } + + function goneLandscape() { + + pic1.visible = true; + pic2.visible = false; + + } + + function gonePortrait() { + + pic1.visible = false; + pic2.visible = true; + + } + + function render() { + + game.stage.context.fillStyle = 'rgb(255,0,0)'; + game.stage.context.font = '20px Arial'; + //game.stage.context.fillText("ttc: " + game._raf.timeToCall.toString(), 0, 64); + + } + +})(); diff --git a/Tests/mobile/test1.html b/Tests/mobile/test1.html new file mode 100644 index 00000000..7491bbf3 --- /dev/null +++ b/Tests/mobile/test1.html @@ -0,0 +1,62 @@ + + + + + + Phaser Mobile Fullscreen Test + + + + + +
+ + + + + \ No newline at end of file diff --git a/Tests/phaser.js b/Tests/phaser.js index 49912f67..9cf81893 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -4357,7 +4357,7 @@ var Phaser; * Either cw or ccw, rotation is always 90 degrees. */ this.rotationDirection = 'cw'; - console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); + //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); this.x = x; this.y = y; this.width = width; @@ -6267,6 +6267,13 @@ var Phaser; this.game.input.removeGameObject(this._sprite); } }; + Input.prototype.checkPointerOver = function (pointer) { + if(this.enabled == false || this._sprite.visible == false) { + return false; + } else { + return Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY); + } + }; Input.prototype.update = /** * Update */ @@ -6275,44 +6282,51 @@ var Phaser; return false; } if(this.draggable && this._draggedPointerID == pointer.id) { - this.updateDrag(pointer); + return this.updateDrag(pointer); + } else if(this._pointerData[pointer.id].isOver == true) { + if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY)) { + this._pointerData[pointer.id].x = pointer.scaledX - this._sprite.x; + this._pointerData[pointer.id].y = pointer.scaledY - this._sprite.y; + return true; + } else { + this._pointOutHandler(pointer); + return false; + } } - if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.x, pointer.y)) { - // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } + }; + Input.prototype._pointerOverHandler = function (pointer) { + // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } + if(this._pointerData[pointer.id].isOver == false) { + 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; - if(this._pointerData[pointer.id].isOver == false) { - this._pointerData[pointer.id].isOver = true; - this._pointerData[pointer.id].isOut = false; - this._pointerData[pointer.id].timeOver = this.game.time.now; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "pointer"; - } - this._sprite.events.onInputOver.dispatch(this._sprite, pointer); + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "pointer"; } - return true; - } else { - if(this._pointerData[pointer.id].isOver) { - this._pointerData[pointer.id].isOver = false; - this._pointerData[pointer.id].isOut = true; - this._pointerData[pointer.id].timeOut = this.game.time.now; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "default"; - } - this._sprite.events.onInputOut.dispatch(this._sprite, pointer); - } - return false; + this._sprite.events.onInputOver.dispatch(this._sprite, pointer); } }; + Input.prototype._pointOutHandler = function (pointer) { + this._pointerData[pointer.id].isOver = false; + this._pointerData[pointer.id].isOut = true; + this._pointerData[pointer.id].timeOut = this.game.time.now; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "default"; + } + this._sprite.events.onInputOut.dispatch(this._sprite, pointer); + }; Input.prototype._touchedHandler = function (pointer) { if(this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { - console.log('touchDown on', this._sprite.texture.cacheKey, this._sprite.frameBounds.width, this._sprite.frameBounds.height); + //console.log('touchDown on', this._sprite.texture.cacheKey,this._sprite.frameName, this._sprite.frameBounds.width,this._sprite.frameBounds.height); this._pointerData[pointer.id].isDown = true; this._pointerData[pointer.id].isUp = false; this._pointerData[pointer.id].timeDown = this.game.time.now; this._sprite.events.onInputDown.dispatch(this._sprite, pointer); // Start drag - if(this.draggable && this.isDragged == false && pointer.draggedObject == null) { + //if (this.draggable && this.isDragged == false && pointer.targetObject == null) + if(this.draggable && this.isDragged == false) { this.startDrag(pointer); } } @@ -6342,7 +6356,7 @@ var Phaser; function (pointer) { if(pointer.isUp) { this.stopDrag(pointer); - return; + return false; } if(this.allowHorizontalDrag) { this._sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; @@ -6360,6 +6374,7 @@ var Phaser; this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; } + return true; }; Input.prototype.justOver = /** * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) @@ -6477,8 +6492,8 @@ var Phaser; } else { this._dragPoint.setTo(this._sprite.x - pointer.x, this._sprite.y - pointer.y); } - pointer.draggedObject = this._sprite; - }; + //pointer.draggedObject = this._sprite; + }; Input.prototype.stopDrag = /** * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. */ @@ -6490,8 +6505,8 @@ var Phaser; this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; } - pointer.draggedObject = null; - }; + //pointer.draggedObject = null; + }; Input.prototype.setDragLock = /** * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! * @@ -6569,10 +6584,10 @@ var Phaser; this._sprite.texture.context.font = '14px Courier'; this._sprite.texture.context.fillStyle = color; this._sprite.texture.context.fillText('Sprite Input: (' + this._sprite.frameBounds.width + ' x ' + this._sprite.frameBounds.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._sprite.texture.context.fillText('x: ' + this.pointerX(1).toFixed(1) + ' y: ' + this.pointerY(1).toFixed(1), x, y + 14); + this._sprite.texture.context.fillText('over: ' + this.pointerOver(1) + ' duration: ' + this.overDuration(1).toFixed(0), x, y + 28); + this._sprite.texture.context.fillText('down: ' + this.pointerDown(1) + ' duration: ' + this.downDuration(1).toFixed(0), x, y + 42); + this._sprite.texture.context.fillText('just over: ' + this.justOver(1) + ' just out: ' + this.justOut(1), x, y + 56); }; return Input; })(); @@ -7148,6 +7163,10 @@ var Phaser; */ this.z = 0; /** + * Render iteration + */ + this.renderOrderID = 0; + /** * This value is added to the angle of the Sprite. * For example if you had a sprite graphic drawn facing straight up then you could set * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. @@ -10663,6 +10682,21 @@ var Phaser; */ this._startHeight = 0; /** + * If the game should be forced to use Landscape mode, this is set to true by Game.Stage + * @type {Boolean} + */ + this.forceLandscape = false; + /** + * If the game should be forced to use Portrait mode, this is set to true by Game.Stage + * @type {Boolean} + */ + this.forcePortrait = false; + /** + * If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true. + * @type {Boolean} + */ + this.incorrectOrientation = false; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} */ @@ -10717,7 +10751,8 @@ var Phaser; StageScaleMode.NO_SCALE = 1; StageScaleMode.SHOW_ALL = 2; Object.defineProperty(StageScaleMode.prototype, "isFullScreen", { - get: function () { + get: // Full Screen API calls + function () { if(document['fullscreenElement'] === null || document['mozFullScreenElement'] === null || document['webkitFullscreenElement'] === null) { return false; } @@ -10755,10 +10790,33 @@ var Phaser; if(this._game.stage.scaleMode !== StageScaleMode.NO_SCALE && (window.innerWidth !== this.width || window.innerHeight !== this.height)) { this.refresh(); } + if(this.forceLandscape || this.forcePortrait) { + this.checkOrientationState(); + } + }; + StageScaleMode.prototype.checkOrientationState = function () { + // They are in the wrong orientation + if(this.incorrectOrientation) { + if((this.forceLandscape && window.innerWidth > window.innerHeight) || (this.forcePortrait && window.innerHeight > window.innerWidth)) { + // Back to normal + this._game.paused = false; + this.incorrectOrientation = false; + this._game.input.reset(); + this.refresh(); + } + } else { + if((this.forceLandscape && window.innerWidth < window.innerHeight) || (this.forcePortrait && window.innerHeight < window.innerWidth)) { + // Show orientation screen + this._game.paused = true; + this.incorrectOrientation = true; + this._game.input.reset(); + this.refresh(); + } + } }; Object.defineProperty(StageScaleMode.prototype, "isPortrait", { get: function () { - return this.orientation == 0; + return this.orientation == 0 || this.orientation == 180; }, enumerable: true, configurable: true @@ -10776,9 +10834,9 @@ var Phaser; function (event) { this.orientation = window['orientation']; if(this.isLandscape) { - this.enterLandscape.dispatch(this.orientation); + this.enterLandscape.dispatch(this.orientation, true, false); } else { - this.enterPortrait.dispatch(this.orientation); + this.enterPortrait.dispatch(this.orientation, false, true); } if(this._game.stage.scaleMode !== StageScaleMode.NO_SCALE) { this.refresh(); @@ -10794,9 +10852,9 @@ var Phaser; this.orientation = 0; } if(this.isLandscape) { - this.enterLandscape.dispatch(this.orientation); + this.enterLandscape.dispatch(this.orientation, true, false); } else { - this.enterPortrait.dispatch(this.orientation); + this.enterPortrait.dispatch(this.orientation, false, true); } if(this._game.stage.scaleMode !== StageScaleMode.NO_SCALE) { this.refresh(); @@ -10822,6 +10880,7 @@ var Phaser; this._check = window.setInterval(function () { return _this.setScreenSize(); }, 10); + this.setScreenSize(); } }; StageScaleMode.prototype.setScreenSize = /** @@ -10839,36 +10898,56 @@ var Phaser; if(window.innerHeight > this._startHeight || this._iterations < 0) { // Set minimum height of content to new window height document.documentElement.style.minHeight = window.innerHeight + 'px'; - if(this._game.stage.scaleMode == StageScaleMode.EXACT_FIT) { - if(this.maxWidth && window.innerWidth > this.maxWidth) { - this.width = this.maxWidth; - } else { - this.width = window.innerWidth; - } - if(this.maxHeight && window.innerHeight > this.maxHeight) { - this.height = this.maxHeight; - } else { - this.height = window.innerHeight; - } + if(this.incorrectOrientation == true) { + this.setMaximum(); + } else if(this._game.stage.scaleMode == StageScaleMode.EXACT_FIT) { + this.setExactFit(); } else if(this._game.stage.scaleMode == StageScaleMode.SHOW_ALL) { - var multiplier = Math.min((window.innerHeight / this._game.stage.height), (window.innerWidth / this._game.stage.width)); - this.width = Math.round(this._game.stage.width * multiplier); - this.height = Math.round(this._game.stage.height * multiplier); - if(this.maxWidth && this.width > this.maxWidth) { - this.width = this.maxWidth; - } - if(this.maxHeight && this.height > this.maxHeight) { - this.height = this.maxHeight; - } + this.setShowAll(); } - this._game.stage.canvas.style.width = this.width + 'px'; - this._game.stage.canvas.style.height = this.height + 'px'; - this._game.input.scaleX = this._game.stage.width / this.width; - this._game.input.scaleY = this._game.stage.height / this.height; clearInterval(this._check); this._check = null; } }; + StageScaleMode.prototype.setMaximum = function () { + this.width = window.innerWidth; + this.height = window.innerHeight; + this._game.stage.canvas.style.width = this.width + 'px'; + this._game.stage.canvas.style.height = this.height + 'px'; + this._game.input.scaleX = this._game.stage.width / this.width; + this._game.input.scaleY = this._game.stage.height / this.height; + }; + StageScaleMode.prototype.setShowAll = function () { + var multiplier = Math.min((window.innerHeight / this._game.stage.height), (window.innerWidth / this._game.stage.width)); + this.width = Math.round(this._game.stage.width * multiplier); + this.height = Math.round(this._game.stage.height * multiplier); + if(this.maxWidth && this.width > this.maxWidth) { + this.width = this.maxWidth; + } + if(this.maxHeight && this.height > this.maxHeight) { + this.height = this.maxHeight; + } + this._game.stage.canvas.style.width = this.width + 'px'; + this._game.stage.canvas.style.height = this.height + 'px'; + this._game.input.scaleX = this._game.stage.width / this.width; + this._game.input.scaleY = this._game.stage.height / this.height; + }; + StageScaleMode.prototype.setExactFit = function () { + if(this.maxWidth && window.innerWidth > this.maxWidth) { + this.width = this.maxWidth; + } else { + this.width = window.innerWidth; + } + if(this.maxHeight && window.innerHeight > this.maxHeight) { + this.height = this.maxHeight; + } else { + this.height = window.innerHeight; + } + this._game.stage.canvas.style.width = this.width + 'px'; + this._game.stage.canvas.style.height = this.height + 'px'; + this._game.input.scaleX = this._game.stage.width / this.width; + this._game.input.scaleY = this._game.stage.height / this.height; + }; return StageScaleMode; })(); Phaser.StageScaleMode = StageScaleMode; @@ -11081,11 +11160,60 @@ var Phaser; })(); Phaser.PauseScreen = PauseScreen; })(Phaser || (Phaser = {})); +/// +/** +* Phaser - OrientationScreen +* +* The Orientation Screen is displayed whenever the device is turned to an unsupported orientation. +*/ +var Phaser; +(function (Phaser) { + var OrientationScreen = (function () { + /** + * OrientationScreen constructor + * Create a new OrientationScreen with specific width and height. + * + * @param width {number} Screen canvas width. + * @param height {number} Screen canvas height. + */ + function OrientationScreen(game) { + this._showOnLandscape = false; + this._showOnPortrait = false; + this.game = game; + } + OrientationScreen.prototype.enable = function (onLandscape, onPortrait, imageKey) { + this._showOnLandscape = onLandscape; + this._showOnPortrait = onPortrait; + this.landscapeImage = this.game.cache.getImage(imageKey); + this.portraitImage = this.game.cache.getImage(imageKey); + }; + OrientationScreen.prototype.update = /** + * Update + */ + function () { + }; + OrientationScreen.prototype.render = /** + * Render + */ + function () { + if(this._showOnLandscape) { + this.game.stage.context.drawImage(this.landscapeImage, 0, 0, this.landscapeImage.width, this.landscapeImage.height, 0, 0, this.game.stage.width, this.game.stage.height); + } else if(this._showOnPortrait) { + this.game.stage.context.drawImage(this.portraitImage, 0, 0, this.portraitImage.width, this.portraitImage.height, 0, 0, this.game.stage.width, this.game.stage.height); + } + //this.game.stage.context.font = '32px Arial'; + //this.game.stage.context.fillText('w: ' + this.game.stage.width + ' h: ' + this.game.stage.height, 32, 32); + }; + return OrientationScreen; + })(); + Phaser.OrientationScreen = OrientationScreen; +})(Phaser || (Phaser = {})); /// /// /// /// /// +/// /** * Phaser - Stage * @@ -11107,10 +11235,10 @@ var Phaser; function Stage(game, parent, width, height) { var _this = this; /** - * Background color of the stage (defaults to black) + * Background color of the stage (defaults to black). Set via the public backgroundColor property. * @type {string} */ - this._bgColor = 'rgb(0,0,0)'; + this._backgroundColor = 'rgb(0,0,0)'; /** * Clear the whole stage every frame? (Default to true) * @type {boolean} @@ -11169,9 +11297,12 @@ var Phaser; * Stage boot */ function () { - this._bootScreen = new Phaser.BootScreen(this._game); - this._pauseScreen = new Phaser.PauseScreen(this._game, this.width, this.height); - }; + this.bootScreen = new Phaser.BootScreen(this._game); + this.pauseScreen = new Phaser.PauseScreen(this._game, this.width, this.height); + this.orientationScreen = new Phaser.OrientationScreen(this._game); + //this.scale.enterLandscape.add(this.orientationChange, this); + //this.scale.enterPortrait.add(this.orientationChange, this); + }; Stage.prototype.update = /** * Update stage for rendering. This will handle scaling, clearing * and PauseScreen/BootScreen updating and rendering. @@ -11182,13 +11313,18 @@ var Phaser; // implement dirty rect? could take up more cpu time than it saves. needs benching. this.context.clearRect(0, 0, this.width, this.height); } - if(this._game.isRunning == false && this.disableBootScreen == false) { - this._bootScreen.update(); - this._bootScreen.render(); + if(this._game.paused && this.scale.incorrectOrientation) { + this.orientationScreen.update(); + this.orientationScreen.render(); + return; } - if(this._game.paused == true && this.disablePauseScreen == false) { - this._pauseScreen.update(); - this._pauseScreen.render(); + if(this._game.isRunning == false && this.disableBootScreen == false) { + this.bootScreen.update(); + this.bootScreen.render(); + } + if(this._game.paused && this.disablePauseScreen == false) { + this.pauseScreen.update(); + this.pauseScreen.render(); } }; Stage.prototype.visibilityChange = /** @@ -11208,13 +11344,52 @@ var Phaser; } } }; + Stage.prototype.enableOrientationCheck = /** + * This method is called when the device orientation changes. + */ + /* + private orientationChange(format: number, landscape: bool, portrait: bool) { + + if (this.scale.forceLandscape && portrait) + { + this._game.paused = true; + this.scale.incorrectOrientation = true; + } + else if (this.scale.forcePortrait && landscape) + { + this._game.paused = true; + this.scale.incorrectOrientation = true; + } + else if ((this.scale.forceLandscape && landscape) || (this.scale.forcePortrait && portrait)) + { + this._game.paused = false; + this.scale.incorrectOrientation = false; + } + + } + */ + function (forceLandscape, forcePortrait, imageKey) { + if (typeof imageKey === "undefined") { imageKey = ''; } + this.scale.forceLandscape = forceLandscape; + this.scale.forcePortrait = forcePortrait; + this.orientationScreen.enable(forceLandscape, forcePortrait, imageKey); + if(forceLandscape || forcePortrait) { + if((this.scale.isLandscape && forcePortrait) || (this.scale.isPortrait && forceLandscape)) { + // They are in the wrong orientation right now + this._game.paused = true; + this.scale.incorrectOrientation = true; + } else { + this.scale.incorrectOrientation = false; + } + } + }; Stage.prototype.pauseGame = function () { - this._pauseScreen.onPaused(); + this.pauseScreen.onPaused(); this.saveCanvasValues(); this._game.paused = true; }; Stage.prototype.resumeGame = function () { - this._pauseScreen.onResume(); + this.pauseScreen.onResume(); this.restoreCanvasValues(); this._game.paused = false; }; @@ -11247,10 +11422,11 @@ var Phaser; }; Object.defineProperty(Stage.prototype, "backgroundColor", { get: function () { - return this._bgColor; + return this._backgroundColor; }, set: function (color) { this.canvas.style.backgroundColor = color; + this._backgroundColor = color; }, enumerable: true, configurable: true @@ -13963,6 +14139,12 @@ var Phaser; * @type {Number} **/ this.totalTouches = 0; + /** + * The Game Object this Pointer is currently over / touching / dragging. + * @property targetObject + * @type {Any} + **/ + this.targetObject = null; this.game = game; this.id = id; this.active = false; @@ -14004,6 +14186,28 @@ var Phaser; if (typeof camera === "undefined") { camera = this.game.camera; } return camera.worldView.y + this.y; }; + Object.defineProperty(Pointer.prototype, "scaledX", { + get: /** + * Gets the X value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + function () { + return Math.floor(this.x * this.game.input.scaleX); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Pointer.prototype, "scaledY", { + get: /** + * Gets the Y value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + function () { + return Math.floor(this.y * this.game.input.scaleY); + }, + enumerable: true, + configurable: true + }); Pointer.prototype.start = /** * Called when the Pointer is pressed onto the touchscreen * @method start @@ -14021,14 +14225,14 @@ var Phaser; return this; } this._history.length = 0; - this.move(event); - this.positionDown.setTo(this.x, this.y); this.active = true; this.withinGame = true; this.isDown = true; this.isUp = false; this.timeDown = this.game.time.now; this._holdSent = false; + this.positionDown.setTo(this.x, this.y); + this.move(event); if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { this.game.input.x = this.x * this.game.input.scaleX; this.game.input.y = this.y * this.game.input.scaleY; @@ -14039,6 +14243,31 @@ var Phaser; if(this.isMouse == false) { this.game.input.currentPointers++; } + // Build our temporary click stack + /* + var _highestPriority = 0; + var _highestRenderID = 0; + var _highestRenderObject: number = -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) + { + _highestRenderID = this.game.input.inputObjects[i].renderOrderID; + _highestRenderObject = i; + } + } + + if (_highestRenderObject !== -1 && this._stateReset == false) + { + this.targetObject = this.game.input.inputObjects[_highestRenderObject]; + this.targetObject.input._touchedHandler(this); + //_highestRenderObject.input._touchedHandler(this); + } + */ + if(this.targetObject !== null) { + this.targetObject.input._touchedHandler(this); + } return this; }; Pointer.prototype.update = function () { @@ -14062,25 +14291,47 @@ var Phaser; } // Iterate through the tracked objects // Build our temporary click stack + /* var _highestPriority = 0; - for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.enabled) { - if(this.game.input.inputObjects[i].input.update(this) && this.game.input.inputObjects[i].input.priorityID > _highestPriority) { - _highestPriority = this.game.input.inputObjects[i].input.priorityID; - } - } + var _highestRenderID = 0; + var _highestRenderObject = null; + + for (var i = 0; i < this.game.input.totalTrackedObjects; i++) + { + if (this.game.input.inputObjects[i].input.enabled) + { + //if (this.game.input.inputObjects[i].input.update(this) && this.game.input.inputObjects[i].input.priorityID > _highestPriority) + if (this.game.input.inputObjects[i].input.update(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) + { + _highestRenderID = this.game.input.inputObjects[i].renderOrderID; + _highestRenderObject = this.game.input.inputObjects[i]; } - if(this.isDown && this._stateReset == false) { - // Now update all objects with the highest priority ID (can be more than 1) - for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.priorityID == _highestPriority) { - if(this.game.input.inputObjects[i].input._touchedHandler(this) == false) { - return; + } + } + + if (_highestRenderObject !== null) + { + _highestRenderObject.input._pointerOverHandler(this); + + if (this.isDown && this._stateReset == false) + { + _highestRenderObject.input._touchedHandler(this); + } + + // Now update all objects with the highest priority ID (can be more than 1) + //for (var i = 0; i < this.game.input.totalTrackedObjects; i++) + //{ + // if (this.game.input.inputObjects[i].input.priorityID == _highestPriority) + // { + // if (this.game.input.inputObjects[i].input._touchedHandler(this) == false) + // { + // return; + // } + // } + //} + } + */ } - } - } - } - } }; Pointer.prototype.move = /** * Called when the Pointer is moved on the touchscreen @@ -14109,6 +14360,27 @@ var Phaser; this.game.input.circle.x = this.game.input.x; this.game.input.circle.y = this.game.input.y; } + if(this.targetObject !== null) { + if(this.targetObject.input.update(this) == false) { + this.targetObject = null; + } + } else { + // Build our temporary click stack + var _highestRenderID = 0; + 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) { + _highestRenderID = this.game.input.inputObjects[i].renderOrderID; + _highestRenderObject = i; + } + } + //console.log('pointer move', _highestRenderID); + if(_highestRenderObject !== -1) { + //console.log('setting target'); + this.targetObject = this.game.input.inputObjects[_highestRenderObject]; + this.targetObject.input._pointerOverHandler(this); + } + } return this; }; Pointer.prototype.leave = /** @@ -14161,7 +14433,10 @@ var Phaser; this.game.input.inputObjects[i].input._releasedHandler(this); } } - this.draggedObject = null; + if(this.targetObject) { + this.targetObject.input._releasedHandler(this); + } + this.targetObject = null; return this; }; Pointer.prototype.justPressed = /** @@ -14207,6 +14482,7 @@ var Phaser; this._holdSent = false; this._history.length = 0; this._stateReset = true; + this.targetObject = null; }; Pointer.prototype.renderDebug = /** * Renders the Pointer.circle object onto the stage in green if down or red if up. @@ -14402,7 +14678,11 @@ var Phaser; * @type {Boolean} */ this.disabled = false; + this.mouseDownCallback = null; + this.mouseMoveCallback = null; + this.mouseUpCallback = null; this._game = game; + this.callbackContext = this._game; } Mouse.LEFT_BUTTON = 0; Mouse.MIDDLE_BUTTON = 1; @@ -14427,6 +14707,9 @@ var Phaser; * @param {MouseEvent} event */ function (event) { + if(this.mouseDownCallback) { + this.mouseDownCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14437,6 +14720,9 @@ var Phaser; * @param {MouseEvent} event */ function (event) { + if(this.mouseMoveCallback) { + this.mouseMoveCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14447,6 +14733,9 @@ var Phaser; * @param {MouseEvent} event */ function (event) { + if(this.mouseUpCallback) { + this.mouseUpCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14735,7 +15024,14 @@ var Phaser; * @type {Boolean} */ this.disabled = false; + this.touchStartCallback = null; + this.touchMoveCallback = null; + this.touchEndCallback = null; + this.touchEnterCallback = null; + this.touchLeaveCallback = null; + this.touchCancelCallback = null; this._game = game; + this.callbackContext = this._game; } Touch.prototype.start = /** * Starts the event listeners running @@ -14781,6 +15077,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchStartCallback) { + this.touchStartCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14799,6 +15098,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchCancelCallback) { + this.touchCancelCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14816,6 +15118,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchEnterCallback) { + this.touchEnterCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14831,6 +15136,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchLeaveCallback) { + this.touchLeaveCallback.call(this.callbackContext, event); + } event.preventDefault(); for(var i = 0; i < event.changedTouches.length; i++) { console.log('touch leave'); @@ -14842,6 +15150,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchMoveCallback) { + this.touchMoveCallback.call(this.callbackContext, event); + } event.preventDefault(); for(var i = 0; i < event.changedTouches.length; i++) { this._game.input.updatePointer(event.changedTouches[i]); @@ -14853,6 +15164,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchEndCallback) { + this.touchEndCallback.call(this.callbackContext, event); + } event.preventDefault(); // For touch end its a list of the touch points that have been removed from the surface // https://developer.mozilla.org/en-US/docs/DOM/TouchList @@ -15463,7 +15777,7 @@ var Phaser; */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._game.stage.context.font = '14px Courier'; + this._game.stage.context.font = '24px Courier'; this._game.stage.context.fillStyle = color; this._game.stage.context.fillText('Input', x, y); this._game.stage.context.fillText('Screen X: ' + this.x + ' Screen Y: ' + this.y, x, y + 14); @@ -15639,6 +15953,7 @@ var Phaser; if(sprite.scale.x == 0 || sprite.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { return false; } + sprite.renderOrderID = this._count; this._count++; // Reset our temp vars this._ga = -1; diff --git a/build/phaser.d.ts b/build/phaser.d.ts index bcbdc138..3efb98df 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -3619,10 +3619,13 @@ module Phaser.Components { public start(priority?: number, checkBody?: bool, useHandCursor?: bool): Sprite; public reset(): void; public stop(): void; + public checkPointerOver(pointer: Pointer): bool; /** * Update */ public update(pointer: Pointer): bool; + public _pointerOverHandler(pointer: Pointer): void; + public _pointOutHandler(pointer: Pointer): void; public consumePointerEvent: bool; public _touchedHandler(pointer: Pointer): bool; public _releasedHandler(pointer: Pointer): void; @@ -4139,6 +4142,10 @@ module Phaser { */ public z: number; /** + * Render iteration + */ + public renderOrderID: number; + /** * This value is added to the angle of the Sprite. * For example if you had a sprite graphic drawn facing straight up then you could set * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. @@ -6077,6 +6084,21 @@ module Phaser { */ static SHOW_ALL: number; /** + * If the game should be forced to use Landscape mode, this is set to true by Game.Stage + * @type {Boolean} + */ + public forceLandscape: bool; + /** + * If the game should be forced to use Portrait mode, this is set to true by Game.Stage + * @type {Boolean} + */ + public forcePortrait: bool; + /** + * If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true. + * @type {Boolean} + */ + public incorrectOrientation: bool; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} */ @@ -6109,17 +6131,27 @@ module Phaser { */ public height: number; /** - * Window orientation angle (90 and -90 are landscape, 0 is portrait) + * Asperct ratio of the scaled game size (width / height) + * @type {number} + */ + public aspectRatio: number; + /** + * The scale factor of the scaled game width + * @type {Vec2} + */ + public scaleFactor: Vec2; + /** + * Window orientation angle (90 and -90 are landscape, 0 and 80 are portrait) * @type {number} */ public orientation: number; /** - * A Signal that is dispatched when the device enters landscape mode from portrait + * A Signal that is dispatched when the device enters landscape orientation from portrait * @type {Signal} */ public enterLandscape: Signal; /** - * A Signal that is dispatched when the device enters portrait mode from landscape + * A Signal that is dispatched when the device enters portrait orientation from landscape * @type {Signal} */ public enterPortrait: Signal; @@ -6130,6 +6162,7 @@ module Phaser { * The core update loop, called by Phaser.Stage */ public update(): void; + private checkOrientationState(); public isPortrait : bool; public isLandscape : bool; /** @@ -6148,6 +6181,10 @@ module Phaser { * Set screen size automatically based on the scaleMode. */ private setScreenSize(); + private setSize(); + private setMaximum(); + private setShowAll(); + private setExactFit(); } } /** @@ -6269,6 +6306,50 @@ module Phaser { } } /** +* Phaser - OrientationScreen +* +* The Orientation Screen is displayed whenever the device is turned to an unsupported orientation. +*/ +module Phaser { + class OrientationScreen { + /** + * OrientationScreen constructor + * Create a new OrientationScreen with specific width and height. + * + * @param width {number} Screen canvas width. + * @param height {number} Screen canvas height. + */ + constructor(game: Game); + /** + * Local reference to game. + */ + public game: Game; + private _showOnLandscape; + private _showOnPortrait; + /** + * Landscape Image. If you only want your game to work in Portrait mode, and display an image when in Landscape, + * then set this to be the key of an image previously loaded into the Game.Cache. + * @type {Cache Reference} + */ + public landscapeImage; + /** + * Portrait Image. If you only want your game to work in Landscape mode, and display an image when in Portrait, + * then set this to be the key of an image previously loaded into the Game.Cache. + * @type {Cache Reference} + */ + public portraitImage; + public enable(onLandscape: bool, onPortrait: bool, imageKey: string): void; + /** + * Update + */ + public update(): void; + /** + * Render + */ + public render(): void; + } +} +/** * Phaser - Stage * * The Stage is the canvas on which everything is displayed. This class handles display within the web browser, focus handling, @@ -6291,20 +6372,25 @@ module Phaser { */ private _game; /** - * Background color of the stage (defaults to black) + * Background color of the stage (defaults to black). Set via the public backgroundColor property. * @type {string} */ - private _bgColor; + private _backgroundColor; /** * This will be displayed when Phaser is started without any default functions or State * @type {BootScreen} */ - private _bootScreen; + public bootScreen; /** * This will be displayed whenever the game loses focus or the player switches to another browser tab. * @type {PauseScreen} */ - private _pauseScreen; + public pauseScreen; + /** + * This will be displayed whenever the device is turned to an unsupported orientation. + * @type {OrientationScreen} + */ + public orientationScreen; /** * Bound of this stage. * @type {Rectangle} @@ -6371,12 +6457,13 @@ module Phaser { * This method is called when the canvas elements visibility is changed. */ private visibilityChange(event); + public enableOrientationCheck(forceLandscape: bool, forcePortrait: bool, imageKey?: string): void; public pauseGame(): void; public resumeGame(): void; /** * Get the DOM offset values of the given element */ - private getOffset(element); + public getOffset(element, populateOffset?: bool): Point; /** * Canvas strokeStyle. * @type {string} @@ -7536,11 +7623,11 @@ module Phaser { **/ public duration : number; /** - * The Game Object this Pointer is currently dragging. - * @property draggedObject + * The Game Object this Pointer is currently over / touching / dragging. + * @property targetObject * @type {Any} **/ - public draggedObject; + public targetObject; /** * Gets the X value of this Pointer in world coordinate space * @param {Camera} [camera] @@ -7552,6 +7639,16 @@ module Phaser { */ public getWorldY(camera?: Camera): number; /** + * Gets the X value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + public scaledX : number; + /** + * Gets the Y value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + public scaledY : number; + /** * Called when the Pointer is pressed onto the touchscreen * @method start * @param {Any} event @@ -7723,6 +7820,14 @@ module Phaser { */ public disabled: bool; /** + * Custom callback useful for hooking into a 3rd party library. Will be passed the mouse event as the only parameter. + * Callbacks are fired even if this component is disabled and before the event propagation is disabled. + */ + public callbackContext; + public mouseDownCallback; + public mouseMoveCallback; + public mouseUpCallback; + /** * Starts the event listeners running * @method start */ @@ -7934,6 +8039,17 @@ module Phaser { */ public disabled: bool; /** + * Custom callback useful for hooking into a 3rd party library. Will be passed the touch event as the only parameter. + * Callbacks are fired even if this component is disabled and before the event propogation is disabled. + */ + public callbackContext; + public touchStartCallback; + public touchMoveCallback; + public touchEndCallback; + public touchEnterCallback; + public touchLeaveCallback; + public touchCancelCallback; + /** * Starts the event listeners running * @method start */ diff --git a/build/phaser.js b/build/phaser.js index 49912f67..1258d308 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -4357,7 +4357,7 @@ var Phaser; * Either cw or ccw, rotation is always 90 degrees. */ this.rotationDirection = 'cw'; - console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); + //console.log('Creating Frame', name, 'x', x, 'y', y, 'width', width, 'height', height); this.x = x; this.y = y; this.width = width; @@ -6267,6 +6267,13 @@ var Phaser; this.game.input.removeGameObject(this._sprite); } }; + Input.prototype.checkPointerOver = function (pointer) { + if(this.enabled == false || this._sprite.visible == false) { + return false; + } else { + return Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY); + } + }; Input.prototype.update = /** * Update */ @@ -6275,44 +6282,52 @@ var Phaser; return false; } if(this.draggable && this._draggedPointerID == pointer.id) { - this.updateDrag(pointer); - } - if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.x, pointer.y)) { - // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } - this._pointerData[pointer.id].x = pointer.x - this._sprite.x; - this._pointerData[pointer.id].y = pointer.y - this._sprite.y; - if(this._pointerData[pointer.id].isOver == false) { - this._pointerData[pointer.id].isOver = true; - this._pointerData[pointer.id].isOut = false; - this._pointerData[pointer.id].timeOver = this.game.time.now; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "pointer"; - } - this._sprite.events.onInputOver.dispatch(this._sprite, pointer); + return this.updateDrag(pointer); + } else if(this._pointerData[pointer.id].isOver == true) { + if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, pointer.scaledX, pointer.scaledY)) { + this._pointerData[pointer.id].x = pointer.scaledX - this._sprite.x; + this._pointerData[pointer.id].y = pointer.scaledY - this._sprite.y; + return true; + } else { + this._pointOutHandler(pointer); + return false; } - return true; - } else { - if(this._pointerData[pointer.id].isOver) { - this._pointerData[pointer.id].isOver = false; - this._pointerData[pointer.id].isOut = true; - this._pointerData[pointer.id].timeOut = this.game.time.now; - if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { - this.game.stage.canvas.style.cursor = "default"; - } - this._sprite.events.onInputOut.dispatch(this._sprite, pointer); - } - return false; } }; + Input.prototype._pointerOverHandler = function (pointer) { + // { id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, isDragged: false } + if(this._pointerData[pointer.id].isOver == false) { + 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; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "pointer"; + } + this._sprite.events.onInputOver.dispatch(this._sprite, pointer); + } + }; + Input.prototype._pointOutHandler = function (pointer) { + this._pointerData[pointer.id].isOver = false; + this._pointerData[pointer.id].isOut = true; + this._pointerData[pointer.id].timeOut = this.game.time.now; + if(this.useHandCursor && this._pointerData[pointer.id].isDragged == false) { + this.game.stage.canvas.style.cursor = "default"; + } + this._sprite.events.onInputOut.dispatch(this._sprite, pointer); + }; Input.prototype._touchedHandler = function (pointer) { + console.log('touched handler', this._pointerData[pointer.id]); if(this._pointerData[pointer.id].isDown == false && this._pointerData[pointer.id].isOver == true) { - console.log('touchDown on', this._sprite.texture.cacheKey, this._sprite.frameBounds.width, this._sprite.frameBounds.height); + //console.log('touchDown on', this._sprite.texture.cacheKey,this._sprite.frameName, this._sprite.frameBounds.width,this._sprite.frameBounds.height); this._pointerData[pointer.id].isDown = true; this._pointerData[pointer.id].isUp = false; this._pointerData[pointer.id].timeDown = this.game.time.now; this._sprite.events.onInputDown.dispatch(this._sprite, pointer); // Start drag - if(this.draggable && this.isDragged == false && pointer.draggedObject == null) { + //if (this.draggable && this.isDragged == false && pointer.targetObject == null) + if(this.draggable && this.isDragged == false) { this.startDrag(pointer); } } @@ -6320,6 +6335,7 @@ var Phaser; return this.consumePointerEvent; }; Input.prototype._releasedHandler = function (pointer) { + console.log('release handler'); // If was previously touched by this Pointer, check if still is if(this._pointerData[pointer.id].isDown && pointer.isUp) { this._pointerData[pointer.id].isDown = false; @@ -6342,7 +6358,7 @@ var Phaser; function (pointer) { if(pointer.isUp) { this.stopDrag(pointer); - return; + return false; } if(this.allowHorizontalDrag) { this._sprite.x = pointer.x + this._dragPoint.x + this.dragOffset.x; @@ -6360,6 +6376,7 @@ var Phaser; this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; } + return true; }; Input.prototype.justOver = /** * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) @@ -6477,8 +6494,8 @@ var Phaser; } else { this._dragPoint.setTo(this._sprite.x - pointer.x, this._sprite.y - pointer.y); } - pointer.draggedObject = this._sprite; - }; + //pointer.draggedObject = this._sprite; + }; Input.prototype.stopDrag = /** * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. */ @@ -6490,8 +6507,8 @@ var Phaser; this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; } - pointer.draggedObject = null; - }; + //pointer.draggedObject = null; + }; Input.prototype.setDragLock = /** * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! * @@ -6566,13 +6583,13 @@ var Phaser; */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._sprite.texture.context.font = '14px Courier'; + this._sprite.texture.context.font = '16px Courier'; this._sprite.texture.context.fillStyle = color; this._sprite.texture.context.fillText('Sprite Input: (' + this._sprite.frameBounds.width + ' x ' + this._sprite.frameBounds.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._sprite.texture.context.fillText('x: ' + this.pointerX(1).toFixed(1) + ' y: ' + this.pointerY(1).toFixed(1), x, y + 14); + this._sprite.texture.context.fillText('over: ' + this.pointerOver(1) + ' duration: ' + this.overDuration(1).toFixed(0), x, y + 28); + this._sprite.texture.context.fillText('down: ' + this.pointerDown(1) + ' duration: ' + this.downDuration(1).toFixed(0), x, y + 42); + this._sprite.texture.context.fillText('just over: ' + this.justOver(1) + ' just out: ' + this.justOut(1), x, y + 56); }; return Input; })(); @@ -7148,6 +7165,10 @@ var Phaser; */ this.z = 0; /** + * Render iteration + */ + this.renderOrderID = 0; + /** * This value is added to the angle of the Sprite. * For example if you had a sprite graphic drawn facing straight up then you could set * angleOffset to 90 and it would correspond correctly with Phasers right-handed coordinate system. @@ -10663,6 +10684,21 @@ var Phaser; */ this._startHeight = 0; /** + * If the game should be forced to use Landscape mode, this is set to true by Game.Stage + * @type {Boolean} + */ + this.forceLandscape = false; + /** + * If the game should be forced to use Portrait mode, this is set to true by Game.Stage + * @type {Boolean} + */ + this.forcePortrait = false; + /** + * If the game should be forced to use a specific orientation and the device currently isn't in that orientation this is set to true. + * @type {Boolean} + */ + this.incorrectOrientation = false; + /** * Minimum width the canvas should be scaled to (in pixels) * @type {number} */ @@ -10706,6 +10742,8 @@ var Phaser; this.orientation = 0; } } + this.scaleFactor = new Phaser.Vec2(1, 1); + this.aspectRatio = 0; window.addEventListener('orientationchange', function (event) { return _this.checkOrientation(event); }, false); @@ -10717,7 +10755,8 @@ var Phaser; StageScaleMode.NO_SCALE = 1; StageScaleMode.SHOW_ALL = 2; Object.defineProperty(StageScaleMode.prototype, "isFullScreen", { - get: function () { + get: // Full Screen API calls + function () { if(document['fullscreenElement'] === null || document['mozFullScreenElement'] === null || document['webkitFullscreenElement'] === null) { return false; } @@ -10755,10 +10794,31 @@ var Phaser; if(this._game.stage.scaleMode !== StageScaleMode.NO_SCALE && (window.innerWidth !== this.width || window.innerHeight !== this.height)) { this.refresh(); } + if(this.forceLandscape || this.forcePortrait) { + this.checkOrientationState(); + } + }; + StageScaleMode.prototype.checkOrientationState = function () { + // They are in the wrong orientation + if(this.incorrectOrientation) { + if((this.forceLandscape && window.innerWidth > window.innerHeight) || (this.forcePortrait && window.innerHeight > window.innerWidth)) { + // Back to normal + this._game.paused = false; + this.incorrectOrientation = false; + this.refresh(); + } + } else { + if((this.forceLandscape && window.innerWidth < window.innerHeight) || (this.forcePortrait && window.innerHeight < window.innerWidth)) { + // Show orientation screen + this._game.paused = true; + this.incorrectOrientation = true; + this.refresh(); + } + } }; Object.defineProperty(StageScaleMode.prototype, "isPortrait", { get: function () { - return this.orientation == 0; + return this.orientation == 0 || this.orientation == 180; }, enumerable: true, configurable: true @@ -10776,9 +10836,9 @@ var Phaser; function (event) { this.orientation = window['orientation']; if(this.isLandscape) { - this.enterLandscape.dispatch(this.orientation); + this.enterLandscape.dispatch(this.orientation, true, false); } else { - this.enterPortrait.dispatch(this.orientation); + this.enterPortrait.dispatch(this.orientation, false, true); } if(this._game.stage.scaleMode !== StageScaleMode.NO_SCALE) { this.refresh(); @@ -10794,9 +10854,9 @@ var Phaser; this.orientation = 0; } if(this.isLandscape) { - this.enterLandscape.dispatch(this.orientation); + this.enterLandscape.dispatch(this.orientation, true, false); } else { - this.enterPortrait.dispatch(this.orientation); + this.enterPortrait.dispatch(this.orientation, false, true); } if(this._game.stage.scaleMode !== StageScaleMode.NO_SCALE) { this.refresh(); @@ -10822,6 +10882,7 @@ var Phaser; this._check = window.setInterval(function () { return _this.setScreenSize(); }, 10); + this.setScreenSize(); } }; StageScaleMode.prototype.setScreenSize = /** @@ -10839,36 +10900,63 @@ var Phaser; if(window.innerHeight > this._startHeight || this._iterations < 0) { // Set minimum height of content to new window height document.documentElement.style.minHeight = window.innerHeight + 'px'; - if(this._game.stage.scaleMode == StageScaleMode.EXACT_FIT) { - if(this.maxWidth && window.innerWidth > this.maxWidth) { - this.width = this.maxWidth; - } else { - this.width = window.innerWidth; - } - if(this.maxHeight && window.innerHeight > this.maxHeight) { - this.height = this.maxHeight; - } else { - this.height = window.innerHeight; - } + if(this.incorrectOrientation == true) { + this.setMaximum(); + } else if(this._game.stage.scaleMode == StageScaleMode.EXACT_FIT) { + this.setExactFit(); } else if(this._game.stage.scaleMode == StageScaleMode.SHOW_ALL) { - var multiplier = Math.min((window.innerHeight / this._game.stage.height), (window.innerWidth / this._game.stage.width)); - this.width = Math.round(this._game.stage.width * multiplier); - this.height = Math.round(this._game.stage.height * multiplier); - if(this.maxWidth && this.width > this.maxWidth) { - this.width = this.maxWidth; - } - if(this.maxHeight && this.height > this.maxHeight) { - this.height = this.maxHeight; - } + this.setShowAll(); } - this._game.stage.canvas.style.width = this.width + 'px'; - this._game.stage.canvas.style.height = this.height + 'px'; - this._game.input.scaleX = this._game.stage.width / this.width; - this._game.input.scaleY = this._game.stage.height / this.height; + this.setSize(); clearInterval(this._check); this._check = null; } }; + StageScaleMode.prototype.setSize = function () { + if(this.maxWidth && this.width > this.maxWidth) { + this.width = this.maxWidth; + } + if(this.maxHeight && this.height > this.maxHeight) { + this.height = this.maxHeight; + } + if(this.minWidth && this.width < this.minWidth) { + this.width = this.minWidth; + } + if(this.minHeight && this.height < this.minHeight) { + this.height = this.minHeight; + } + this._game.stage.canvas.style.width = this.width + 'px'; + this._game.stage.canvas.style.height = this.height + 'px'; + this._game.input.scaleX = this._game.stage.width / this.width; + this._game.input.scaleY = this._game.stage.height / this.height; + this._game.stage.getOffset(this._game.stage.canvas); + this.aspectRatio = this.width / this.height; + this.scaleFactor.x = this._game.stage.width / this.width; + this.scaleFactor.y = this._game.stage.height / this.height; + //this.scaleFactor.x = this.width / this._game.stage.width; + //this.scaleFactor.y = this.height / this._game.stage.height; + }; + StageScaleMode.prototype.setMaximum = function () { + this.width = window.innerWidth; + this.height = window.innerHeight; + }; + StageScaleMode.prototype.setShowAll = function () { + var multiplier = Math.min((window.innerHeight / this._game.stage.height), (window.innerWidth / this._game.stage.width)); + this.width = Math.round(this._game.stage.width * multiplier); + this.height = Math.round(this._game.stage.height * multiplier); + }; + StageScaleMode.prototype.setExactFit = function () { + if(this.maxWidth && window.innerWidth > this.maxWidth) { + this.width = this.maxWidth; + } else { + this.width = window.innerWidth; + } + if(this.maxHeight && window.innerHeight > this.maxHeight) { + this.height = this.maxHeight; + } else { + this.height = window.innerHeight; + } + }; return StageScaleMode; })(); Phaser.StageScaleMode = StageScaleMode; @@ -11081,11 +11169,58 @@ var Phaser; })(); Phaser.PauseScreen = PauseScreen; })(Phaser || (Phaser = {})); +/// +/** +* Phaser - OrientationScreen +* +* The Orientation Screen is displayed whenever the device is turned to an unsupported orientation. +*/ +var Phaser; +(function (Phaser) { + var OrientationScreen = (function () { + /** + * OrientationScreen constructor + * Create a new OrientationScreen with specific width and height. + * + * @param width {number} Screen canvas width. + * @param height {number} Screen canvas height. + */ + function OrientationScreen(game) { + this._showOnLandscape = false; + this._showOnPortrait = false; + this.game = game; + } + OrientationScreen.prototype.enable = function (onLandscape, onPortrait, imageKey) { + this._showOnLandscape = onLandscape; + this._showOnPortrait = onPortrait; + this.landscapeImage = this.game.cache.getImage(imageKey); + this.portraitImage = this.game.cache.getImage(imageKey); + }; + OrientationScreen.prototype.update = /** + * Update + */ + function () { + }; + OrientationScreen.prototype.render = /** + * Render + */ + function () { + if(this._showOnLandscape) { + this.game.stage.context.drawImage(this.landscapeImage, 0, 0, this.landscapeImage.width, this.landscapeImage.height, 0, 0, this.game.stage.width, this.game.stage.height); + } else if(this._showOnPortrait) { + this.game.stage.context.drawImage(this.portraitImage, 0, 0, this.portraitImage.width, this.portraitImage.height, 0, 0, this.game.stage.width, this.game.stage.height); + } + }; + return OrientationScreen; + })(); + Phaser.OrientationScreen = OrientationScreen; +})(Phaser || (Phaser = {})); /// /// /// /// /// +/// /** * Phaser - Stage * @@ -11107,10 +11242,10 @@ var Phaser; function Stage(game, parent, width, height) { var _this = this; /** - * Background color of the stage (defaults to black) + * Background color of the stage (defaults to black). Set via the public backgroundColor property. * @type {string} */ - this._bgColor = 'rgb(0,0,0)'; + this._backgroundColor = 'rgb(0,0,0)'; /** * Clear the whole stage every frame? (Default to true) * @type {boolean} @@ -11132,7 +11267,7 @@ var Phaser; this.canvas = document.createElement('canvas'); this.canvas.width = width; this.canvas.height = height; - if(document.getElementById(parent)) { + if((parent !== '' || parent !== null) && document.getElementById(parent)) { document.getElementById(parent).appendChild(this.canvas); document.getElementById(parent).style.overflow = 'hidden'; } else { @@ -11147,11 +11282,11 @@ var Phaser; event.preventDefault(); }; this.context = this.canvas.getContext('2d'); - this.offset = this.getOffset(this.canvas); - this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, width, height); - this.aspectRatio = width / height; this.scaleMode = Phaser.StageScaleMode.NO_SCALE; this.scale = new Phaser.StageScaleMode(this._game); + this.getOffset(this.canvas); + this.bounds = new Phaser.Rectangle(this.offset.x, this.offset.y, width, height); + this.aspectRatio = width / height; document.addEventListener('visibilitychange', function (event) { return _this.visibilityChange(event); }, false); @@ -11169,8 +11304,9 @@ var Phaser; * Stage boot */ function () { - this._bootScreen = new Phaser.BootScreen(this._game); - this._pauseScreen = new Phaser.PauseScreen(this._game, this.width, this.height); + this.bootScreen = new Phaser.BootScreen(this._game); + this.pauseScreen = new Phaser.PauseScreen(this._game, this.width, this.height); + this.orientationScreen = new Phaser.OrientationScreen(this._game); }; Stage.prototype.update = /** * Update stage for rendering. This will handle scaling, clearing @@ -11182,13 +11318,18 @@ var Phaser; // implement dirty rect? could take up more cpu time than it saves. needs benching. this.context.clearRect(0, 0, this.width, this.height); } - if(this._game.isRunning == false && this.disableBootScreen == false) { - this._bootScreen.update(); - this._bootScreen.render(); + if(this._game.paused && this.scale.incorrectOrientation) { + this.orientationScreen.update(); + this.orientationScreen.render(); + return; } - if(this._game.paused == true && this.disablePauseScreen == false) { - this._pauseScreen.update(); - this._pauseScreen.render(); + if(this._game.isRunning == false && this.disableBootScreen == false) { + this.bootScreen.update(); + this.bootScreen.render(); + } + if(this._game.paused && this.disablePauseScreen == false) { + this.pauseScreen.update(); + this.pauseScreen.render(); } }; Stage.prototype.visibilityChange = /** @@ -11208,26 +11349,51 @@ var Phaser; } } }; + Stage.prototype.enableOrientationCheck = function (forceLandscape, forcePortrait, imageKey) { + if (typeof imageKey === "undefined") { imageKey = ''; } + this.scale.forceLandscape = forceLandscape; + this.scale.forcePortrait = forcePortrait; + this.orientationScreen.enable(forceLandscape, forcePortrait, imageKey); + if(forceLandscape || forcePortrait) { + if((this.scale.isLandscape && forcePortrait) || (this.scale.isPortrait && forceLandscape)) { + // They are in the wrong orientation right now + this._game.paused = true; + this.scale.incorrectOrientation = true; + } else { + this.scale.incorrectOrientation = false; + } + } + }; Stage.prototype.pauseGame = function () { - this._pauseScreen.onPaused(); + if(this.disablePauseScreen == false) { + this.pauseScreen.onPaused(); + } this.saveCanvasValues(); this._game.paused = true; }; Stage.prototype.resumeGame = function () { - this._pauseScreen.onResume(); + if(this.disablePauseScreen == false) { + this.pauseScreen.onResume(); + } this.restoreCanvasValues(); this._game.paused = false; }; Stage.prototype.getOffset = /** * Get the DOM offset values of the given element */ - function (element) { + function (element, populateOffset) { + if (typeof populateOffset === "undefined") { populateOffset = true; } var box = element.getBoundingClientRect(); var clientTop = element.clientTop || document.body.clientTop || 0; var clientLeft = element.clientLeft || document.body.clientLeft || 0; var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop; var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft; - return new Phaser.Point(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop); + if(populateOffset) { + this.offset = new Phaser.Point(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop); + return this.offset; + } else { + return new Phaser.Point(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop); + } }; Stage.prototype.saveCanvasValues = /** * Save current canvas properties (strokeStyle, lineWidth and fillStyle) for later using. @@ -11247,10 +11413,11 @@ var Phaser; }; Object.defineProperty(Stage.prototype, "backgroundColor", { get: function () { - return this._bgColor; + return this._backgroundColor; }, set: function (color) { this.canvas.style.backgroundColor = color; + this._backgroundColor = color; }, enumerable: true, configurable: true @@ -13963,6 +14130,12 @@ var Phaser; * @type {Number} **/ this.totalTouches = 0; + /** + * The Game Object this Pointer is currently over / touching / dragging. + * @property targetObject + * @type {Any} + **/ + this.targetObject = null; this.game = game; this.id = id; this.active = false; @@ -14004,6 +14177,28 @@ var Phaser; if (typeof camera === "undefined") { camera = this.game.camera; } return camera.worldView.y + this.y; }; + Object.defineProperty(Pointer.prototype, "scaledX", { + get: /** + * Gets the X value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + function () { + return Math.floor(this.x * this.game.input.scaleX); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Pointer.prototype, "scaledY", { + get: /** + * Gets the Y value of this Pointer in world coordinate space + * @param {Camera} [camera] + */ + function () { + return Math.floor(this.y * this.game.input.scaleY); + }, + enumerable: true, + configurable: true + }); Pointer.prototype.start = /** * Called when the Pointer is pressed onto the touchscreen * @method start @@ -14016,19 +14211,19 @@ var Phaser; this.button = event.button; } // Fix to stop rogue browser plugins from blocking the visibility state event - if(this.game.paused == true) { + if(this.game.paused == true && this.game.stage.scale.incorrectOrientation == false) { this.game.stage.resumeGame(); return this; } this._history.length = 0; - this.move(event); - this.positionDown.setTo(this.x, this.y); this.active = true; this.withinGame = true; this.isDown = true; this.isUp = false; this.timeDown = this.game.time.now; this._holdSent = false; + this.positionDown.setTo(this.x, this.y); + this.move(event); if(this.game.input.multiInputOverride == Phaser.Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Phaser.Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Phaser.Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { this.game.input.x = this.x * this.game.input.scaleX; this.game.input.y = this.y * this.game.input.scaleY; @@ -14039,6 +14234,31 @@ var Phaser; if(this.isMouse == false) { this.game.input.currentPointers++; } + // Build our temporary click stack + /* + var _highestPriority = 0; + var _highestRenderID = 0; + var _highestRenderObject: number = -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) + { + _highestRenderID = this.game.input.inputObjects[i].renderOrderID; + _highestRenderObject = i; + } + } + + if (_highestRenderObject !== -1 && this._stateReset == false) + { + this.targetObject = this.game.input.inputObjects[_highestRenderObject]; + this.targetObject.input._touchedHandler(this); + //_highestRenderObject.input._touchedHandler(this); + } + */ + if(this.targetObject !== null) { + this.targetObject.input._touchedHandler(this); + } return this; }; Pointer.prototype.update = function () { @@ -14062,25 +14282,47 @@ var Phaser; } // Iterate through the tracked objects // Build our temporary click stack + /* var _highestPriority = 0; - for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.enabled) { - if(this.game.input.inputObjects[i].input.update(this) && this.game.input.inputObjects[i].input.priorityID > _highestPriority) { - _highestPriority = this.game.input.inputObjects[i].input.priorityID; - } - } + var _highestRenderID = 0; + var _highestRenderObject = null; + + for (var i = 0; i < this.game.input.totalTrackedObjects; i++) + { + if (this.game.input.inputObjects[i].input.enabled) + { + //if (this.game.input.inputObjects[i].input.update(this) && this.game.input.inputObjects[i].input.priorityID > _highestPriority) + if (this.game.input.inputObjects[i].input.update(this) && this.game.input.inputObjects[i].renderOrderID > _highestRenderID) + { + _highestRenderID = this.game.input.inputObjects[i].renderOrderID; + _highestRenderObject = this.game.input.inputObjects[i]; } - if(this.isDown && this._stateReset == false) { - // Now update all objects with the highest priority ID (can be more than 1) - for(var i = 0; i < this.game.input.totalTrackedObjects; i++) { - if(this.game.input.inputObjects[i].input.priorityID == _highestPriority) { - if(this.game.input.inputObjects[i].input._touchedHandler(this) == false) { - return; + } + } + + if (_highestRenderObject !== null) + { + _highestRenderObject.input._pointerOverHandler(this); + + if (this.isDown && this._stateReset == false) + { + _highestRenderObject.input._touchedHandler(this); + } + + // Now update all objects with the highest priority ID (can be more than 1) + //for (var i = 0; i < this.game.input.totalTrackedObjects; i++) + //{ + // if (this.game.input.inputObjects[i].input.priorityID == _highestPriority) + // { + // if (this.game.input.inputObjects[i].input._touchedHandler(this) == false) + // { + // return; + // } + // } + //} + } + */ } - } - } - } - } }; Pointer.prototype.move = /** * Called when the Pointer is moved on the touchscreen @@ -14109,6 +14351,26 @@ var Phaser; this.game.input.circle.x = this.game.input.x; this.game.input.circle.y = this.game.input.y; } + if(this.targetObject !== null) { + if(this.targetObject.input.update(this) == false) { + this.targetObject = null; + } + } else { + // Build our temporary click stack + var _highestRenderID = 0; + 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) { + _highestRenderID = this.game.input.inputObjects[i].renderOrderID; + _highestRenderObject = i; + } + } + if(_highestRenderObject !== -1) { + //console.log('setting target'); + this.targetObject = this.game.input.inputObjects[_highestRenderObject]; + this.targetObject.input._pointerOverHandler(this); + } + } return this; }; Pointer.prototype.leave = /** @@ -14161,7 +14423,10 @@ var Phaser; this.game.input.inputObjects[i].input._releasedHandler(this); } } - this.draggedObject = null; + if(this.targetObject) { + this.targetObject.input._releasedHandler(this); + } + this.targetObject = null; return this; }; Pointer.prototype.justPressed = /** @@ -14207,6 +14472,10 @@ var Phaser; this._holdSent = false; this._history.length = 0; this._stateReset = true; + if(this.targetObject) { + this.targetObject.input._releasedHandler(this); + } + this.targetObject = null; }; Pointer.prototype.renderDebug = /** * Renders the Pointer.circle object onto the stage in green if down or red if up. @@ -14402,7 +14671,11 @@ var Phaser; * @type {Boolean} */ this.disabled = false; + this.mouseDownCallback = null; + this.mouseMoveCallback = null; + this.mouseUpCallback = null; this._game = game; + this.callbackContext = this._game; } Mouse.LEFT_BUTTON = 0; Mouse.MIDDLE_BUTTON = 1; @@ -14427,6 +14700,9 @@ var Phaser; * @param {MouseEvent} event */ function (event) { + if(this.mouseDownCallback) { + this.mouseDownCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14437,6 +14713,9 @@ var Phaser; * @param {MouseEvent} event */ function (event) { + if(this.mouseMoveCallback) { + this.mouseMoveCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14447,6 +14726,9 @@ var Phaser; * @param {MouseEvent} event */ function (event) { + if(this.mouseUpCallback) { + this.mouseUpCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14735,7 +15017,14 @@ var Phaser; * @type {Boolean} */ this.disabled = false; + this.touchStartCallback = null; + this.touchMoveCallback = null; + this.touchEndCallback = null; + this.touchEnterCallback = null; + this.touchLeaveCallback = null; + this.touchCancelCallback = null; this._game = game; + this.callbackContext = this._game; } Touch.prototype.start = /** * Starts the event listeners running @@ -14781,6 +15070,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchStartCallback) { + this.touchStartCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14799,6 +15091,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchCancelCallback) { + this.touchCancelCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } @@ -14816,13 +15111,16 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchEnterCallback) { + this.touchEnterCallback.call(this.callbackContext, event); + } if(this._game.input.disabled || this.disabled) { return; } event.preventDefault(); for(var i = 0; i < event.changedTouches.length; i++) { - console.log('touch enter'); - } + //console.log('touch enter'); + } }; Touch.prototype.onTouchLeave = /** * For touch enter and leave its a list of the touch points that have entered or left the target @@ -14831,10 +15129,13 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchLeaveCallback) { + this.touchLeaveCallback.call(this.callbackContext, event); + } event.preventDefault(); for(var i = 0; i < event.changedTouches.length; i++) { - console.log('touch leave'); - } + //console.log('touch leave'); + } }; Touch.prototype.onTouchMove = /** * @@ -14842,6 +15143,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchMoveCallback) { + this.touchMoveCallback.call(this.callbackContext, event); + } event.preventDefault(); for(var i = 0; i < event.changedTouches.length; i++) { this._game.input.updatePointer(event.changedTouches[i]); @@ -14853,6 +15157,9 @@ var Phaser; * @param {Any} event **/ function (event) { + if(this.touchEndCallback) { + this.touchEndCallback.call(this.callbackContext, event); + } event.preventDefault(); // For touch end its a list of the touch points that have been removed from the surface // https://developer.mozilla.org/en-US/docs/DOM/TouchList @@ -15220,12 +15527,7 @@ var Phaser; this.pointer10.reset(); } this.currentPointers = 0; - for(var i = 0; i < this.totalTrackedObjects; i++) { - this.inputObjects[i].input.reset(); - } this._game.stage.canvas.style.cursor = "default"; - this.inputObjects.length = 0; - this.totalTrackedObjects = 0; if(hard == true) { this.onDown.dispose(); this.onUp.dispose(); @@ -15235,6 +15537,11 @@ var Phaser; this.onUp = new Phaser.Signal(); this.onTap = new Phaser.Signal(); this.onHold = new Phaser.Signal(); + for(var i = 0; i < this.totalTrackedObjects; i++) { + this.inputObjects[i].input.reset(); + } + this.inputObjects.length = 0; + this.totalTrackedObjects = 0; } }; Object.defineProperty(Input.prototype, "totalInactivePointers", { @@ -15463,7 +15770,7 @@ var Phaser; */ function (x, y, color) { if (typeof color === "undefined") { color = 'rgb(255,255,255)'; } - this._game.stage.context.font = '14px Courier'; + this._game.stage.context.font = '24px Courier'; this._game.stage.context.fillStyle = color; this._game.stage.context.fillText('Input', x, y); this._game.stage.context.fillText('Screen X: ' + this.x + ' Screen Y: ' + this.y, x, y + 14); @@ -15639,6 +15946,7 @@ var Phaser; if(sprite.scale.x == 0 || sprite.scale.y == 0 || sprite.texture.alpha < 0.1 || this.inCamera(camera, sprite) == false) { return false; } + sprite.renderOrderID = this._count; this._count++; // Reset our temp vars this._ga = -1;