diff --git a/Phaser/components/sprite/Input.ts b/Phaser/components/sprite/Input.ts index 758fea174..2e2d8495c 100644 --- a/Phaser/components/sprite/Input.ts +++ b/Phaser/components/sprite/Input.ts @@ -21,12 +21,8 @@ module Phaser.Components { this.game = parent.game; this._sprite = parent; - this.enabled = false; - this.checkBody = false; - this.useHandCursor = false; - } /** @@ -39,17 +35,7 @@ module Phaser.Components { */ private _sprite: Sprite; - private dragOffsetX: number; - private dragOffsetY: number; - private dragFromPoint: bool; - private dragPixelPerfect:bool = false; - private dragPixelPerfectAlpha:number; - private allowHorizontalDrag: bool = true; - private allowVerticalDrag: bool = true; - private snapOnDrag: bool = false; - private snapOnRelease: bool = false; - private snapX: number; - private snapY: number; + private _pointerData; /** * If enabled the Input component will be updated by the parent Sprite @@ -58,10 +44,69 @@ module Phaser.Components { public enabled: bool; /** - * Is this sprite being dragged by the mouse or not? - * @default false - */ - public isDragged: bool = false; + * The PriorityID controls which Sprite receives an Input event first if they should overlap. + */ + public priorityID:number = 0; + + public start(priority:number = 0, checkBody?:bool = false, useHandCursor?:bool = false) { + + // Turning on + if (this.enabled) + { + return; + } + else + { + // Register, etc + this.checkBody = checkBody; + this.useHandCursor = useHandCursor; + + this._pointerData = []; + + for (var i = 0; i < 10; i++) + { + this._pointerData.push({ id: i, x: 0, y: 0, isDown: false, isUp: false, isOver: false, isOut: false, timeOver: 0, timeOut: 0, timeDown: 0, timeUp: 0, downDuration: 0, isDragged: false }); + } + + this.snapOffset = new Point; + this.enabled = true; + + this.game.input.addGameObject(this._sprite); + } + + } + + public stop() { + + // Turning off + if (this.enabled == false) + { + return; + } + else + { + // De-register, etc + this.enabled = false; + this.game.input.removeGameObject(this._sprite); + } + + } + + private _dragPoint: Point; + public dragOffset: Point; + public dragFromCenter: bool; + public dragPixelPerfect:bool = false; + public dragPixelPerfectAlpha:number; + + public allowHorizontalDrag: bool = true; + public allowVerticalDrag: bool = true; + + public snapOnDrag: bool = false; + public snapOnRelease: bool = false; + public snapOffset: Point; + public snapX: number = 0; + public snapY: number = 0; + /** * Is this sprite allowed to be dragged by the mouse? true = yes, false = no @@ -70,13 +115,13 @@ module Phaser.Components { public draggable: bool = false; /** - * An FlxRect region of the game world within which the sprite is restricted during mouse drag + * A region of the game world within which the sprite is restricted during drag * @default null */ public boundsRect: Rectangle = null; /** - * An FlxSprite the bounds of which this sprite is restricted during mouse drag + * An Sprite the bounds of which this sprite is restricted during drag * @default null */ public boundsSprite: Sprite = null; @@ -97,145 +142,203 @@ module Phaser.Components { /** * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set with the pointer is over this Sprite. + * This value is only set when the pointer is over this Sprite. * @type {number} */ - public x: number = 0; + public pointerX(pointer: number = 0): number { + return this._pointerData[pointer].x; + } /** * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set with the pointer is over this Sprite. + * This value is only set when the pointer is over this Sprite. * @type {number} */ - public y: number = 0; + public pointerY(pointer: number = 0): number { + return this._pointerData[pointer].y; + } /** * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true * @property isDown * @type {Boolean} **/ - public isDown: bool = false; + public pointerDown(pointer: number = 0): bool { + return this._pointerData[pointer].isDown; + } /** * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true * @property isUp * @type {Boolean} **/ - public isUp: bool = true; + public pointerUp(pointer: number = 0): bool { + return this._pointerData[pointer].isUp; + } /** * A timestamp representing when the Pointer first touched the touchscreen. * @property timeDown * @type {Number} **/ - public timeOver: number = 0; + public pointerTimeDown(pointer: number = 0): bool { + return this._pointerData[pointer].timeDown; + } /** * A timestamp representing when the Pointer left the touchscreen. * @property timeUp * @type {Number} **/ - public timeOut: number = 0; + public pointerTimeUp(pointer: number = 0): bool { + return this._pointerData[pointer].timeUp; + } /** * Is the Pointer over this Sprite * @property isOver * @type {Boolean} **/ - public isOver: bool = false; + public pointerOver(pointer: number = 0): bool { + return this._pointerData[pointer].isOver; + } /** * Is the Pointer outside of this Sprite * @property isOut * @type {Boolean} **/ - public isOut: bool = true; + public pointerOut(pointer: number = 0): bool { + return this._pointerData[pointer].isOut; + } - public oldX: number; - public oldY: number; + /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + public pointerTimeOver(pointer: number = 0): bool { + return this._pointerData[pointer].timeOver; + } + /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + public pointerTimeOut(pointer: number = 0): bool { + return this._pointerData[pointer].timeOut; + } + + /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + public pointerDragged(pointer: number = 0): bool { + return this._pointerData[pointer].isDragged; + } /** * Update */ - public update() { + public update(pointer: Phaser.Pointer) { if (this.enabled == false) { return; } - if (this.draggable && this.isDragged) - { - this.updateDrag(); - } - - if (this.game.input.x != this.oldX || this.game.input.y != this.oldY) + // If was previously touched by this Pointer, check if still is + if (this._pointerData[pointer.id].isDown && pointer.isUp) { - this.oldX = this.game.input.x; - this.oldY = this.game.input.y; - - if (RectangleUtils.contains(this._sprite.frameBounds, this.game.input.x, this.game.input.y)) - { - this.x = this.game.input.x - this._sprite.x; - this.y = this.game.input.y - this._sprite.y; - - if (this.isOver == false) - { - this.isOver = true; - this.isOut = false; - this.timeOver = this.game.time.now; - - if (this.useHandCursor) - { - this._sprite.game.stage.canvas.style.cursor = "pointer"; - } - - this._sprite.events.onInputOver.dispatch(this._sprite, this.x, this.y, this.timeOver); - } - } - else - { - if (this.isOver) - { - this.isOver = false; - this.isOut = true; - this.timeOut = this.game.time.now; - - if (this.useHandCursor) - { - this._sprite.game.stage.canvas.style.cursor = "default"; - } - - this._sprite.events.onInputOut.dispatch(this._sprite, this.timeOut); - } - } - + this._releasedHandler(pointer); } - // click handler to add to stack for sorting + if (this.draggable && this._pointerData[pointer.id].isDragged) + { + this.updateDrag(pointer); + //return; + } + + if (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); + } + } + 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); + } + } + + } + + public _touchedHandler(pointer: Pointer) { + + 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); + + } + + public _releasedHandler(pointer: Pointer) { + + this._pointerData[pointer.id].isDown = false; + this._pointerData[pointer.id].isUp = true; + this._pointerData[pointer.id].timeUp = this.game.time.now; + //this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; + + this._sprite.events.onInputDown.dispatch(this._sprite, pointer); } /** - * Updates the Mouse Drag on this Sprite. + * Updates the Pointer drag on this Sprite. */ - private updateDrag():void + private updateDrag(pointer: Pointer):void { - if (this.isUp) + if (pointer.isUp) { - this.stopDrag(); + this.stopDrag(pointer); return; } - +// something wrong here, should use _dragPoint as well I think somehow if (this.allowHorizontalDrag) { - this._sprite.x = this.game.input.x - this.dragOffsetX; + this._sprite.x = pointer.x - this.dragOffset.x; } if (this.allowVerticalDrag) { - this._sprite.y = this.game.input.y - this.dragOffsetY; + this._sprite.y = pointer.y - this.dragOffset.y; } if (this.boundsRect) @@ -260,8 +363,8 @@ module Phaser.Components { * @param delay The time below which the pointer is considered as just over. * @returns {boolean} */ - public justOver(delay?: number = 500): bool { - return (this.isOver && this.duration < delay); + public justOver(pointer: number = 0, delay?: number = 500): bool { + return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); } /** @@ -269,19 +372,52 @@ module Phaser.Components { * @param delay The time below which the pointer is considered as just out. * @returns {boolean} */ - public justOut(delay?: number = 500): bool { - return (this.isOut && (this.game.time.now - this.timeOut < delay)); + public justOut(pointer: number = 0, delay?: number = 500): bool { + return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); + } + + /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + public justPressed(pointer: number = 0, delay?: number = 500): bool { + return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); + } + + /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + public justReleased(pointer: number = 0, delay?: number = 500): bool { + return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); } /** * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. */ - public get duration(): number { + public overDuration(pointer: number = 0): number { - if (this.isOver) + if (this._pointerData[pointer].isOver) { - return this.game.time.now - this.timeOver; + return this.game.time.now - this._pointerData[pointer].timeOver; + } + + return -1; + + } + + /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + public downDuration(pointer: number = 0): number { + + if (this._pointerData[pointer].isDown) + { + return this.game.time.now - this._pointerData[pointer].timeDown; } return -1; @@ -291,7 +427,7 @@ module Phaser.Components { /** * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * - * @param lockCenter If false the Sprite will drag from where you click it. If true it will center itself to the tip of the mouse pointer. + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere @@ -299,9 +435,12 @@ module Phaser.Components { */ public enableDrag(lockCenter:bool = false, pixelPerfect:bool = false, alphaThreshold:number = 255, boundsRect:Rectangle = null, boundsSprite:Sprite = null):void { + this._dragPoint = new Point; + this.draggable = true; - this.dragFromPoint = lockCenter; + this.dragOffset = new Point; + this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; this.dragPixelPerfectAlpha = alphaThreshold; @@ -321,19 +460,51 @@ module Phaser.Components { */ public disableDrag():void { - if (this.isDragged) - { - //FlxMouseControl.dragTarget = null; - //FlxMouseControl.isDragging = false; - } - - this.isDragged = false; + if (this._pointerData) + { + for (var i = 0; i < 10; i++) + { + this._pointerData[i].isDragged = false; + } + } + this.draggable = false; //mouseStartDragCallback = null; //mouseStopDragCallback = null; } - + + /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + public startDrag(pointer: Pointer):void + { + this._pointerData[pointer.id].isDragged = true; + + if (this.dragFromCenter) + { + // Move the sprite to the middle of the pointer + this.dragOffset.setTo(this._sprite.frameBounds.halfWidth, this._sprite.frameBounds.halfHeight); + } + + this._dragPoint.setTo(pointer.x - this._sprite.x - this.dragOffset.x, pointer.y - this._sprite.y - this.dragOffset.y); + + } + + /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + public stopDrag(pointer: Pointer):void + { + this._pointerData[pointer.id].isDragged = false; + + if (this.snapOnRelease) + { + this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; + this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; + } + } + /** * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! * @@ -371,26 +542,6 @@ module Phaser.Components { this.snapOnDrag = false; this.snapOnRelease = false; } - - /** - * Called by FlxMouseControl when Mouse Drag starts on this Sprite. Should not usually be called directly. - */ - public startDrag():void - { - this.isDragged = true; - - if (this.dragFromPoint == false) - { - this.dragOffsetX = this.game.input.x - this._sprite.x; - this.dragOffsetY = this.game.input.y - this._sprite.y; - } - else - { - // Move the sprite to the middle of the mouse - this.dragOffsetX = this._sprite.frameBounds.halfWidth; - this.dragOffsetY = this._sprite.frameBounds.halfHeight; - } - } /** * Bounds Rect check for the sprite drag @@ -439,20 +590,6 @@ module Phaser.Components { this._sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this._sprite.height; } } - - /** - * Called by FlxMouseControl when Mouse Drag is stopped on this Sprite. Should not usually be called directly. - */ - public stopDrag():void - { - this.isDragged = false; - - if (this.snapOnRelease) - { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - } /** * Render debug infos. (including name, bounds info, position and some other properties) @@ -465,9 +602,10 @@ module Phaser.Components { 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.x.toFixed(1) + ' y: ' + this.y.toFixed(1), x, y + 14); - this._sprite.texture.context.fillText('over: ' + this.isOver + ' duration: ' + this.duration.toFixed(0), x, y + 28); - this._sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 42); + 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); } diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index 211b712ae..1bdda8c8d 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -303,8 +303,6 @@ module Phaser { } */ - this.input.update(); - if (this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.angle == 0 && this.angleOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { this.modified = false; diff --git a/Phaser/input/Input.ts b/Phaser/input/Input.ts index 5bea27558..ea1cde0b2 100644 --- a/Phaser/input/Input.ts +++ b/Phaser/input/Input.ts @@ -446,14 +446,36 @@ module Phaser { this.mspointer.start(); this.gestures.start(); + this.mousePointer.active = true; + } + public inputObjects = []; + public totalTrackedObjects: number = 0; + + // Add Input Enabled array + add/remove methods and then iterate and update them during the main update + // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + + public addGameObject(object) { + + // Lots more checks here + this.inputObjects.push(object); + this.totalTrackedObjects++; + } + + public removeGameObject(object) { + // TODO + } + + + /** * Updates the Input Manager. Called by the core Game loop. * @method update **/ public update() { + // Swap for velocity vector - and add it to Pointer? this.speed.x = this.position.x - this._oldPosition.x; this.speed.y = this.position.y - this._oldPosition.y; diff --git a/Phaser/input/Mouse.ts b/Phaser/input/Mouse.ts index 6ea05f22c..f3dcac199 100644 --- a/Phaser/input/Mouse.ts +++ b/Phaser/input/Mouse.ts @@ -24,7 +24,6 @@ module Phaser { **/ private _game: Game; - public static LEFT_BUTTON: number = 0; public static MIDDLE_BUTTON: number = 1; public static RIGHT_BUTTON: number = 2; diff --git a/Phaser/input/Pointer.ts b/Phaser/input/Pointer.ts index 93e3913a5..62d94a761 100644 --- a/Phaser/input/Pointer.ts +++ b/Phaser/input/Pointer.ts @@ -18,7 +18,7 @@ module Phaser { */ constructor(game: Game, id: number) { - this._game = game; + this.game = game; this.id = id; this.active = false; @@ -35,11 +35,11 @@ module Phaser { /** * Local private reference to game. - * @property _game + * @property game * @type {Phaser.Game} * @private **/ - private _game: Game; + public game: Game; /** * Local private variable to store the status of dispatching a hold event @@ -248,15 +248,24 @@ module Phaser { return -1; } - return this._game.time.now - this.timeDown; + return this.game.time.now - this.timeDown; } + // Sprite Drag Related + + /** + * The Game Object this Pointer is currently dragging. + * @property draggedObject + * @type {Any} + **/ + public draggedObject; + /** * Gets the X value of this Pointer in world coordinate space * @param {Camera} [camera] */ - public getWorldX(camera?: Camera = this._game.camera) { + public getWorldX(camera?: Camera = this.game.camera) { return camera.worldView.x + this.x; @@ -266,7 +275,7 @@ module Phaser { * Gets the Y value of this Pointer in world coordinate space * @param {Camera} [camera] */ - public getWorldY(camera?: Camera = this._game.camera) { + public getWorldY(camera?: Camera = this.game.camera) { return camera.worldView.y + this.y; @@ -288,9 +297,9 @@ 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.resumeGame(); + this.game.stage.resumeGame(); return this; } @@ -304,21 +313,21 @@ module Phaser { this.withinGame = true; this.isDown = true; this.isUp = false; - this.timeDown = this._game.time.now; + this.timeDown = this.game.time.now; this._holdSent = false; - if (this._game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this._game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this._game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this._game.input.currentPointers == 0)) + if (this.game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == 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; - this._game.input.onDown.dispatch(this); + this.game.input.x = this.x * this.game.input.scaleX; + this.game.input.y = this.y * this.game.input.scaleY; + this.game.input.onDown.dispatch(this); } this.totalTouches++; if (this.isMouse == false) { - this._game.input.currentPointers++; + this.game.input.currentPointers++; } return this; @@ -329,28 +338,58 @@ module Phaser { if (this.active) { - if (this._holdSent == false && this.duration >= this._game.input.holdRate) + if (this._holdSent == false && this.duration >= this.game.input.holdRate) { - if (this._game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this._game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this._game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this._game.input.currentPointers == 0)) + if (this.game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this._game.input.onHold.dispatch(this); + this.game.input.onHold.dispatch(this); } this._holdSent = true; } // Update the droppings history - if (this._game.input.recordPointerHistory && this._game.time.now >= this._nextDrop) + if (this.game.input.recordPointerHistory && this.game.time.now >= this._nextDrop) { - this._nextDrop = this._game.time.now + this._game.input.recordRate; + this._nextDrop = this.game.time.now + this.game.input.recordRate; this._history.push({ x: this.position.x, y: this.position.y }); - if (this._history.length > this._game.input.recordLimit) + if (this._history.length > this.game.input.recordLimit) { this._history.shift(); } } + // 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) + { + this.game.input.inputObjects[i].input.update(this); + + if (this.game.input.inputObjects[i].input.priorityID > _highestPriority) + { + _highestPriority = this.game.input.inputObjects[i].input.priorityID; + } + } + } + + if (this.isDown) + { + // 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) + { + this.game.input.inputObjects[i].input._touchedHandler(this); + } + } + } + } } @@ -374,20 +413,20 @@ module Phaser { this.screenX = event.screenX; this.screenY = event.screenY; - this.x = this.pageX - this._game.stage.offset.x; - this.y = this.pageY - this._game.stage.offset.y; + this.x = this.pageX - this.game.stage.offset.x; + this.y = this.pageY - this.game.stage.offset.y; this.position.setTo(this.x, this.y); this.circle.x = this.x; this.circle.y = this.y; - if (this._game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this._game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this._game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this._game.input.currentPointers == 0)) + if (this.game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == 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; - this._game.input.position.setTo(this._game.input.x, this._game.input.y); - this._game.input.circle.x = this._game.input.x; - this._game.input.circle.y = this._game.input.y; + this.game.input.x = this.x * this.game.input.scaleX; + this.game.input.y = this.y * this.game.input.scaleY; + this.game.input.position.setTo(this.game.input.x, this.game.input.y); + this.game.input.circle.x = this.game.input.x; + this.game.input.circle.y = this.game.input.y; } return this; @@ -413,25 +452,25 @@ module Phaser { */ public stop(event): Pointer { - this.timeUp = this._game.time.now; + this.timeUp = this.game.time.now; - if (this._game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this._game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this._game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this._game.input.currentPointers == 0)) + if (this.game.input.multiInputOverride == Input.MOUSE_OVERRIDES_TOUCH || this.game.input.multiInputOverride == Input.MOUSE_TOUCH_COMBINE || (this.game.input.multiInputOverride == Input.TOUCH_OVERRIDES_MOUSE && this.game.input.currentPointers == 0)) { - this._game.input.onUp.dispatch(this); + this.game.input.onUp.dispatch(this); // Was it a tap? - if (this.duration >= 0 && this.duration <= this._game.input.tapRate) + if (this.duration >= 0 && this.duration <= this.game.input.tapRate) { // Was it a double-tap? - if (this.timeUp - this.previousTapTime < this._game.input.doubleTapRate) + if (this.timeUp - this.previousTapTime < this.game.input.doubleTapRate) { // Yes, let's dispatch the signal then with the 2nd parameter set to true - this._game.input.onTap.dispatch(this, true); + this.game.input.onTap.dispatch(this, true); } else { // Wasn't a double-tap, so dispatch a single tap signal - this._game.input.onTap.dispatch(this, false); + this.game.input.onTap.dispatch(this, false); } this.previousTapTime = this.timeUp; @@ -439,14 +478,19 @@ module Phaser { } - this.active = false; + // Mouse is always active + if (this.id > 0) + { + this.active = false; + } + this.withinGame = false; this.isDown = false; this.isUp = true; if (this.isMouse == false) { - this._game.input.currentPointers--; + this.game.input.currentPointers--; } return this; @@ -459,9 +503,9 @@ module Phaser { * @param {Number} [duration]. * @return {Boolean} */ - public justPressed(duration?: number = this._game.input.justPressedRate): bool { + public justPressed(duration?: number = this.game.input.justPressedRate): bool { - if (this.isDown === true && (this.timeDown + duration) > this._game.time.now) + if (this.isDown === true && (this.timeDown + duration) > this.game.time.now) { return true; } @@ -478,9 +522,9 @@ module Phaser { * @param {Number} [duration]. * @return {Boolean} */ - public justReleased(duration?: number = this._game.input.justReleasedRate): bool { + public justReleased(duration?: number = this.game.input.justReleasedRate): bool { - if (this.isUp === true && (this.timeUp + duration) > this._game.time.now) + if (this.isUp === true && (this.timeUp + duration) > this.game.time.now) { return true; } @@ -518,37 +562,37 @@ module Phaser { return; } - this._game.stage.context.beginPath(); - this._game.stage.context.arc(this.x, this.y, this.circle.radius, 0, Math.PI * 2); + this.game.stage.context.beginPath(); + this.game.stage.context.arc(this.x, this.y, this.circle.radius, 0, Math.PI * 2); if (this.active) { - this._game.stage.context.fillStyle = 'rgba(0,255,0,0.5)'; - this._game.stage.context.strokeStyle = 'rgb(0,255,0)'; + this.game.stage.context.fillStyle = 'rgba(0,255,0,0.5)'; + this.game.stage.context.strokeStyle = 'rgb(0,255,0)'; } else { - this._game.stage.context.fillStyle = 'rgba(255,0,0,0.5)'; - this._game.stage.context.strokeStyle = 'rgb(100,0,0)'; + this.game.stage.context.fillStyle = 'rgba(255,0,0,0.5)'; + this.game.stage.context.strokeStyle = 'rgb(100,0,0)'; } - this._game.stage.context.fill(); - this._game.stage.context.closePath(); + this.game.stage.context.fill(); + this.game.stage.context.closePath(); // Render the points - this._game.stage.context.beginPath(); - this._game.stage.context.moveTo(this.positionDown.x, this.positionDown.y); - this._game.stage.context.lineTo(this.position.x, this.position.y); - this._game.stage.context.lineWidth = 2; - this._game.stage.context.stroke(); - this._game.stage.context.closePath(); + this.game.stage.context.beginPath(); + this.game.stage.context.moveTo(this.positionDown.x, this.positionDown.y); + this.game.stage.context.lineTo(this.position.x, this.position.y); + this.game.stage.context.lineWidth = 2; + this.game.stage.context.stroke(); + this.game.stage.context.closePath(); // Render the text - this._game.stage.context.fillStyle = 'rgb(255,255,255)'; - this._game.stage.context.font = 'Arial 16px'; - this._game.stage.context.fillText('ID: ' + this.id + " Active: " + this.active, this.x, this.y - 100); - this._game.stage.context.fillText('Screen X: ' + this.x + " Screen Y: " + this.y, this.x, this.y - 80); - this._game.stage.context.fillText('Duration: ' + this.duration + " ms", this.x, this.y - 60); + this.game.stage.context.fillStyle = 'rgb(255,255,255)'; + this.game.stage.context.font = 'Arial 16px'; + this.game.stage.context.fillText('ID: ' + this.id + " Active: " + this.active, this.x, this.y - 100); + this.game.stage.context.fillText('Screen X: ' + this.x + " Screen Y: " + this.y, this.x, this.y - 80); + this.game.stage.context.fillText('Duration: ' + this.duration + " ms", this.x, this.y - 60); } diff --git a/README.md b/README.md index 4ffae8f01..083cfcd7e 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ TODO: * Polygon geom primitive * If the Camera is larger than the Stage size then the rotation offset isn't correct * Texture Repeat doesn't scroll, because it's part of the camera not the world, need to think about this more -* Hook-up more events * Bug: Sprite x/y gets shifted if dynamic from the original value +* Input CSS cursor those little 4-way arrows on drag? V1.0.0 @@ -68,7 +68,8 @@ V1.0.0 * Added Group.addNewSprite(x,y,key) for quick addition of new Sprites to a Group * Fixed Group.sort so the sortHandler is called correctly * Added Group.swap(a,b) to swap the z-index of 2 objects with optional rendering update boolean - +* Sprites dispatch killed/revived and added to and removed from Group events. +* Added Input drag, bounds, sprite bounds and snapping support. V0.9.6 diff --git a/Tests/input/over sprite 1.js b/Tests/input/over sprite 1.js index a1d7dfb4e..c8688b125 100644 --- a/Tests/input/over sprite 1.js +++ b/Tests/input/over sprite 1.js @@ -10,9 +10,7 @@ function create() { sprite = game.add.sprite(200, 200, 'sprite'); // Enable Input detection - sprite.input.enabled = true; - // Change the mouse pointer to a hand when over this sprite - sprite.input.useHandCursor = true; + sprite.input.start(0, false, true); } function render() { game.input.renderDebugInfo(32, 32); diff --git a/Tests/input/over sprite 1.ts b/Tests/input/over sprite 1.ts index f44531e79..5a595df5d 100644 --- a/Tests/input/over sprite 1.ts +++ b/Tests/input/over sprite 1.ts @@ -19,10 +19,7 @@ sprite = game.add.sprite(200, 200, 'sprite'); // Enable Input detection - sprite.input.enabled = true; - - // Change the mouse pointer to a hand when over this sprite - sprite.input.useHandCursor = true; + sprite.input.start(0, false, true); } diff --git a/Tests/phaser.js b/Tests/phaser.js index ddf43b67a..845c94d66 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -5579,136 +5579,245 @@ var Phaser; * @param parent The Sprite using this Input component */ function Input(parent) { + /** + * The PriorityID controls which Sprite receives an Input event first if they should overlap. + */ + this.priorityID = 0; this.dragPixelPerfect = false; this.allowHorizontalDrag = true; this.allowVerticalDrag = true; this.snapOnDrag = false; this.snapOnRelease = false; - /** - * Is this sprite being dragged by the mouse or not? - * @default false - */ - this.isDragged = false; + this.snapX = 0; + this.snapY = 0; /** * Is this sprite allowed to be dragged by the mouse? true = yes, false = no * @default false */ this.draggable = false; /** - * An FlxRect region of the game world within which the sprite is restricted during mouse drag + * A region of the game world within which the sprite is restricted during drag * @default null */ this.boundsRect = null; /** - * An FlxSprite the bounds of which this sprite is restricted during mouse drag + * An Sprite the bounds of which this sprite is restricted during drag * @default null */ this.boundsSprite = null; - /** - * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set with the pointer is over this Sprite. - * @type {number} - */ - this.x = 0; - /** - * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set with the pointer is over this Sprite. - * @type {number} - */ - this.y = 0; - /** - * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true - * @property isDown - * @type {Boolean} - **/ - this.isDown = false; - /** - * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true - * @property isUp - * @type {Boolean} - **/ - this.isUp = true; - /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - this.timeOver = 0; - /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - this.timeOut = 0; - /** - * Is the Pointer over this Sprite - * @property isOver - * @type {Boolean} - **/ - this.isOver = false; - /** - * Is the Pointer outside of this Sprite - * @property isOut - * @type {Boolean} - **/ - this.isOut = true; this.game = parent.game; this._sprite = parent; this.enabled = false; - this.checkBody = false; - this.useHandCursor = false; } + Input.prototype.start = function (priority, checkBody, useHandCursor) { + if (typeof priority === "undefined") { priority = 0; } + if (typeof checkBody === "undefined") { checkBody = false; } + if (typeof useHandCursor === "undefined") { useHandCursor = false; } + // Turning on + if(this.enabled) { + return; + } else { + // Register, etc + this.checkBody = checkBody; + this.useHandCursor = useHandCursor; + this._pointerData = []; + for(var i = 0; i < 10; i++) { + this._pointerData.push({ + id: i, + x: 0, + y: 0, + isDown: false, + isUp: false, + isOver: false, + isOut: false, + timeOver: 0, + timeOut: 0, + timeDown: 0, + timeUp: 0, + downDuration: 0, + isDragged: false + }); + } + this.snapOffset = new Phaser.Point(); + this.enabled = true; + this.game.input.addGameObject(this._sprite); + } + }; + Input.prototype.stop = function () { + // Turning off + if(this.enabled == false) { + return; + } else { + // De-register, etc + this.enabled = false; + this.game.input.removeGameObject(this._sprite); + } + }; + Input.prototype.pointerX = /** + * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].x; + }; + Input.prototype.pointerY = /** + * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].y; + }; + Input.prototype.pointerDown = /** + * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true + * @property isDown + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDown; + }; + Input.prototype.pointerUp = /** + * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true + * @property isUp + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isUp; + }; + Input.prototype.pointerTimeDown = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeDown; + }; + Input.prototype.pointerTimeUp = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeUp; + }; + Input.prototype.pointerOver = /** + * Is the Pointer over this Sprite + * @property isOver + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOver; + }; + Input.prototype.pointerOut = /** + * Is the Pointer outside of this Sprite + * @property isOut + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOut; + }; + Input.prototype.pointerTimeOver = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOver; + }; + Input.prototype.pointerTimeOut = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOut; + }; + Input.prototype.pointerDragged = /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDragged; + }; Input.prototype.update = /** * Update */ - function () { + function (pointer) { if(this.enabled == false) { return; } - if(this.draggable && this.isDragged) { - this.updateDrag(); + // If was previously touched by this Pointer, check if still is + if(this._pointerData[pointer.id].isDown && pointer.isUp) { + this._releasedHandler(pointer); } - if(this.game.input.x != this.oldX || this.game.input.y != this.oldY) { - this.oldX = this.game.input.x; - this.oldY = this.game.input.y; - if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, this.game.input.x, this.game.input.y)) { - this.x = this.game.input.x - this._sprite.x; - this.y = this.game.input.y - this._sprite.y; - if(this.isOver == false) { - this.isOver = true; - this.isOut = false; - this.timeOver = this.game.time.now; - if(this.useHandCursor) { - this._sprite.game.stage.canvas.style.cursor = "pointer"; - } - this._sprite.events.onInputOver.dispatch(this._sprite, this.x, this.y, this.timeOver); + if(this.draggable && this._pointerData[pointer.id].isDragged) { + this.updateDrag(pointer); + //return; + } + 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"; } - } else { - if(this.isOver) { - this.isOver = false; - this.isOut = true; - this.timeOut = this.game.time.now; - if(this.useHandCursor) { - this._sprite.game.stage.canvas.style.cursor = "default"; - } - this._sprite.events.onInputOut.dispatch(this._sprite, this.timeOut); + this._sprite.events.onInputOver.dispatch(this._sprite, pointer); + } + } 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); } } }; + Input.prototype._touchedHandler = function (pointer) { + 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); + }; + Input.prototype._releasedHandler = function (pointer) { + this._pointerData[pointer.id].isDown = false; + this._pointerData[pointer.id].isUp = true; + this._pointerData[pointer.id].timeUp = this.game.time.now; + //this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; + this._sprite.events.onInputDown.dispatch(this._sprite, pointer); + }; Input.prototype.updateDrag = /** - * Updates the Mouse Drag on this Sprite. + * Updates the Pointer drag on this Sprite. */ - function () { - if(this.isUp) { - this.stopDrag(); + function (pointer) { + if(pointer.isUp) { + this.stopDrag(pointer); return; } + // something wrong here, should use _dragPoint as well I think somehow if(this.allowHorizontalDrag) { - this._sprite.x = this.game.input.x - this.dragOffsetX; + this._sprite.x = pointer.x - this.dragOffset.x; } if(this.allowVerticalDrag) { - this._sprite.y = this.game.input.y - this.dragOffsetY; + this._sprite.y = pointer.y - this.dragOffset.y; } if(this.boundsRect) { this.checkBoundsRect(); @@ -5726,37 +5835,67 @@ var Phaser; * @param delay The time below which the pointer is considered as just over. * @returns {boolean} */ - function (delay) { + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } if (typeof delay === "undefined") { delay = 500; } - return (this.isOver && this.duration < delay); + return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); }; Input.prototype.justOut = /** * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) * @param delay The time below which the pointer is considered as just out. * @returns {boolean} */ - function (delay) { + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } if (typeof delay === "undefined") { delay = 500; } - return (this.isOut && (this.game.time.now - this.timeOut < delay)); + return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); + }; + Input.prototype.justPressed = /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); + }; + Input.prototype.justReleased = /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); + }; + Input.prototype.overDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isOver) { + return this.game.time.now - this._pointerData[pointer].timeOver; + } + return -1; + }; + Input.prototype.downDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isDown) { + return this.game.time.now - this._pointerData[pointer].timeDown; + } + return -1; }; - Object.defineProperty(Input.prototype, "duration", { - get: /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. - */ - function () { - if(this.isOver) { - return this.game.time.now - this.timeOver; - } - return -1; - }, - enumerable: true, - configurable: true - }); Input.prototype.enableDrag = /** * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * - * @param lockCenter If false the Sprite will drag from where you click it. If true it will center itself to the tip of the mouse pointer. + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere @@ -5768,8 +5907,10 @@ var Phaser; if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } if (typeof boundsRect === "undefined") { boundsRect = null; } if (typeof boundsSprite === "undefined") { boundsSprite = null; } + this._dragPoint = new Phaser.Point(); this.draggable = true; - this.dragFromPoint = lockCenter; + this.dragOffset = new Phaser.Point(); + this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; this.dragPixelPerfectAlpha = alphaThreshold; if(boundsRect) { @@ -5783,15 +5924,36 @@ var Phaser; * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. */ function () { - if(this.isDragged) { - //FlxMouseControl.dragTarget = null; - //FlxMouseControl.isDragging = false; - } - this.isDragged = false; + if(this._pointerData) { + for(var i = 0; i < 10; i++) { + this._pointerData[i].isDragged = false; + } + } this.draggable = false; //mouseStartDragCallback = null; //mouseStopDragCallback = null; }; + Input.prototype.startDrag = /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this._pointerData[pointer.id].isDragged = true; + if(this.dragFromCenter) { + // Move the sprite to the middle of the pointer + this.dragOffset.setTo(this._sprite.frameBounds.halfWidth, this._sprite.frameBounds.halfHeight); + } + this._dragPoint.setTo(pointer.x - this._sprite.x - this.dragOffset.x, pointer.y - this._sprite.y - this.dragOffset.y); + }; + Input.prototype.stopDrag = /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this._pointerData[pointer.id].isDragged = false; + if(this.snapOnRelease) { + this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; + this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; + } + }; 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! * @@ -5828,20 +5990,6 @@ var Phaser; this.snapOnDrag = false; this.snapOnRelease = false; }; - Input.prototype.startDrag = /** - * Called by FlxMouseControl when Mouse Drag starts on this Sprite. Should not usually be called directly. - */ - function () { - this.isDragged = true; - if(this.dragFromPoint == false) { - this.dragOffsetX = this.game.input.x - this._sprite.x; - this.dragOffsetY = this.game.input.y - this._sprite.y; - } else { - // Move the sprite to the middle of the mouse - this.dragOffsetX = this._sprite.frameBounds.halfWidth; - this.dragOffsetY = this._sprite.frameBounds.halfHeight; - } - }; Input.prototype.checkBoundsRect = /** * Bounds Rect check for the sprite drag */ @@ -5872,16 +6020,6 @@ var Phaser; this._sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this._sprite.height; } }; - Input.prototype.stopDrag = /** - * Called by FlxMouseControl when Mouse Drag is stopped on this Sprite. Should not usually be called directly. - */ - function () { - this.isDragged = false; - if(this.snapOnRelease) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - }; Input.prototype.renderDebugInfo = /** * Render debug infos. (including name, bounds info, position and some other properties) * @param x {number} X position of the debug info to be rendered. @@ -5893,9 +6031,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.x.toFixed(1) + ' y: ' + this.y.toFixed(1), x, y + 14); - this._sprite.texture.context.fillText('over: ' + this.isOver + ' duration: ' + this.duration.toFixed(0), x, y + 28); - this._sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 42); + 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); }; return Input; })(); @@ -6624,7 +6763,6 @@ var Phaser; } } */ - this.input.update(); if(this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.angle == 0 && this.angleOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { this.modified = false; } @@ -13280,7 +13418,7 @@ var Phaser; * @type {Number} **/ this.totalTouches = 0; - this._game = game; + this.game = game; this.id = id; this.active = false; this.position = new Phaser.Vec2(); @@ -13300,7 +13438,7 @@ var Phaser; if(this.isUp) { return -1; } - return this._game.time.now - this.timeDown; + return this.game.time.now - this.timeDown; }, enumerable: true, configurable: true @@ -13310,7 +13448,7 @@ var Phaser; * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this._game.camera; } + if (typeof camera === "undefined") { camera = this.game.camera; } return camera.worldView.x + this.x; }; Pointer.prototype.getWorldY = /** @@ -13318,7 +13456,7 @@ var Phaser; * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this._game.camera; } + if (typeof camera === "undefined") { camera = this.game.camera; } return camera.worldView.y + this.y; }; Pointer.prototype.start = /** @@ -13333,8 +13471,8 @@ var Phaser; this.button = event.button; } // Fix to stop rogue browser plugins from blocking the visibility state event - if(this._game.paused == true) { - this._game.stage.resumeGame(); + if(this.game.paused == true) { + this.game.stage.resumeGame(); return this; } this._history.length = 0; @@ -13344,38 +13482,57 @@ var Phaser; this.withinGame = true; this.isDown = true; this.isUp = false; - this.timeDown = this._game.time.now; + this.timeDown = this.game.time.now; this._holdSent = false; - 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; - this._game.input.onDown.dispatch(this); + 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; + this.game.input.onDown.dispatch(this); } this.totalTouches++; if(this.isMouse == false) { - this._game.input.currentPointers++; + this.game.input.currentPointers++; } return this; }; Pointer.prototype.update = function () { if(this.active) { - if(this._holdSent == false && this.duration >= this._game.input.holdRate) { - 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.onHold.dispatch(this); + if(this._holdSent == false && this.duration >= this.game.input.holdRate) { + 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.onHold.dispatch(this); } this._holdSent = true; } // Update the droppings history - if(this._game.input.recordPointerHistory && this._game.time.now >= this._nextDrop) { - this._nextDrop = this._game.time.now + this._game.input.recordRate; + if(this.game.input.recordPointerHistory && this.game.time.now >= this._nextDrop) { + this._nextDrop = this.game.time.now + this.game.input.recordRate; this._history.push({ x: this.position.x, y: this.position.y }); - if(this._history.length > this._game.input.recordLimit) { + if(this._history.length > this.game.input.recordLimit) { this._history.shift(); } } + // 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) { + this.game.input.inputObjects[i].input.update(this); + if(this.game.input.inputObjects[i].input.priorityID > _highestPriority) { + _highestPriority = this.game.input.inputObjects[i].input.priorityID; + } + } + } + if(this.isDown) { + // 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) { + this.game.input.inputObjects[i].input._touchedHandler(this); + } + } + } } }; Pointer.prototype.move = /** @@ -13393,17 +13550,17 @@ var Phaser; this.pageY = event.pageY; this.screenX = event.screenX; this.screenY = event.screenY; - this.x = this.pageX - this._game.stage.offset.x; - this.y = this.pageY - this._game.stage.offset.y; + this.x = this.pageX - this.game.stage.offset.x; + this.y = this.pageY - this.game.stage.offset.y; this.position.setTo(this.x, this.y); this.circle.x = this.x; this.circle.y = this.y; - 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; - this._game.input.position.setTo(this._game.input.x, this._game.input.y); - this._game.input.circle.x = this._game.input.x; - this._game.input.circle.y = this._game.input.y; + 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; + this.game.input.position.setTo(this.game.input.x, this.game.input.y); + this.game.input.circle.x = this.game.input.x; + this.game.input.circle.y = this.game.input.y; } return this; }; @@ -13422,28 +13579,31 @@ var Phaser; * @param {Any} event */ function (event) { - this.timeUp = this._game.time.now; - 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.onUp.dispatch(this); + this.timeUp = this.game.time.now; + 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.onUp.dispatch(this); // Was it a tap? - if(this.duration >= 0 && this.duration <= this._game.input.tapRate) { + if(this.duration >= 0 && this.duration <= this.game.input.tapRate) { // Was it a double-tap? - if(this.timeUp - this.previousTapTime < this._game.input.doubleTapRate) { + if(this.timeUp - this.previousTapTime < this.game.input.doubleTapRate) { // Yes, let's dispatch the signal then with the 2nd parameter set to true - this._game.input.onTap.dispatch(this, true); + this.game.input.onTap.dispatch(this, true); } else { // Wasn't a double-tap, so dispatch a single tap signal - this._game.input.onTap.dispatch(this, false); + this.game.input.onTap.dispatch(this, false); } this.previousTapTime = this.timeUp; } } - this.active = false; + // Mouse is always active + if(this.id > 0) { + this.active = false; + } this.withinGame = false; this.isDown = false; this.isUp = true; if(this.isMouse == false) { - this._game.input.currentPointers--; + this.game.input.currentPointers--; } return this; }; @@ -13454,8 +13614,8 @@ var Phaser; * @return {Boolean} */ function (duration) { - if (typeof duration === "undefined") { duration = this._game.input.justPressedRate; } - if(this.isDown === true && (this.timeDown + duration) > this._game.time.now) { + if (typeof duration === "undefined") { duration = this.game.input.justPressedRate; } + if(this.isDown === true && (this.timeDown + duration) > this.game.time.now) { return true; } else { return false; @@ -13468,8 +13628,8 @@ var Phaser; * @return {Boolean} */ function (duration) { - if (typeof duration === "undefined") { duration = this._game.input.justReleasedRate; } - if(this.isUp === true && (this.timeUp + duration) > this._game.time.now) { + if (typeof duration === "undefined") { duration = this.game.input.justReleasedRate; } + if(this.isUp === true && (this.timeUp + duration) > this.game.time.now) { return true; } else { return false; @@ -13497,30 +13657,30 @@ var Phaser; if(hideIfUp == true && this.isUp == true) { return; } - this._game.stage.context.beginPath(); - this._game.stage.context.arc(this.x, this.y, this.circle.radius, 0, Math.PI * 2); + this.game.stage.context.beginPath(); + this.game.stage.context.arc(this.x, this.y, this.circle.radius, 0, Math.PI * 2); if(this.active) { - this._game.stage.context.fillStyle = 'rgba(0,255,0,0.5)'; - this._game.stage.context.strokeStyle = 'rgb(0,255,0)'; + this.game.stage.context.fillStyle = 'rgba(0,255,0,0.5)'; + this.game.stage.context.strokeStyle = 'rgb(0,255,0)'; } else { - this._game.stage.context.fillStyle = 'rgba(255,0,0,0.5)'; - this._game.stage.context.strokeStyle = 'rgb(100,0,0)'; + this.game.stage.context.fillStyle = 'rgba(255,0,0,0.5)'; + this.game.stage.context.strokeStyle = 'rgb(100,0,0)'; } - this._game.stage.context.fill(); - this._game.stage.context.closePath(); + this.game.stage.context.fill(); + this.game.stage.context.closePath(); // Render the points - this._game.stage.context.beginPath(); - this._game.stage.context.moveTo(this.positionDown.x, this.positionDown.y); - this._game.stage.context.lineTo(this.position.x, this.position.y); - this._game.stage.context.lineWidth = 2; - this._game.stage.context.stroke(); - this._game.stage.context.closePath(); + this.game.stage.context.beginPath(); + this.game.stage.context.moveTo(this.positionDown.x, this.positionDown.y); + this.game.stage.context.lineTo(this.position.x, this.position.y); + this.game.stage.context.lineWidth = 2; + this.game.stage.context.stroke(); + this.game.stage.context.closePath(); // Render the text - this._game.stage.context.fillStyle = 'rgb(255,255,255)'; - this._game.stage.context.font = 'Arial 16px'; - this._game.stage.context.fillText('ID: ' + this.id + " Active: " + this.active, this.x, this.y - 100); - this._game.stage.context.fillText('Screen X: ' + this.x + " Screen Y: " + this.y, this.x, this.y - 80); - this._game.stage.context.fillText('Duration: ' + this.duration + " ms", this.x, this.y - 60); + this.game.stage.context.fillStyle = 'rgb(255,255,255)'; + this.game.stage.context.font = 'Arial 16px'; + this.game.stage.context.fillText('ID: ' + this.id + " Active: " + this.active, this.x, this.y - 100); + this.game.stage.context.fillText('Screen X: ' + this.x + " Screen Y: " + this.y, this.x, this.y - 80); + this.game.stage.context.fillText('Duration: ' + this.duration + " ms", this.x, this.y - 60); }; Pointer.prototype.toString = /** * Returns a string representation of this object. @@ -14329,6 +14489,8 @@ var Phaser; * @type {Pointer} **/ this.pointer10 = null; + this.inputObjects = []; + this.totalTrackedObjects = 0; this._game = game; this._stack = []; this.mousePointer = new Phaser.Pointer(this._game, 0); @@ -14426,12 +14588,24 @@ var Phaser; this.touch.start(); this.mspointer.start(); this.gestures.start(); + this.mousePointer.active = true; }; + Input.prototype.addGameObject = // Add Input Enabled array + add/remove methods and then iterate and update them during the main update + // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + function (object) { + // Lots more checks here + this.inputObjects.push(object); + this.totalTrackedObjects++; + }; + Input.prototype.removeGameObject = function (object) { + // TODO + }; Input.prototype.update = /** * Updates the Input Manager. Called by the core Game loop. * @method update **/ function () { + // Swap for velocity vector - and add it to Pointer? this.speed.x = this.position.x - this._oldPosition.x; this.speed.y = this.position.y - this._oldPosition.y; this._oldPosition.copyFrom(this.position); diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 6fd13af7b..83980c536 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -3261,39 +3261,42 @@ module Phaser.Components { * Reference to the Image stored in the Game.Cache that is used as the texture for the Sprite. */ private _sprite; - private dragOffsetX; - private dragOffsetY; - private dragFromPoint; - private dragPixelPerfect; - private dragPixelPerfectAlpha; - private allowHorizontalDrag; - private allowVerticalDrag; - private snapOnDrag; - private snapOnRelease; - private snapX; - private snapY; + private _pointerData; /** * If enabled the Input component will be updated by the parent Sprite * @type {Boolean} */ public enabled: bool; /** - * Is this sprite being dragged by the mouse or not? - * @default false + * The PriorityID controls which Sprite receives an Input event first if they should overlap. */ - public isDragged: bool; + public priorityID: number; + public start(priority?: number, checkBody?: bool, useHandCursor?: bool): void; + public stop(): void; + private _dragPoint; + public dragOffset: Point; + public dragFromCenter: bool; + public dragPixelPerfect: bool; + public dragPixelPerfectAlpha: number; + public allowHorizontalDrag: bool; + public allowVerticalDrag: bool; + public snapOnDrag: bool; + public snapOnRelease: bool; + public snapOffset: Point; + public snapX: number; + public snapY: number; /** * Is this sprite allowed to be dragged by the mouse? true = yes, false = no * @default false */ public draggable: bool; /** - * An FlxRect region of the game world within which the sprite is restricted during mouse drag + * A region of the game world within which the sprite is restricted during drag * @default null */ public boundsRect: Rectangle; /** - * An FlxSprite the bounds of which this sprite is restricted during mouse drag + * An Sprite the bounds of which this sprite is restricted during drag * @default null */ public boundsSprite: Sprite; @@ -3311,83 +3314,117 @@ module Phaser.Components { public useHandCursor: bool; /** * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set with the pointer is over this Sprite. + * This value is only set when the pointer is over this Sprite. * @type {number} */ - public x: number; + public pointerX(pointer?: number): number; /** * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set with the pointer is over this Sprite. + * This value is only set when the pointer is over this Sprite. * @type {number} */ - public y: number; + public pointerY(pointer?: number): number; /** * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true * @property isDown * @type {Boolean} **/ - public isDown: bool; + public pointerDown(pointer?: number): bool; /** * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true * @property isUp * @type {Boolean} **/ - public isUp: bool; + public pointerUp(pointer?: number): bool; /** * A timestamp representing when the Pointer first touched the touchscreen. * @property timeDown * @type {Number} **/ - public timeOver: number; + public pointerTimeDown(pointer?: number): bool; /** * A timestamp representing when the Pointer left the touchscreen. * @property timeUp * @type {Number} **/ - public timeOut: number; + public pointerTimeUp(pointer?: number): bool; /** * Is the Pointer over this Sprite * @property isOver * @type {Boolean} **/ - public isOver: bool; + public pointerOver(pointer?: number): bool; /** * Is the Pointer outside of this Sprite * @property isOut * @type {Boolean} **/ - public isOut: bool; - public oldX: number; - public oldY: number; + public pointerOut(pointer?: number): bool; + /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + public pointerTimeOver(pointer?: number): bool; + /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + public pointerTimeOut(pointer?: number): bool; + /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + public pointerDragged(pointer?: number): bool; /** * Update */ - public update(): void; + public update(pointer: Pointer): void; + public _touchedHandler(pointer: Pointer): void; + public _releasedHandler(pointer: Pointer): void; /** - * Updates the Mouse Drag on this Sprite. + * Updates the Pointer drag on this Sprite. */ - private updateDrag(); + private updateDrag(pointer); /** * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) * @param delay The time below which the pointer is considered as just over. * @returns {boolean} */ - public justOver(delay?: number): bool; + public justOver(pointer?: number, delay?: number): bool; /** * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) * @param delay The time below which the pointer is considered as just out. * @returns {boolean} */ - public justOut(delay?: number): bool; + public justOut(pointer?: number, delay?: number): bool; + /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + public justPressed(pointer?: number, delay?: number): bool; + /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + public justReleased(pointer?: number, delay?: number): bool; /** * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. */ - public duration : number; + public overDuration(pointer?: number): number; + /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + public downDuration(pointer?: number): number; /** * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * - * @param lockCenter If false the Sprite will drag from where you click it. If true it will center itself to the tip of the mouse pointer. + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere @@ -3399,6 +3436,14 @@ module Phaser.Components { */ public disableDrag(): void; /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + public startDrag(pointer: Pointer): void; + /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + public stopDrag(pointer: Pointer): void; + /** * Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move! * * @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false @@ -3420,10 +3465,6 @@ module Phaser.Components { */ public disableSnap(): void; /** - * Called by FlxMouseControl when Mouse Drag starts on this Sprite. Should not usually be called directly. - */ - public startDrag(): void; - /** * Bounds Rect check for the sprite drag */ private checkBoundsRect(); @@ -3432,10 +3473,6 @@ module Phaser.Components { */ private checkBoundsSprite(); /** - * Called by FlxMouseControl when Mouse Drag is stopped on this Sprite. Should not usually be called directly. - */ - public stopDrag(): void; - /** * Render debug infos. (including name, bounds info, position and some other properties) * @param x {number} X position of the debug info to be rendered. * @param y {number} Y position of the debug info to be rendered. @@ -7065,11 +7102,11 @@ module Phaser { constructor(game: Game, id: number); /** * Local private reference to game. - * @property _game + * @property game * @type {Phaser.Game} * @private **/ - private _game; + public game: Game; /** * Local private variable to store the status of dispatching a hold event * @property _holdSent @@ -7245,6 +7282,12 @@ module Phaser { **/ public duration : number; /** + * The Game Object this Pointer is currently dragging. + * @property draggedObject + * @type {Any} + **/ + public draggedObject; + /** * Gets the X value of this Pointer in world coordinate space * @param {Camera} [camera] */ @@ -7981,6 +8024,10 @@ module Phaser { * @method start **/ public boot(): void; + public inputObjects: any[]; + public totalTrackedObjects: number; + public addGameObject(object): void; + public removeGameObject(object): void; /** * Updates the Input Manager. Called by the core Game loop. * @method update diff --git a/build/phaser.js b/build/phaser.js index ddf43b67a..845c94d66 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -5579,136 +5579,245 @@ var Phaser; * @param parent The Sprite using this Input component */ function Input(parent) { + /** + * The PriorityID controls which Sprite receives an Input event first if they should overlap. + */ + this.priorityID = 0; this.dragPixelPerfect = false; this.allowHorizontalDrag = true; this.allowVerticalDrag = true; this.snapOnDrag = false; this.snapOnRelease = false; - /** - * Is this sprite being dragged by the mouse or not? - * @default false - */ - this.isDragged = false; + this.snapX = 0; + this.snapY = 0; /** * Is this sprite allowed to be dragged by the mouse? true = yes, false = no * @default false */ this.draggable = false; /** - * An FlxRect region of the game world within which the sprite is restricted during mouse drag + * A region of the game world within which the sprite is restricted during drag * @default null */ this.boundsRect = null; /** - * An FlxSprite the bounds of which this sprite is restricted during mouse drag + * An Sprite the bounds of which this sprite is restricted during drag * @default null */ this.boundsSprite = null; - /** - * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. - * This value is only set with the pointer is over this Sprite. - * @type {number} - */ - this.x = 0; - /** - * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite - * This value is only set with the pointer is over this Sprite. - * @type {number} - */ - this.y = 0; - /** - * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true - * @property isDown - * @type {Boolean} - **/ - this.isDown = false; - /** - * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true - * @property isUp - * @type {Boolean} - **/ - this.isUp = true; - /** - * A timestamp representing when the Pointer first touched the touchscreen. - * @property timeDown - * @type {Number} - **/ - this.timeOver = 0; - /** - * A timestamp representing when the Pointer left the touchscreen. - * @property timeUp - * @type {Number} - **/ - this.timeOut = 0; - /** - * Is the Pointer over this Sprite - * @property isOver - * @type {Boolean} - **/ - this.isOver = false; - /** - * Is the Pointer outside of this Sprite - * @property isOut - * @type {Boolean} - **/ - this.isOut = true; this.game = parent.game; this._sprite = parent; this.enabled = false; - this.checkBody = false; - this.useHandCursor = false; } + Input.prototype.start = function (priority, checkBody, useHandCursor) { + if (typeof priority === "undefined") { priority = 0; } + if (typeof checkBody === "undefined") { checkBody = false; } + if (typeof useHandCursor === "undefined") { useHandCursor = false; } + // Turning on + if(this.enabled) { + return; + } else { + // Register, etc + this.checkBody = checkBody; + this.useHandCursor = useHandCursor; + this._pointerData = []; + for(var i = 0; i < 10; i++) { + this._pointerData.push({ + id: i, + x: 0, + y: 0, + isDown: false, + isUp: false, + isOver: false, + isOut: false, + timeOver: 0, + timeOut: 0, + timeDown: 0, + timeUp: 0, + downDuration: 0, + isDragged: false + }); + } + this.snapOffset = new Phaser.Point(); + this.enabled = true; + this.game.input.addGameObject(this._sprite); + } + }; + Input.prototype.stop = function () { + // Turning off + if(this.enabled == false) { + return; + } else { + // De-register, etc + this.enabled = false; + this.game.input.removeGameObject(this._sprite); + } + }; + Input.prototype.pointerX = /** + * The x coordinate of the Input pointer, relative to the top-left of the parent Sprite. + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].x; + }; + Input.prototype.pointerY = /** + * The y coordinate of the Input pointer, relative to the top-left of the parent Sprite + * This value is only set when the pointer is over this Sprite. + * @type {number} + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].y; + }; + Input.prototype.pointerDown = /** + * If the Pointer is touching the touchscreen, or the mouse button is held down, isDown is set to true + * @property isDown + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDown; + }; + Input.prototype.pointerUp = /** + * If the Pointer is not touching the touchscreen, or the mouse button is up, isUp is set to true + * @property isUp + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isUp; + }; + Input.prototype.pointerTimeDown = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeDown; + }; + Input.prototype.pointerTimeUp = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeUp; + }; + Input.prototype.pointerOver = /** + * Is the Pointer over this Sprite + * @property isOver + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOver; + }; + Input.prototype.pointerOut = /** + * Is the Pointer outside of this Sprite + * @property isOut + * @type {Boolean} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isOut; + }; + Input.prototype.pointerTimeOver = /** + * A timestamp representing when the Pointer first touched the touchscreen. + * @property timeDown + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOver; + }; + Input.prototype.pointerTimeOut = /** + * A timestamp representing when the Pointer left the touchscreen. + * @property timeUp + * @type {Number} + **/ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].timeOut; + }; + Input.prototype.pointerDragged = /** + * Is this sprite being dragged by the mouse or not? + * @default false + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + return this._pointerData[pointer].isDragged; + }; Input.prototype.update = /** * Update */ - function () { + function (pointer) { if(this.enabled == false) { return; } - if(this.draggable && this.isDragged) { - this.updateDrag(); + // If was previously touched by this Pointer, check if still is + if(this._pointerData[pointer.id].isDown && pointer.isUp) { + this._releasedHandler(pointer); } - if(this.game.input.x != this.oldX || this.game.input.y != this.oldY) { - this.oldX = this.game.input.x; - this.oldY = this.game.input.y; - if(Phaser.RectangleUtils.contains(this._sprite.frameBounds, this.game.input.x, this.game.input.y)) { - this.x = this.game.input.x - this._sprite.x; - this.y = this.game.input.y - this._sprite.y; - if(this.isOver == false) { - this.isOver = true; - this.isOut = false; - this.timeOver = this.game.time.now; - if(this.useHandCursor) { - this._sprite.game.stage.canvas.style.cursor = "pointer"; - } - this._sprite.events.onInputOver.dispatch(this._sprite, this.x, this.y, this.timeOver); + if(this.draggable && this._pointerData[pointer.id].isDragged) { + this.updateDrag(pointer); + //return; + } + 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"; } - } else { - if(this.isOver) { - this.isOver = false; - this.isOut = true; - this.timeOut = this.game.time.now; - if(this.useHandCursor) { - this._sprite.game.stage.canvas.style.cursor = "default"; - } - this._sprite.events.onInputOut.dispatch(this._sprite, this.timeOut); + this._sprite.events.onInputOver.dispatch(this._sprite, pointer); + } + } 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); } } }; + Input.prototype._touchedHandler = function (pointer) { + 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); + }; + Input.prototype._releasedHandler = function (pointer) { + this._pointerData[pointer.id].isDown = false; + this._pointerData[pointer.id].isUp = true; + this._pointerData[pointer.id].timeUp = this.game.time.now; + //this._pointerData[pointer.id].downDuration = this._pointerData[pointer.id].timeUp - this._pointerData[pointer.id].timeDown; + this._sprite.events.onInputDown.dispatch(this._sprite, pointer); + }; Input.prototype.updateDrag = /** - * Updates the Mouse Drag on this Sprite. + * Updates the Pointer drag on this Sprite. */ - function () { - if(this.isUp) { - this.stopDrag(); + function (pointer) { + if(pointer.isUp) { + this.stopDrag(pointer); return; } + // something wrong here, should use _dragPoint as well I think somehow if(this.allowHorizontalDrag) { - this._sprite.x = this.game.input.x - this.dragOffsetX; + this._sprite.x = pointer.x - this.dragOffset.x; } if(this.allowVerticalDrag) { - this._sprite.y = this.game.input.y - this.dragOffsetY; + this._sprite.y = pointer.y - this.dragOffset.y; } if(this.boundsRect) { this.checkBoundsRect(); @@ -5726,37 +5835,67 @@ var Phaser; * @param delay The time below which the pointer is considered as just over. * @returns {boolean} */ - function (delay) { + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } if (typeof delay === "undefined") { delay = 500; } - return (this.isOver && this.duration < delay); + return (this._pointerData[pointer].isOver && this.overDuration(pointer) < delay); }; Input.prototype.justOut = /** * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) * @param delay The time below which the pointer is considered as just out. * @returns {boolean} */ - function (delay) { + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } if (typeof delay === "undefined") { delay = 500; } - return (this.isOut && (this.game.time.now - this.timeOut < delay)); + return (this._pointerData[pointer].isOut && (this.game.time.now - this._pointerData[pointer].timeOut < delay)); + }; + Input.prototype.justPressed = /** + * Returns true if the pointer has entered the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just over. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isDown && this.downDuration(pointer) < delay); + }; + Input.prototype.justReleased = /** + * Returns true if the pointer has left the Sprite within the specified delay time (defaults to 500ms, half a second) + * @param delay The time below which the pointer is considered as just out. + * @returns {boolean} + */ + function (pointer, delay) { + if (typeof pointer === "undefined") { pointer = 0; } + if (typeof delay === "undefined") { delay = 500; } + return (this._pointerData[pointer].isUp && (this.game.time.now - this._pointerData[pointer].timeUp < delay)); + }; + Input.prototype.overDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isOver) { + return this.game.time.now - this._pointerData[pointer].timeOver; + } + return -1; + }; + Input.prototype.downDuration = /** + * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. + * @returns {number} The number of milliseconds the pointer has been pressed down on the Sprite, or -1 if not over. + */ + function (pointer) { + if (typeof pointer === "undefined") { pointer = 0; } + if(this._pointerData[pointer].isDown) { + return this.game.time.now - this._pointerData[pointer].timeDown; + } + return -1; }; - Object.defineProperty(Input.prototype, "duration", { - get: /** - * If the pointer is currently over this Sprite this returns how long it has been there for in milliseconds. - * @returns {number} The number of milliseconds the pointer has been over the Sprite, or -1 if not over. - */ - function () { - if(this.isOver) { - return this.game.time.now - this.timeOver; - } - return -1; - }, - enumerable: true, - configurable: true - }); Input.prototype.enableDrag = /** * Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback * - * @param lockCenter If false the Sprite will drag from where you click it. If true it will center itself to the tip of the mouse pointer. + * @param lockCenter If false the Sprite will drag from where you click it minus the dragOffset. If true it will center itself to the tip of the mouse pointer. * @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box. * @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255) * @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere @@ -5768,8 +5907,10 @@ var Phaser; if (typeof alphaThreshold === "undefined") { alphaThreshold = 255; } if (typeof boundsRect === "undefined") { boundsRect = null; } if (typeof boundsSprite === "undefined") { boundsSprite = null; } + this._dragPoint = new Phaser.Point(); this.draggable = true; - this.dragFromPoint = lockCenter; + this.dragOffset = new Phaser.Point(); + this.dragFromCenter = lockCenter; this.dragPixelPerfect = pixelPerfect; this.dragPixelPerfectAlpha = alphaThreshold; if(boundsRect) { @@ -5783,15 +5924,36 @@ var Phaser; * Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks. */ function () { - if(this.isDragged) { - //FlxMouseControl.dragTarget = null; - //FlxMouseControl.isDragging = false; - } - this.isDragged = false; + if(this._pointerData) { + for(var i = 0; i < 10; i++) { + this._pointerData[i].isDragged = false; + } + } this.draggable = false; //mouseStartDragCallback = null; //mouseStopDragCallback = null; }; + Input.prototype.startDrag = /** + * Called by Pointer when drag starts on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this._pointerData[pointer.id].isDragged = true; + if(this.dragFromCenter) { + // Move the sprite to the middle of the pointer + this.dragOffset.setTo(this._sprite.frameBounds.halfWidth, this._sprite.frameBounds.halfHeight); + } + this._dragPoint.setTo(pointer.x - this._sprite.x - this.dragOffset.x, pointer.y - this._sprite.y - this.dragOffset.y); + }; + Input.prototype.stopDrag = /** + * Called by Pointer when drag is stopped on this Sprite. Should not usually be called directly. + */ + function (pointer) { + this._pointerData[pointer.id].isDragged = false; + if(this.snapOnRelease) { + this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; + this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; + } + }; 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! * @@ -5828,20 +5990,6 @@ var Phaser; this.snapOnDrag = false; this.snapOnRelease = false; }; - Input.prototype.startDrag = /** - * Called by FlxMouseControl when Mouse Drag starts on this Sprite. Should not usually be called directly. - */ - function () { - this.isDragged = true; - if(this.dragFromPoint == false) { - this.dragOffsetX = this.game.input.x - this._sprite.x; - this.dragOffsetY = this.game.input.y - this._sprite.y; - } else { - // Move the sprite to the middle of the mouse - this.dragOffsetX = this._sprite.frameBounds.halfWidth; - this.dragOffsetY = this._sprite.frameBounds.halfHeight; - } - }; Input.prototype.checkBoundsRect = /** * Bounds Rect check for the sprite drag */ @@ -5872,16 +6020,6 @@ var Phaser; this._sprite.y = (this.boundsSprite.y + this.boundsSprite.height) - this._sprite.height; } }; - Input.prototype.stopDrag = /** - * Called by FlxMouseControl when Mouse Drag is stopped on this Sprite. Should not usually be called directly. - */ - function () { - this.isDragged = false; - if(this.snapOnRelease) { - this._sprite.x = Math.floor(this._sprite.x / this.snapX) * this.snapX; - this._sprite.y = Math.floor(this._sprite.y / this.snapY) * this.snapY; - } - }; Input.prototype.renderDebugInfo = /** * Render debug infos. (including name, bounds info, position and some other properties) * @param x {number} X position of the debug info to be rendered. @@ -5893,9 +6031,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.x.toFixed(1) + ' y: ' + this.y.toFixed(1), x, y + 14); - this._sprite.texture.context.fillText('over: ' + this.isOver + ' duration: ' + this.duration.toFixed(0), x, y + 28); - this._sprite.texture.context.fillText('just over: ' + this.justOver() + ' just out: ' + this.justOut(), x, y + 42); + 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); }; return Input; })(); @@ -6624,7 +6763,6 @@ var Phaser; } } */ - this.input.update(); if(this.modified == true && this.scale.equals(1) && this.skew.equals(0) && this.angle == 0 && this.angleOffset == 0 && this.texture.flippedX == false && this.texture.flippedY == false) { this.modified = false; } @@ -13280,7 +13418,7 @@ var Phaser; * @type {Number} **/ this.totalTouches = 0; - this._game = game; + this.game = game; this.id = id; this.active = false; this.position = new Phaser.Vec2(); @@ -13300,7 +13438,7 @@ var Phaser; if(this.isUp) { return -1; } - return this._game.time.now - this.timeDown; + return this.game.time.now - this.timeDown; }, enumerable: true, configurable: true @@ -13310,7 +13448,7 @@ var Phaser; * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this._game.camera; } + if (typeof camera === "undefined") { camera = this.game.camera; } return camera.worldView.x + this.x; }; Pointer.prototype.getWorldY = /** @@ -13318,7 +13456,7 @@ var Phaser; * @param {Camera} [camera] */ function (camera) { - if (typeof camera === "undefined") { camera = this._game.camera; } + if (typeof camera === "undefined") { camera = this.game.camera; } return camera.worldView.y + this.y; }; Pointer.prototype.start = /** @@ -13333,8 +13471,8 @@ var Phaser; this.button = event.button; } // Fix to stop rogue browser plugins from blocking the visibility state event - if(this._game.paused == true) { - this._game.stage.resumeGame(); + if(this.game.paused == true) { + this.game.stage.resumeGame(); return this; } this._history.length = 0; @@ -13344,38 +13482,57 @@ var Phaser; this.withinGame = true; this.isDown = true; this.isUp = false; - this.timeDown = this._game.time.now; + this.timeDown = this.game.time.now; this._holdSent = false; - 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; - this._game.input.onDown.dispatch(this); + 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; + this.game.input.onDown.dispatch(this); } this.totalTouches++; if(this.isMouse == false) { - this._game.input.currentPointers++; + this.game.input.currentPointers++; } return this; }; Pointer.prototype.update = function () { if(this.active) { - if(this._holdSent == false && this.duration >= this._game.input.holdRate) { - 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.onHold.dispatch(this); + if(this._holdSent == false && this.duration >= this.game.input.holdRate) { + 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.onHold.dispatch(this); } this._holdSent = true; } // Update the droppings history - if(this._game.input.recordPointerHistory && this._game.time.now >= this._nextDrop) { - this._nextDrop = this._game.time.now + this._game.input.recordRate; + if(this.game.input.recordPointerHistory && this.game.time.now >= this._nextDrop) { + this._nextDrop = this.game.time.now + this.game.input.recordRate; this._history.push({ x: this.position.x, y: this.position.y }); - if(this._history.length > this._game.input.recordLimit) { + if(this._history.length > this.game.input.recordLimit) { this._history.shift(); } } + // 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) { + this.game.input.inputObjects[i].input.update(this); + if(this.game.input.inputObjects[i].input.priorityID > _highestPriority) { + _highestPriority = this.game.input.inputObjects[i].input.priorityID; + } + } + } + if(this.isDown) { + // 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) { + this.game.input.inputObjects[i].input._touchedHandler(this); + } + } + } } }; Pointer.prototype.move = /** @@ -13393,17 +13550,17 @@ var Phaser; this.pageY = event.pageY; this.screenX = event.screenX; this.screenY = event.screenY; - this.x = this.pageX - this._game.stage.offset.x; - this.y = this.pageY - this._game.stage.offset.y; + this.x = this.pageX - this.game.stage.offset.x; + this.y = this.pageY - this.game.stage.offset.y; this.position.setTo(this.x, this.y); this.circle.x = this.x; this.circle.y = this.y; - 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; - this._game.input.position.setTo(this._game.input.x, this._game.input.y); - this._game.input.circle.x = this._game.input.x; - this._game.input.circle.y = this._game.input.y; + 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; + this.game.input.position.setTo(this.game.input.x, this.game.input.y); + this.game.input.circle.x = this.game.input.x; + this.game.input.circle.y = this.game.input.y; } return this; }; @@ -13422,28 +13579,31 @@ var Phaser; * @param {Any} event */ function (event) { - this.timeUp = this._game.time.now; - 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.onUp.dispatch(this); + this.timeUp = this.game.time.now; + 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.onUp.dispatch(this); // Was it a tap? - if(this.duration >= 0 && this.duration <= this._game.input.tapRate) { + if(this.duration >= 0 && this.duration <= this.game.input.tapRate) { // Was it a double-tap? - if(this.timeUp - this.previousTapTime < this._game.input.doubleTapRate) { + if(this.timeUp - this.previousTapTime < this.game.input.doubleTapRate) { // Yes, let's dispatch the signal then with the 2nd parameter set to true - this._game.input.onTap.dispatch(this, true); + this.game.input.onTap.dispatch(this, true); } else { // Wasn't a double-tap, so dispatch a single tap signal - this._game.input.onTap.dispatch(this, false); + this.game.input.onTap.dispatch(this, false); } this.previousTapTime = this.timeUp; } } - this.active = false; + // Mouse is always active + if(this.id > 0) { + this.active = false; + } this.withinGame = false; this.isDown = false; this.isUp = true; if(this.isMouse == false) { - this._game.input.currentPointers--; + this.game.input.currentPointers--; } return this; }; @@ -13454,8 +13614,8 @@ var Phaser; * @return {Boolean} */ function (duration) { - if (typeof duration === "undefined") { duration = this._game.input.justPressedRate; } - if(this.isDown === true && (this.timeDown + duration) > this._game.time.now) { + if (typeof duration === "undefined") { duration = this.game.input.justPressedRate; } + if(this.isDown === true && (this.timeDown + duration) > this.game.time.now) { return true; } else { return false; @@ -13468,8 +13628,8 @@ var Phaser; * @return {Boolean} */ function (duration) { - if (typeof duration === "undefined") { duration = this._game.input.justReleasedRate; } - if(this.isUp === true && (this.timeUp + duration) > this._game.time.now) { + if (typeof duration === "undefined") { duration = this.game.input.justReleasedRate; } + if(this.isUp === true && (this.timeUp + duration) > this.game.time.now) { return true; } else { return false; @@ -13497,30 +13657,30 @@ var Phaser; if(hideIfUp == true && this.isUp == true) { return; } - this._game.stage.context.beginPath(); - this._game.stage.context.arc(this.x, this.y, this.circle.radius, 0, Math.PI * 2); + this.game.stage.context.beginPath(); + this.game.stage.context.arc(this.x, this.y, this.circle.radius, 0, Math.PI * 2); if(this.active) { - this._game.stage.context.fillStyle = 'rgba(0,255,0,0.5)'; - this._game.stage.context.strokeStyle = 'rgb(0,255,0)'; + this.game.stage.context.fillStyle = 'rgba(0,255,0,0.5)'; + this.game.stage.context.strokeStyle = 'rgb(0,255,0)'; } else { - this._game.stage.context.fillStyle = 'rgba(255,0,0,0.5)'; - this._game.stage.context.strokeStyle = 'rgb(100,0,0)'; + this.game.stage.context.fillStyle = 'rgba(255,0,0,0.5)'; + this.game.stage.context.strokeStyle = 'rgb(100,0,0)'; } - this._game.stage.context.fill(); - this._game.stage.context.closePath(); + this.game.stage.context.fill(); + this.game.stage.context.closePath(); // Render the points - this._game.stage.context.beginPath(); - this._game.stage.context.moveTo(this.positionDown.x, this.positionDown.y); - this._game.stage.context.lineTo(this.position.x, this.position.y); - this._game.stage.context.lineWidth = 2; - this._game.stage.context.stroke(); - this._game.stage.context.closePath(); + this.game.stage.context.beginPath(); + this.game.stage.context.moveTo(this.positionDown.x, this.positionDown.y); + this.game.stage.context.lineTo(this.position.x, this.position.y); + this.game.stage.context.lineWidth = 2; + this.game.stage.context.stroke(); + this.game.stage.context.closePath(); // Render the text - this._game.stage.context.fillStyle = 'rgb(255,255,255)'; - this._game.stage.context.font = 'Arial 16px'; - this._game.stage.context.fillText('ID: ' + this.id + " Active: " + this.active, this.x, this.y - 100); - this._game.stage.context.fillText('Screen X: ' + this.x + " Screen Y: " + this.y, this.x, this.y - 80); - this._game.stage.context.fillText('Duration: ' + this.duration + " ms", this.x, this.y - 60); + this.game.stage.context.fillStyle = 'rgb(255,255,255)'; + this.game.stage.context.font = 'Arial 16px'; + this.game.stage.context.fillText('ID: ' + this.id + " Active: " + this.active, this.x, this.y - 100); + this.game.stage.context.fillText('Screen X: ' + this.x + " Screen Y: " + this.y, this.x, this.y - 80); + this.game.stage.context.fillText('Duration: ' + this.duration + " ms", this.x, this.y - 60); }; Pointer.prototype.toString = /** * Returns a string representation of this object. @@ -14329,6 +14489,8 @@ var Phaser; * @type {Pointer} **/ this.pointer10 = null; + this.inputObjects = []; + this.totalTrackedObjects = 0; this._game = game; this._stack = []; this.mousePointer = new Phaser.Pointer(this._game, 0); @@ -14426,12 +14588,24 @@ var Phaser; this.touch.start(); this.mspointer.start(); this.gestures.start(); + this.mousePointer.active = true; }; + Input.prototype.addGameObject = // Add Input Enabled array + add/remove methods and then iterate and update them during the main update + // Clear down this array on State swap??? Maybe removed from it when Sprite is destroyed + function (object) { + // Lots more checks here + this.inputObjects.push(object); + this.totalTrackedObjects++; + }; + Input.prototype.removeGameObject = function (object) { + // TODO + }; Input.prototype.update = /** * Updates the Input Manager. Called by the core Game loop. * @method update **/ function () { + // Swap for velocity vector - and add it to Pointer? this.speed.x = this.position.x - this._oldPosition.x; this.speed.y = this.position.y - this._oldPosition.y; this._oldPosition.copyFrom(this.position);