From 76040d303e44d73427e7edbc61b5bfb018f01d92 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Mon, 3 Mar 2014 01:42:11 +0000 Subject: [PATCH] Added in the Gestures support contribution for testing. --- Gruntfile.js | 1 + build/config.php | 1 + src/input/Gestures.js | 727 ++++++++++++++++++++++++++++++++++++++++++ src/input/Input.js | 57 ++-- 4 files changed, 762 insertions(+), 24 deletions(-) create mode 100644 src/input/Gestures.js diff --git a/Gruntfile.js b/Gruntfile.js index e54a95cb..49b4c4b5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -130,6 +130,7 @@ module.exports = function (grunt) { 'src/input/SinglePad.js', 'src/input/GamepadButton.js', 'src/input/InputHandler.js', + 'src/input/Gestures.js', 'src/gameobjects/Events.js', 'src/gameobjects/GameObjectFactory.js', diff --git a/build/config.php b/build/config.php index 9ae32cf6..48a11c59 100644 --- a/build/config.php +++ b/build/config.php @@ -85,6 +85,7 @@ + diff --git a/src/input/Gestures.js b/src/input/Gestures.js new file mode 100644 index 00000000..2ec5fa77 --- /dev/null +++ b/src/input/Gestures.js @@ -0,0 +1,727 @@ +/** +* @author Antony Woods +* @copyright 2013 Photon Storm Ltd. +* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} +*/ + +/** +* Phaser - Gestures constructor. +* +* @class Phaser.Gestures +* @classdesc An object for controlling the detection of global gestures. +* @constructor +* @param {Phaser.Game} game - A reference to the currently running game. +*/ +Phaser.Gestures = function (game) { + + /** + * @property {Phaser.Game} game - A reference to the currently running game. + */ + this.game = game; + + /** + * @property {boolean} active - If true, the Gestures class will attempt to detect gestures + * @default + */ + this.active = false; + + /** + * @property {Array} _gestures - A list of gestures that we're currently tracking. + * @default + */ + this._gestures = []; + + /** + * @property {Array} _pointers - A list of of pointers that are in the process of being detected + * @default + */ + this._pointers = []; + + /** + * Update pointer state + */ + this.game.input.setMoveCallback(function (pointer) { + + if (this.active) + { + this._updatePointerState(pointer); + } + }, this); + +}; + +Phaser.Gestures.prototype = { + + /** + * Add a new pointer and gesture type to the detection system + * @method Phaser.Gestures#add + * @param {Phaser.Gestures} gesture - a gesture that we wish to detect (i.e. Phaser.Gesture.SwipeLeft) + * @param {function} onGestureUpdated - a callback for when the gesture updates (returns with valid data) + */ + add: function (gesture, onGestureUpdated) { + + this.add(gesture, onGestureUpdated, null, null); + + }, + + /** + * Add a new pointer and gesture type to the detection system + * @method Phaser.Gestures#add + * @param {Phaser.Gestures} gesture - a gesture that we wish to detect (i.e. Phaser.Gesture.SwipeLeft) + * @param {function} onGestureUpdated - a callback for when the gesture updates (returns with valid data) + * @param {function} onGestureStarted - a callback for when the gesture starts (begins detection) + * @param {function} onGestureStopped - a callback for when the gesture stops (ends detection) + */ + add: function (gesture, onGestureUpdated, onGestureStarted, onGestureStopped) { + + var gestureObject = { + gesture: new gesture(), + hasStarted: false, + onGestureStarted: onGestureStarted, + onGestureUpdated: onGestureUpdated, + onGestureStopped: onGestureStopped, + } + + this._gestures.push(gestureObject); + + }, + + /** + * Remove a pointer and gesture combination from the detection system + * @method Phaser.Gestures#remove + * @param {Phaser.Gestures} gesture - a gesture that we no longer wish to detect (i.e. Phaser.Gesture.SwipeLeft) + */ + remove: function (gesture) { + + for(var i = this._gestures.length - 1; i >= 0; --i) + { + if(this._gestures[i].gesture.name == new gesture().name) + { + delete this._gestures[i]; + } + } + this._gestures = this._gestures.filter(function(a){return typeof a !== 'undefined';}); + }, + + /** + * Update function, called whenever a pointer triggers an event. + * @method Phaser.Gestures#update + */ + update: function () { + + if(this.active && this._pointers.length > 0) + { + var hasPointers = this._pointers.filter(function(p){return p.isDown;}).length > 0; + for(var i = this._gestures.length - 1; i >= 0; --i) + { + if(!this._gestures[i].hasStarted) + { + this._gestures[i].hasStarted = true; + this._gestures[i].gesture.start(this._pointers); + if(this._gestures[i].onGestureStarted != null) + { + this._gestures[i].onGestureStarted(); + } + } + else + { + var result = this._gestures[i].gesture.update(this._pointers); + if(result){ + var data = this._gestures[i].gesture.getData(); + if(this._gestures[i].onGestureUpdated != null) + { + this._gestures[i].onGestureUpdated(data); + } + } + if(!hasPointers) + { + this._gestures[i].gesture.stop(this._pointers); + this._gestures[i].hasStarted = false; + if(this._gestures[i].onGestureStopped != null) + { + this._gestures[i].onGestureStopped(); + } + } + } + } + + this._pointers = this._pointers.filter(function(p){return p.isDown;}); + } + }, + + /** + * Updates internal pointer state + * @method Phaser.Gestures#update + * @param {Phaser.Pointer} pointer - the pointer that triggered this update + */ + _updatePointerState: function (pointer) { + + var pointerObject = null; + for(var i = this._pointers.length - 1; i >= 0; --i) + { + if(this._pointers[i].pointer == pointer) + { + pointerObject = this._pointers[i]; + break; + } + } + + if(pointerObject == null && pointer.isDown) + { + pointerObject = { + pointer:pointer, + justPressed:true, + isUp:false, + isDown:true + } + this._pointers.push(pointerObject); + } + else if(pointerObject != null) + { + pointerObject.justPressed = false; + pointerObject.isDown = pointer.isDown; + pointerObject.isUp = pointer.isUp; + } + } +}; + +Phaser.Gestures.prototype.constructor = Phaser.Gestures; + +/* ---------------------------------------- */ + +Phaser.Gestures.Helpers = { + + /** + * Finds or creates a local 'pointer' object from a given array + * + * @method Phaser.Gestures.Helpers#createOrFindPointerData + * @param {Array} - an array of objects that expose 'pointer' as a field. + * @param {Phaser.Point} - the pointer object we're attempting to find. + */ + createOrFindPointerData: function(pointerArray, pointer) { + + var pointerObject = null; + for(var i = pointerArray.length - 1; i >= 0; --i) + { + if(pointerArray[i].pointer == pointer) + { + pointerObject = pointerArray[i]; + break; + } + } + if(pointerObject == null) + { + pointerObject = { + pointer:pointer, + isNew: true + } + pointerArray.push(pointerObject); + } + return pointerObject; + } +}; + +Phaser.Gesture = {}; + +/** +* Swipe-Left detection +* +* @class Phaser.Gesture.SwipeLeft +*/ +Phaser.Gesture.SwipeLeft = function (game) { + + /** + * @property {Phaser.Game} game - A reference to the currently running game. + */ + this.game = game; + + /** + * @property {String} - the name of the gesture + * @default + */ + this.name = "SwipeLeft"; + + /** + * @property {Array} _deltaXPerPointer - A list of delta X value for each pointer. + * @default + */ + this._pointerData = []; + +}; + +Phaser.Gesture.SwipeLeft.prototype = { + + /** + * Find a pointer data object using the helper + * + * @method Phaser.Gesture.SwipeLeft#_createOrFindPointerData + * @param {Phaser.Pointer} - the pointer for which we want to retrieve data + */ + _createOrFindPointerData: function (pointer) { + + var ptrObject = Phaser.Gestures.Helpers.createOrFindPointerData(this._pointerData, pointer); + + if (ptrObject.isNew) + { + ptrObject.isNew = false; + ptrObject.lastX = pointer.pointer.x; + ptrObject.lastY = pointer.pointer.y; + ptrObject.hasTriggered = false; + } + + return ptrObject; + + }, + + /** + * Start detection process for gesture, called when a pointer touches the screen + * + * @method Phaser.Gesture.SwipeLeft#update + * @param {Array} - an array to all the current pointers + */ + start: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + this._createOrFindPointerData(pointers[i]); + } + + }, + + /** + * Update during the detection of a gesture, called when a pointer moves + * + * @method Phaser.Gesture.SwipeLeft#update + * @param {Array} - an array to all the current pointers + * @returns {boolean} True, if the gesture has been detected and can return some tangible information. + */ + update: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + var ptrObject = this._createOrFindPointerData(pointers[i]); + + if (ptrObject.pointer.isDown && !ptrObject.hasTriggered) + { + var currentX = pointers[i].pointer.x; + var deltaX = ptrObject.lastX - currentX; + + ptrObject.lastX = currentX; + + if (deltaX > 100) + { + ptrObject.hasTriggered = true; + return true; + } + } + } + + return false + + }, + + /** + * Stop detection process for gesture, called when a pointer leaves the screen + * + * @method Phaser.Gesture.SwipeLeft#update + * @param {Array} - an array to all the current pointers + */ + stop: function (pointers) { + + this._pointerData = []; + + }, + + /** + * Fetches the current relevant data for this gesture + * + * @method Phaser.Gesture.SwipeLeft#getData + * @returns {object} an object with data relating to the current state of this gesture + */ + getData: function () { + + return { didSwipe: true }; + + } + +} + +Phaser.Gesture.SwipeLeft.prototype.constructor = Phaser.Gesture.SwipeLeft; + +/** +* Swipe-Right detection +* +* @class Phaser.Gesture.SwipeRight +*/ +Phaser.Gesture.SwipeRight = function (game) { + + /** + * @property {Phaser.Game} game - A reference to the currently running game. + */ + this.game = game; + + /** + * @property {String} - the name of the gesture + * @default + */ + this.name = "SwipeRight"; + + /** + * @property {Array} _pointerData - A pointer data array. + * @default + */ + this._pointerData = []; + +}; + +Phaser.Gesture.SwipeRight.prototype = { + + /** + * Find a pointer data object using the helper + * + * @method Phaser.Gesture.SwipeRight#_createOrFindPointerData + * @private + * @param {Phaser.Pointer} - the pointer for which we want to retrieve data + */ + _createOrFindPointerData: function(pointer) { + + var ptrObject = Phaser.Gestures.Helpers.createOrFindPointerData(this._pointerData, pointer); + + if (ptrObject.isNew) + { + ptrObject.isNew = false; + ptrObject.lastX = pointer.pointer.x; + ptrObject.lastY = pointer.pointer.y; + ptrObject.hasTriggered = false; + } + + return ptrObject; + + }, + + /** + * Start detection process for gesture, called when a pointer touches the screen + * + * @method Phaser.Gesture.SwipeRight#update + * @param {Array} - an array to all the current pointers + */ + start: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + this._createOrFindPointerData(pointers[i]); + } + + }, + + /** + * Update during the detection of a gesture, called when a pointer moves + * + * @method Phaser.Gesture.SwipeRight#update + * @param {Array} - an array to all the current pointers + * @returns {boolean} True, if the gesture has been detected and can return some tangible information. + */ + update: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + var ptrObject = this._createOrFindPointerData(pointers[i]); + + if (ptrObject.pointer.isDown && !ptrObject.hasTriggered) + { + var currentX = pointers[i].pointer.x; + var deltaX = ptrObject.lastX - currentX; + + ptrObject.lastX = currentX; + + if (deltaX < -100) + { + ptrObject.hasTriggered = true; + return true; + } + } + } + + return false + + }, + + /** + * Stop detection process for gesture, called when a pointer leaves the screen + * + * @method Phaser.Gesture.SwipeRight#update + * @param {Array} - an array to all the current pointers + */ + stop: function (pointers) { + + this._pointerData = []; + + }, + + /** + * Fetches the current relevant data for this gesture + * + * @method Phaser.Gesture.SwipeRight#getData + * @returns {object} an object with data relating to the current state of this gesture + */ + getData: function () { + + return { didSwipe: true }; + + } + +} + +Phaser.Gesture.SwipeRight.prototype.constructor = Phaser.Gesture.SwipeRight; + +/** +* Swipe-Down detection +* +* @class Phaser.Gesture.SwipeDown +*/ +Phaser.Gesture.SwipeDown = function (game) { + + /** + * @property {Phaser.Game} game - A reference to the currently running game. + */ + this.game = game; + + /** + * @property {String} - the name of the gesture + * @default + */ + this.name = "SwipeDown"; + + /** + * @property {Array} _pointerData - Array of pointer data. + * @default + */ + this._pointerData = []; + +}; + +Phaser.Gesture.SwipeDown.prototype = { + + /** + * Find a pointer data object using the helper + * + * @method Phaser.Gesture.SwipeDown#_createOrFindPointerData + * @private + * @param {Phaser.Pointer} - the pointer for which we want to retrieve data + */ + _createOrFindPointerData: function (pointer) { + + var ptrObject = Phaser.Gestures.Helpers.createOrFindPointerData(this._pointerData, pointer); + + if (ptrObject.isNew) + { + ptrObject.isNew = false; + ptrObject.lastX = pointer.pointer.x; + ptrObject.lastY = pointer.pointer.y; + ptrObject.hasTriggered = false; + } + + return ptrObject; + + }, + + /** + * Start detection process for gesture, called when a pointer touches the screen + * + * @method Phaser.Gesture.SwipeDown#update + * @param {Array} - an array to all the current pointers + */ + start: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + this._createOrFindPointerData(pointers[i]); + } + + }, + + /** + * Update during the detection of a gesture, called when a pointer moves + * + * @method Phaser.Gesture.SwipeDown#update + * @param {Array} - an array to all the current pointers + * @returns {boolean} True, if the gesture has been detected and can return some tangible information. + */ + update: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + var ptrObject = this._createOrFindPointerData(pointers[i]); + + if (ptrObject.pointer.isDown && !ptrObject.hasTriggered) + { + var currentY = pointers[i].pointer.y; + var deltaY = ptrObject.lastY - currentY; + + ptrObject.lastY = currentY; + + if (deltaY < -100) + { + ptrObject.hasTriggered = true; + return true; + } + } + } + + return false + + }, + + /** + * Stop detection process for gesture, called when a pointer leaves the screen + * + * @method Phaser.Gesture.SwipeDown#update + * @param {Array} pointers - an array to all the current pointers + */ + stop: function (pointers) { + + this._pointerData = []; + + }, + + /** + * Fetches the current relevant data for this gesture + * + * @method Phaser.Gesture.SwipeDown#getData + * @returns {object} an object with data relating to the current state of this gesture + */ + getData: function ( ) { + + return { didSwipe: true }; + + } + +} + +Phaser.Gesture.SwipeDown.prototype.constructor = Phaser.Gesture.SwipeDown; + +/** +* Swipe-Up detection +* +* @class Phaser.Gesture.SwipeUp +*/ +Phaser.Gesture.SwipeUp = function (game) { + + /** + * @property {Phaser.Game} game - A reference to the currently running game. + */ + this.game = game; + + /** + * @property {String} - the name of the gesture + * @default + */ + this.name = "SwipeUp"; + + /** + * @property {Array} _pointerData - Array of pointer data. + * @default + */ + this._pointerData = []; + +}; + +Phaser.Gesture.SwipeUp.prototype = { + + /** + * Find a pointer data object using the helper + * + * @method Phaser.Gesture.SwipeUp#_createOrFindPointerData + * @private + * @param {Phaser.Pointer} - the pointer for which we want to retrieve data + */ + _createOrFindPointerData: function (pointer) { + + var ptrObject = Phaser.Gestures.Helpers.createOrFindPointerData(this._pointerData, pointer); + + if (ptrObject.isNew) + { + ptrObject.isNew = false; + ptrObject.lastX = pointer.pointer.x; + ptrObject.lastY = pointer.pointer.y; + ptrObject.hasTriggered = false; + } + + return ptrObject; + + }, + + /** + * Start detection process for gesture, called when a pointer touches the screen + * + * @method Phaser.Gesture.SwipeUp#update + * @param {Array} - an array to all the current pointers + */ + start: function (pointers) { + + for (var i = pointers.length - 1; i >=0; --i) + { + this._createOrFindPointerData(pointers[i]); + } + + }, + + /** + * Update during the detection of a gesture, called when a pointer moves + * + * @method Phaser.Gesture.SwipeUp#update + * @param {Array} - an array to all the current pointers + * @returns {boolean} True, if the gesture has been detected and can return some tangible information. + */ + update: function ( pointers ) { + + for (var i = pointers.length - 1; i >=0; --i) + { + var ptrObject = this._createOrFindPointerData(pointers[i]); + + if (ptrObject.pointer.isDown && !ptrObject.hasTriggered) + { + var currentY = pointers[i].pointer.y; + var deltaY = ptrObject.lastY - currentY; + + ptrObject.lastY = currentY; + + if (deltaY > 100) + { + ptrObject.hasTriggered = true; + return true; + } + } + } + + return false + + }, + + /** + * Stop detection process for gesture, called when a pointer leaves the screen + * + * @method Phaser.Gesture.SwipeUp#update + * @param {Array} - an array to all the current pointers + */ + stop: function (pointers) { + + this._pointerData = []; + + }, + + /** + * Fetches the current relevant data for this gesture + * + * @method Phaser.Gesture.SwipeUp#getData + * @returns {object} an object with data relating to the current state of this gesture + */ + getData: function () { + + return { didSwipe: true }; + + } + +} + +Phaser.Gesture.SwipeUp.prototype.constructor = Phaser.Gesture.SwipeUp; diff --git a/src/input/Input.js b/src/input/Input.js index 129de263..164265cd 100644 --- a/src/input/Input.js +++ b/src/input/Input.js @@ -46,30 +46,6 @@ Phaser.Input = function (game) { * @default */ this.pollRate = 0; - - /** - * @property {number} _pollCounter - Internal var holding the current poll counter. - * @private - */ - this._pollCounter = 0; - - /** - * @property {Phaser.Point} _oldPosition - A point object representing the previous position of the Pointer. - * @private - */ - this._oldPosition = null; - - /** - * @property {number} _x - x coordinate of the most recent Pointer event - * @private - */ - this._x = 0; - - /** - * @property {number} _y - Y coordinate of the most recent Pointer event - * @private - */ - this._y = 0; /** * You can disable all Input by setting Input.disabled = true. While set all new input related events will be ignored. @@ -260,6 +236,11 @@ Phaser.Input = function (game) { */ this.gamepad = null; + /** + * @property {Phaser.Gestures} gestures - The Gestures manager. + */ + this.gestures = null; + /** * @property {Phaser.Signal} onDown - A Signal that is dispatched each time a pointer is pressed down. */ @@ -292,6 +273,30 @@ Phaser.Input = function (game) { */ this._localPoint = new Phaser.Point(); + /** + * @property {number} _pollCounter - Internal var holding the current poll counter. + * @private + */ + this._pollCounter = 0; + + /** + * @property {Phaser.Point} _oldPosition - A point object representing the previous position of the Pointer. + * @private + */ + this._oldPosition = null; + + /** + * @property {number} _x - x coordinate of the most recent Pointer event + * @private + */ + this._x = 0; + + /** + * @property {number} _y - Y coordinate of the most recent Pointer event + * @private + */ + this._y = 0; + }; /** @@ -330,6 +335,7 @@ Phaser.Input.prototype = { this.touch = new Phaser.Touch(this.game); this.mspointer = new Phaser.MSPointer(this.game); this.gamepad = new Phaser.Gamepad(this.game); + this.gestures = new Phaser.Gestures(this.game); this.onDown = new Phaser.Signal(); this.onUp = new Phaser.Signal(); @@ -370,6 +376,7 @@ Phaser.Input.prototype = { this.touch.stop(); this.mspointer.stop(); this.gamepad.stop(); + this.gestures.stop(); this.moveCallback = null; @@ -458,6 +465,8 @@ Phaser.Input.prototype = { this._pollCounter = 0; + if (this.gestures.active) { this.gestures.update(); } + }, /**