diff --git a/v3/src/boot/Game.js b/v3/src/boot/Game.js index 08c0db35d..7b92dc360 100644 --- a/v3/src/boot/Game.js +++ b/v3/src/boot/Game.js @@ -14,7 +14,7 @@ var AnimationManager = require('../animation/manager/AnimationManager'); var CreateRenderer = require('./CreateRenderer'); var Data = require('../plugins/Data'); var GlobalCache = require('../cache/GlobalCache'); -var GlobalInputManager = require('../input/GlobalInputManager'); +var GlobalInputManager = require('../input/global/GlobalInputManager'); var GlobalSceneManager = require('../scene/GlobalSceneManager'); var TextureManager = require('../textures/TextureManager'); var TimeStep = require('./TimeStep'); diff --git a/v3/src/checksum.js b/v3/src/checksum.js index c6f5085db..42f4951e5 100644 --- a/v3/src/checksum.js +++ b/v3/src/checksum.js @@ -1,4 +1,4 @@ var CHECKSUM = { -build: '668ff4c0-6d49-11e7-a9ff-d120a05f4baf' +build: 'a59b1ca0-6d65-11e7-9e25-f9ff7de73fa8' }; module.exports = CHECKSUM; \ No newline at end of file diff --git a/v3/src/input/InteractiveObject.js b/v3/src/input/InteractiveObject.js index 3dc5effbd..22ba8e510 100644 --- a/v3/src/input/InteractiveObject.js +++ b/v3/src/input/InteractiveObject.js @@ -20,6 +20,9 @@ var InteractiveObject = function (gameObject, hitArea, hitAreaCallback) isDown: false, isDragged: false, + pointersOver: [], + pointersDown: [], + callbackContext: gameObject, onDown: NOOP, diff --git a/v3/src/input/const.js b/v3/src/input/const.js deleted file mode 100644 index a86e48970..000000000 --- a/v3/src/input/const.js +++ /dev/null @@ -1,8 +0,0 @@ -var INPUT_CONST = { - - ALL: 0, - TOP: 1 - -}; - -module.exports = INPUT_CONST; diff --git a/v3/src/input/GlobalInputManager.js b/v3/src/input/global/GlobalInputManager.js similarity index 91% rename from v3/src/input/GlobalInputManager.js rename to v3/src/input/global/GlobalInputManager.js index 025de0608..f1ef1fa9e 100644 --- a/v3/src/input/GlobalInputManager.js +++ b/v3/src/input/global/GlobalInputManager.js @@ -1,16 +1,16 @@ // Phaser.Input.GlobalInputManager -var Class = require('../utils/Class'); -var EventDispatcher = require('../events/EventDispatcher'); +var Class = require('../../utils/Class'); +var EventDispatcher = require('../../events/EventDispatcher'); var GetTransformedPoint = require('./components/GetTransformedPoint'); -var Keyboard = require('./keyboard/KeyboardManager'); -var Mouse = require('./mouse/MouseManager'); -var MouseEvent = require('./mouse/events/'); -var Pointer = require('./Pointer'); +var Keyboard = require('../keyboard/KeyboardManager'); +var Mouse = require('../mouse/MouseManager'); +var MouseEvent = require('../mouse/events/'); +var Pointer = require('../Pointer'); var PointScreenToWorldHitTest = require('./components/PointScreenToWorldHitTest'); var HitTest = require('./components/HitTest'); var PointWithinGameObject = require('./components/PointWithinGameObject'); -var TransformMatrix = require('../gameobjects/components/TransformMatrix'); +var TransformMatrix = require('../../gameobjects/components/TransformMatrix'); var GlobalInputManager = new Class({ diff --git a/v3/src/input/components/GetTransformedPoint.js b/v3/src/input/global/components/GetTransformedPoint.js similarity index 100% rename from v3/src/input/components/GetTransformedPoint.js rename to v3/src/input/global/components/GetTransformedPoint.js diff --git a/v3/src/input/components/HitTest.js b/v3/src/input/global/components/HitTest.js similarity index 100% rename from v3/src/input/components/HitTest.js rename to v3/src/input/global/components/HitTest.js diff --git a/v3/src/input/components/PointScreenToWorldHitTest.js b/v3/src/input/global/components/PointScreenToWorldHitTest.js similarity index 100% rename from v3/src/input/components/PointScreenToWorldHitTest.js rename to v3/src/input/global/components/PointScreenToWorldHitTest.js diff --git a/v3/src/input/components/PointWithinGameObject.js b/v3/src/input/global/components/PointWithinGameObject.js similarity index 100% rename from v3/src/input/components/PointWithinGameObject.js rename to v3/src/input/global/components/PointWithinGameObject.js diff --git a/v3/src/input/components/PointWithinHitArea.js b/v3/src/input/global/components/PointWithinHitArea.js similarity index 100% rename from v3/src/input/components/PointWithinHitArea.js rename to v3/src/input/global/components/PointWithinHitArea.js diff --git a/v3/src/input/components/PointWithinInteractiveObject.js b/v3/src/input/global/components/PointWithinInteractiveObject.js similarity index 100% rename from v3/src/input/components/PointWithinInteractiveObject.js rename to v3/src/input/global/components/PointWithinInteractiveObject.js diff --git a/v3/src/input/index.js b/v3/src/input/index.js index edb66fffe..a4bf2cb45 100644 --- a/v3/src/input/index.js +++ b/v3/src/input/index.js @@ -2,10 +2,6 @@ module.exports = { - // CONSTs (makes them visible under Phaser.Input) - RETURN_ALL: 0, - RETURN_TOP: 1, - Keyboard: require('./keyboard'), Mouse: require('./mouse') diff --git a/v3/src/input/local/SceneInputManager.js b/v3/src/input/local/SceneInputManager.js new file mode 100644 index 000000000..dea6a7c8b --- /dev/null +++ b/v3/src/input/local/SceneInputManager.js @@ -0,0 +1,113 @@ +var Class = require('../../utils/Class'); + +// Drag Events +// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API + +var SceneInputManager = new Class({ + + initialize: + + function SceneInputManager (scene, game) + { + // The Scene that owns this plugin + this.scene = scene; + + // GlobalInputManager + this.manager = game.input; + + // A reference to this.scene.sys.displayList (set in boot) + this.displayList; + + // A reference to the this.scene.sys.cameras.cameras array (set in boot) + this.cameras; + + // Should use Scene event dispatcher? + this.events = this.manager.events; + + // this.keyboard = this.manager.keyboard; + // this.mouse = this.manager.mouse; + + // Only fire *callbacks* on the top-most Game Object in the display list (emulating DOM behavior) + // and ignoring any GOs below it, or call them all? + + this.topOnly = true; + + // How often should the pointer input be checked? + // Time given in ms + // Pointer will *always* be checked if it has been moved by the user. + // This controls how often it will be polled if it hasn't been moved. + // Set to 0 to poll constantly. Set to -1 to only poll on user movement. + this.pollRate = -1; + + this._pollTimer = 0; + + this._size = 0; + + // All list of all Interactive Objects + this._list = []; + + // Objects waiting to be inserted or removed from the active list + this._pendingInsertion = []; + this._pendingRemoval = []; + + // A list of Interactive Objects which are *currently* below a pointer (any pointer) during the previous frame + this._over = []; + + // Only Game Objects which have been flagged as draggable are added to this array + this._draggable = []; + + this._validTypes = [ 'onDown', 'onUp', 'onOver', 'onOut' ]; + }, + + boot: require('./components/Boot'), + begin: require('./components/Begin'), + update: require('./components/Update'), + hitTestPointer: require('./components/HitTestPointer'), + + setpollRate: require('./components/SetPollRate'), + setpollAlways: require('./components/SetPollAlways'), + setpollOnMove: require('./components/SetPollOnMove'), + + setHitArea: require('./components/SetHitArea'), + setHitAreaCircle: require('./components/SetHitAreaCircle'), + setHitAreaEllipse: require('./components/SetHitAreaEllipse'), + setHitAreaFromTexture: require('./components/SetHitAreaFromTexture'), + setHitAreaRectangle: require('./components/SetHitAreaRectangle'), + setHitAreaTriangle: require('./components/SetHitAreaTriangle'), + + setCallback: require('./components/SetCallback'), + setCallbacks: require('./components/SetCallbacks'), + setOnDownCallback: require('./components/SetOnDownCallback'), + setOnOutCallback: require('./components/SetOnOutCallback'), + setOnOverCallback: require('./components/SetOnOverCallback'), + setOnUpCallback: require('./components/SetOnUpCallback'), + + queueForInsertion: require('./components/QueueForInsertion'), + queueForRemoval: require('./components/QueueForRemoval'), + + // Scene that owns this is shutting down + shutdown: function () + { + this._list = []; + this._over = []; + this._draggable = []; + this._pendingRemoval = []; + this._pendingInsertion = []; + }, + + // Game level nuke + destroy: function () + { + this.shutdown(); + + this.scene = undefined; + this.cameras = undefined; + this.manager = undefined; + this.events = undefined; + this.keyboard = undefined; + this.mouse = undefined; + } + +}); + +module.exports = SceneInputManager; diff --git a/v3/src/input/local/components/Begin.js b/v3/src/input/local/components/Begin.js new file mode 100644 index 000000000..bbd3e79af --- /dev/null +++ b/v3/src/input/local/components/Begin.js @@ -0,0 +1,48 @@ +var Begin = function () +{ + var toRemove = this._pendingRemoval.length; + var toInsert = this._pendingInsertion.length; + + if (toRemove === 0 && toInsert === 0) + { + // Quick bail + return; + } + + var i; + var gameObject; + + // Delete old gameObjects + for (i = 0; i < toRemove; i++) + { + gameObject = this._pendingRemoval[i]; + + var index = this._list.indexOf(gameObject); + + if (index > -1) + { + this._list.splice(index, 1); + + gameObject.input = null; + } + } + + // Move pending to active (can swap for concat splice if we don't need anything extra here) + + for (i = 0; i < toInsert; i++) + { + gameObject = this._pendingInsertion[i]; + + // Swap for Input Enabled Object + this._list.push(gameObject); + } + + this._size = this._list.length; + + // Clear the lists + this._pendingRemoval.length = 0; + this._pendingInsertion.length = 0; +}; + +module.exports = Begin; + diff --git a/v3/src/input/local/components/Boot.js b/v3/src/input/local/components/Boot.js new file mode 100644 index 000000000..4198e6842 --- /dev/null +++ b/v3/src/input/local/components/Boot.js @@ -0,0 +1,8 @@ +var Boot = function () +{ + this.cameras = this.scene.sys.cameras.cameras; + + this.displayList = this.scene.sys.displayList; +}; + +module.exports = Boot; diff --git a/v3/src/input/local/components/Disable.js b/v3/src/input/local/components/Disable.js new file mode 100644 index 000000000..e604fe7e0 --- /dev/null +++ b/v3/src/input/local/components/Disable.js @@ -0,0 +1,6 @@ +var Disable = function (gameObject) +{ + gameObject.input.enabled = false; +}; + +module.exports = Disable; diff --git a/v3/src/input/local/components/Enable.js b/v3/src/input/local/components/Enable.js new file mode 100644 index 000000000..07355a165 --- /dev/null +++ b/v3/src/input/local/components/Enable.js @@ -0,0 +1,17 @@ +var Enable = function (gameObject, shape, callback) +{ + if (gameObject.input) + { + // If it is already has an InteractiveObject then just enable it and return + gameObject.input.enabled = true; + } + else + { + // Create an InteractiveObject and enable it + this.setHitArea(gameObject, shape, callback); + } + + return this; +}; + +module.exports = Enable; diff --git a/v3/src/input/local/components/HitTestPointer.js b/v3/src/input/local/components/HitTestPointer.js new file mode 100644 index 000000000..d954d8a09 --- /dev/null +++ b/v3/src/input/local/components/HitTestPointer.js @@ -0,0 +1,20 @@ +var HitTestPointer = function (pointer) +{ + var output = []; + + // Get a list of all objects that can be seen by all the cameras in the scene and store in 'tested' array. + // All objects in this array are input enabled, as checked by the hitTest function, so we don't need to check later on as well. + for (var i = 0; i < this.cameras.length; i++) + { + var camera = this.cameras[i]; + + if (camera.inputEnabled) + { + output = output.concat(this.manager.hitTest(this._list, pointer.x, pointer.y, camera)); + } + } + + return output; +}; + +module.exports = HitTestPointer; diff --git a/v3/src/input/local/components/QueueForInsertion.js b/v3/src/input/local/components/QueueForInsertion.js new file mode 100644 index 000000000..b6634c614 --- /dev/null +++ b/v3/src/input/local/components/QueueForInsertion.js @@ -0,0 +1,12 @@ +// Queues a Game Object for insertion into this Input Manager on the next update. +var QueueForInsertion = function (child) +{ + if (this._pendingInsertion.indexOf(child) === -1 && this._list.indexOf(child) === -1) + { + this._pendingInsertion.push(child); + } + + return this; +}; + +module.exports = QueueForInsertion; diff --git a/v3/src/input/local/components/QueueForRemoval.js b/v3/src/input/local/components/QueueForRemoval.js new file mode 100644 index 000000000..6bf5dc65f --- /dev/null +++ b/v3/src/input/local/components/QueueForRemoval.js @@ -0,0 +1,9 @@ +// Queues a Game Object for removal from this Input Manager on the next update. +var QueueForRemoval = function (child) +{ + this._pendingRemoval.push(child); + + return this; +}; + +module.exports = QueueForRemoval; diff --git a/v3/src/input/local/components/SetCallback.js b/v3/src/input/local/components/SetCallback.js new file mode 100644 index 000000000..63dea2a78 --- /dev/null +++ b/v3/src/input/local/components/SetCallback.js @@ -0,0 +1,31 @@ +var SetCallback = function (gameObjects, type, callback, context) +{ + if (this._validTypes.indexOf(type) === -1) + { + return this; + } + + if (!Array.isArray(gameObjects)) + { + gameObjects = [ gameObjects ]; + } + + for (var i = 0; i < gameObjects.length; i++) + { + var gameObject = gameObjects[i]; + + if (gameObject.input) + { + gameObject.input[type] = callback; + + if (context) + { + gameObject.input.callbackContext = context; + } + } + } + + return this; +}; + +module.exports = SetCallback; diff --git a/v3/src/input/local/components/SetCallbacks.js b/v3/src/input/local/components/SetCallbacks.js new file mode 100644 index 000000000..cb95e6920 --- /dev/null +++ b/v3/src/input/local/components/SetCallbacks.js @@ -0,0 +1,26 @@ +var SetCallbacks = function (gameObjects, onDown, onUp, onOver, onOut, context) +{ + if (onDown) + { + this.setOnDownCallback(gameObjects, onDown, context); + } + + if (onUp) + { + this.setOnDownCallback(gameObjects, onUp, context); + } + + if (onOver) + { + this.setOnDownCallback(gameObjects, onOver, context); + } + + if (onOut) + { + this.setOnDownCallback(gameObjects, onOut, context); + } + + return this; +}; + +module.exports = SetCallbacks; diff --git a/v3/src/input/local/components/SetDraggable.js b/v3/src/input/local/components/SetDraggable.js new file mode 100644 index 000000000..4adcab082 --- /dev/null +++ b/v3/src/input/local/components/SetDraggable.js @@ -0,0 +1,40 @@ +var SetDraggable = function (gameObjects, value) +{ + if (value === undefined) { value = true; } + + if (!Array.isArray(gameObjects)) + { + gameObjects = [ gameObjects ]; + } + + for (var i = 0; i < gameObjects.length; i++) + { + var gameObject = gameObjects[i]; + var index = this._draggable.indexOf(gameObject); + + if (value) + { + // Make draggable + gameObject.input.draggable = true; + + if (index === -1) + { + this._draggable.push(gameObject); + } + } + else + { + // Disable drag + gameObject.input.draggable = false; + + if (index === -1) + { + this._draggable.splice(index, 1); + } + } + } + + return true; +}; + +module.exports = SetDraggable; diff --git a/v3/src/input/local/components/SetHitArea.js b/v3/src/input/local/components/SetHitArea.js new file mode 100644 index 000000000..c060ac9a8 --- /dev/null +++ b/v3/src/input/local/components/SetHitArea.js @@ -0,0 +1,27 @@ +var InteractiveObject = require('../../InteractiveObject'); + +var SetHitArea = function (gameObjects, shape, callback) +{ + if (shape === undefined) + { + return this.setHitAreaFromTexture(gameObjects); + } + + if (!Array.isArray(gameObjects)) + { + gameObjects = [ gameObjects ]; + } + + for (var i = 0; i < gameObjects.length; i++) + { + var gameObject = gameObjects[i]; + + gameObject.input = InteractiveObject(gameObject, shape, callback); + + this.queueForInsertion(gameObject); + } + + return this; +}; + +module.exports = SetHitArea; diff --git a/v3/src/input/local/components/SetHitAreaCircle.js b/v3/src/input/local/components/SetHitAreaCircle.js new file mode 100644 index 000000000..a91a1978f --- /dev/null +++ b/v3/src/input/local/components/SetHitAreaCircle.js @@ -0,0 +1,13 @@ +var Circle = require('../../../geom/circle/Circle'); +var CircleContains = require('../../../geom/circle/Contains'); + +var SetHitAreaCircle = function (gameObjects, x, y, radius, callback) +{ + if (callback === undefined) { callback = CircleContains; } + + var shape = new Circle(x, y, radius); + + return this.setHitArea(gameObjects, shape, callback); +}; + +module.exports = SetHitAreaCircle; diff --git a/v3/src/input/local/components/SetHitAreaEllipse.js b/v3/src/input/local/components/SetHitAreaEllipse.js new file mode 100644 index 000000000..16430004e --- /dev/null +++ b/v3/src/input/local/components/SetHitAreaEllipse.js @@ -0,0 +1,13 @@ +var Ellipse = require('../../../geom/ellipse/Ellipse'); +var EllipseContains = require('../../../geom/ellipse/Contains'); + +var SetHitAreaEllipse = function (gameObjects, x, y, width, height, callback) +{ + if (callback === undefined) { callback = EllipseContains; } + + var shape = new Ellipse(x, y, width, height); + + return this.setHitArea(gameObjects, shape, callback); +}; + +module.exports = SetHitAreaEllipse; diff --git a/v3/src/input/local/components/SetHitAreaFromTexture.js b/v3/src/input/local/components/SetHitAreaFromTexture.js new file mode 100644 index 000000000..d10b49c37 --- /dev/null +++ b/v3/src/input/local/components/SetHitAreaFromTexture.js @@ -0,0 +1,29 @@ +var InteractiveObject = require('../../InteractiveObject'); +var Rectangle = require('../../../geom/rectangle/Rectangle'); +var RectangleContains = require('../../../geom/rectangle/Contains'); + +var SetHitAreaFromTexture = function (gameObjects, callback) +{ + if (callback === undefined) { callback = RectangleContains; } + + if (!Array.isArray(gameObjects)) + { + gameObjects = [ gameObjects ]; + } + + for (var i = 0; i < gameObjects.length; i++) + { + var gameObject = gameObjects[i]; + + if (gameObject.frame) + { + gameObject.input = InteractiveObject(gameObject, new Rectangle(0, 0, gameObject.frame.width, gameObject.frame.height), callback); + + this.queueForInsertion(gameObject); + } + } + + return this; +}; + +module.exports = SetHitAreaFromTexture; diff --git a/v3/src/input/local/components/SetHitAreaRectangle.js b/v3/src/input/local/components/SetHitAreaRectangle.js new file mode 100644 index 000000000..c5a90015d --- /dev/null +++ b/v3/src/input/local/components/SetHitAreaRectangle.js @@ -0,0 +1,13 @@ +var Rectangle = require('../../../geom/rectangle/Rectangle'); +var RectangleContains = require('../../../geom/rectangle/Contains'); + +var SetHitAreaRectangle = function (gameObjects, x, y, width, height, callback) +{ + if (callback === undefined) { callback = RectangleContains; } + + var shape = new Rectangle(x, y, width, height); + + return this.setHitArea(gameObjects, shape, callback); +}; + +module.exports = SetHitAreaRectangle; diff --git a/v3/src/input/local/components/SetHitAreaTriangle.js b/v3/src/input/local/components/SetHitAreaTriangle.js new file mode 100644 index 000000000..0d517a9de --- /dev/null +++ b/v3/src/input/local/components/SetHitAreaTriangle.js @@ -0,0 +1,13 @@ +var Triangle = require('../../../geom/triangle/Triangle'); +var TriangleContains = require('../../../geom/triangle/Contains'); + +var SetHitAreaTriangle = function (gameObjects, x1, y1, x2, y2, x3, y3, callback) +{ + if (callback === undefined) { callback = TriangleContains; } + + var shape = new Triangle(x1, y1, x2, y2, x3, y3); + + return this.setHitArea(gameObjects, shape, callback); +}; + +module.exports = SetHitAreaTriangle; diff --git a/v3/src/input/local/components/SetOnDownCallback.js b/v3/src/input/local/components/SetOnDownCallback.js new file mode 100644 index 000000000..f20403ee0 --- /dev/null +++ b/v3/src/input/local/components/SetOnDownCallback.js @@ -0,0 +1,6 @@ +var SetOnDownCallback = function (gameObjects, callback, context) +{ + return this.setCallback(gameObjects, 'onDown', callback, context); +}; + +module.exports = SetOnDownCallback; diff --git a/v3/src/input/local/components/SetOnOutCallback.js b/v3/src/input/local/components/SetOnOutCallback.js new file mode 100644 index 000000000..5b53c69f2 --- /dev/null +++ b/v3/src/input/local/components/SetOnOutCallback.js @@ -0,0 +1,6 @@ +var SetOnOutCallback = function (gameObjects, callback, context) +{ + return this.setCallback(gameObjects, 'onOut', callback, context); +}; + +module.exports = SetOnOutCallback; diff --git a/v3/src/input/local/components/SetOnOverCallback.js b/v3/src/input/local/components/SetOnOverCallback.js new file mode 100644 index 000000000..4b634e211 --- /dev/null +++ b/v3/src/input/local/components/SetOnOverCallback.js @@ -0,0 +1,6 @@ +var SetOnOverCallback = function (gameObjects, callback, context) +{ + return this.setCallback(gameObjects, 'onOver', callback, context); +}; + +module.exports = SetOnOverCallback; diff --git a/v3/src/input/local/components/SetOnUpCallback.js b/v3/src/input/local/components/SetOnUpCallback.js new file mode 100644 index 000000000..164be5f29 --- /dev/null +++ b/v3/src/input/local/components/SetOnUpCallback.js @@ -0,0 +1,6 @@ +var SetOnUpCallback = function (gameObjects, callback, context) +{ + return this.setCallback(gameObjects, 'onUp', callback, context); +}; + +module.exports = SetOnUpCallback; diff --git a/v3/src/input/local/components/SetPollAlways.js b/v3/src/input/local/components/SetPollAlways.js new file mode 100644 index 000000000..9c5d2f648 --- /dev/null +++ b/v3/src/input/local/components/SetPollAlways.js @@ -0,0 +1,9 @@ +var SetPollAlways = function () +{ + this.pollRate = 0; + this._pollTimer = 0; + + return this; +}; + +module.exports = SetPollAlways; diff --git a/v3/src/input/local/components/SetPollOnMove.js b/v3/src/input/local/components/SetPollOnMove.js new file mode 100644 index 000000000..beafd3590 --- /dev/null +++ b/v3/src/input/local/components/SetPollOnMove.js @@ -0,0 +1,9 @@ +var SetPollOnMove = function () +{ + this.pollRate = -1; + this._pollTimer = 0; + + return this; +}; + +module.exports = SetPollOnMove; diff --git a/v3/src/input/local/components/SetPollRate.js b/v3/src/input/local/components/SetPollRate.js new file mode 100644 index 000000000..e2e415fab --- /dev/null +++ b/v3/src/input/local/components/SetPollRate.js @@ -0,0 +1,9 @@ +var SetPollRate = function (value) +{ + this.pollRate = value; + this._pollTimer = 0; + + return this; +}; + +module.exports = SetPollRate; diff --git a/v3/src/input/local/components/Update.js b/v3/src/input/local/components/Update.js new file mode 100644 index 000000000..e419d4db5 --- /dev/null +++ b/v3/src/input/local/components/Update.js @@ -0,0 +1,43 @@ +var Update = function (time, delta) +{ + if (this._size === 0) + { + return; + } + + var pointer = this.manager.activePointer; + + var runUpdate = (pointer.dirty || this.pollRate === 0); + + if (this.pollRate > -1) + { + this._pollTimer -= delta; + + if (this._pollTimer < 0) + { + runUpdate = true; + + // Discard timer diff + this._pollTimer = this.pollRate; + } + } + + if (runUpdate) + { + var results = this.hitTestPointer(pointer); + + this.processOverOutEvents(pointer, results); + + if (pointer.justUp || pointer.justDown) + { + this.processUpDownEvents(pointer, results); + } + + if (pointer.justMoved) + { + this.processMovementEvents(pointer, results); + } + } +}; + +module.exports = Update; diff --git a/v3/src/input/events/DragEndEvent.js b/v3/src/input/local/events/DragEndEvent.js similarity index 100% rename from v3/src/input/events/DragEndEvent.js rename to v3/src/input/local/events/DragEndEvent.js diff --git a/v3/src/input/events/DragEvent.js b/v3/src/input/local/events/DragEvent.js similarity index 100% rename from v3/src/input/events/DragEvent.js rename to v3/src/input/local/events/DragEvent.js diff --git a/v3/src/input/events/DragStartEvent.js b/v3/src/input/local/events/DragStartEvent.js similarity index 100% rename from v3/src/input/events/DragStartEvent.js rename to v3/src/input/local/events/DragStartEvent.js diff --git a/v3/src/input/events/PointerDownEvent.js b/v3/src/input/local/events/PointerDownEvent.js similarity index 89% rename from v3/src/input/events/PointerDownEvent.js rename to v3/src/input/local/events/PointerDownEvent.js index d1afad908..b1617df7a 100644 --- a/v3/src/input/events/PointerDownEvent.js +++ b/v3/src/input/local/events/PointerDownEvent.js @@ -17,10 +17,10 @@ var PointerDownEvent = new Class({ this.y = pointer.y; // An array of all the game objects the pointer event occurred on - this.gameObjects = gameObjects; + this.list = gameObjects; // A reference to the top-most game object in the list (based on display list order) - this.top = topObject; + this.gameObject = topObject; } }); diff --git a/v3/src/input/events/PointerOutEvent.js b/v3/src/input/local/events/PointerOutEvent.js similarity index 89% rename from v3/src/input/events/PointerOutEvent.js rename to v3/src/input/local/events/PointerOutEvent.js index 9d281e838..d7ef5cb97 100644 --- a/v3/src/input/events/PointerOutEvent.js +++ b/v3/src/input/local/events/PointerOutEvent.js @@ -17,10 +17,10 @@ var PointerOutEvent = new Class({ this.y = pointer.y; // An array of all the game objects the pointer event occurred on - this.gameObjects = gameObjects; + this.list = gameObjects; // A reference to the top-most game object in the list (based on display list order) - this.top = topObject; + this.gameObject = topObject; } }); diff --git a/v3/src/input/events/PointerOverEvent.js b/v3/src/input/local/events/PointerOverEvent.js similarity index 89% rename from v3/src/input/events/PointerOverEvent.js rename to v3/src/input/local/events/PointerOverEvent.js index f09451405..2b458a304 100644 --- a/v3/src/input/events/PointerOverEvent.js +++ b/v3/src/input/local/events/PointerOverEvent.js @@ -17,10 +17,10 @@ var PointerOverEvent = new Class({ this.y = pointer.y; // An array of all the game objects the pointer event occurred on - this.gameObjects = gameObjects; + this.list = gameObjects; // A reference to the top-most game object in the list (based on display list order) - this.top = topObject; + this.gameObject = topObject; } }); diff --git a/v3/src/input/events/PointerUpEvent.js b/v3/src/input/local/events/PointerUpEvent.js similarity index 89% rename from v3/src/input/events/PointerUpEvent.js rename to v3/src/input/local/events/PointerUpEvent.js index cb75c266f..ba7ba1ac3 100644 --- a/v3/src/input/events/PointerUpEvent.js +++ b/v3/src/input/local/events/PointerUpEvent.js @@ -17,10 +17,10 @@ var PointerUpEvent = new Class({ this.y = pointer.y; // An array of all the game objects the pointer event occurred on - this.gameObjects = gameObjects; + this.list = gameObjects; // A reference to the top-most game object in the list (based on display list order) - this.top = topObject; + this.gameObject = topObject; } }); diff --git a/v3/src/input/events/index.js b/v3/src/input/local/events/index.js similarity index 100% rename from v3/src/input/events/index.js rename to v3/src/input/local/events/index.js diff --git a/v3/src/plugins/InputManager.js b/v3/src/plugins/InputManager.js index d5ceef0a5..ef3213975 100644 --- a/v3/src/plugins/InputManager.js +++ b/v3/src/plugins/InputManager.js @@ -1,191 +1,50 @@ -var Circle = require('../geom/circle/Circle'); -var CircleContains = require('../geom/circle/Contains'); var Class = require('../utils/Class'); -var CONST = require('../input/const'); -var Ellipse = require('../geom/ellipse/Ellipse'); -var EllipseContains = require('../geom/ellipse/Contains'); -var InputEvent = require('../input/events'); -var InteractiveObject = require('../input/InteractiveObject'); -var Rectangle = require('../geom/rectangle/Rectangle'); -var RectangleContains = require('../geom/rectangle/Contains'); -var Triangle = require('../geom/triangle/Triangle'); -var TriangleContains = require('../geom/triangle/Contains'); +var SceneInputManager = require('../input/local/SceneInputManager'); var InputManager = new Class({ + Extends: SceneInputManager, + initialize: function InputManager (scene, game) { - // The Scene that owns this plugin - this.scene = scene; + SceneInputManager.call(this, scene, game); + } - // A reference to this.scene.sys.displayList (set in boot) - this.displayList; - - // A reference to the this.scene.sys.cameras.cameras array (set in boot) - this.cameras; - - // GlobalInputManager - this.manager = game.input; - - // Should use Scene event dispatcher? - this.events = this.manager.events; - - this.keyboard = this.manager.keyboard; - this.mouse = this.manager.mouse; - - // Only fire *callbacks* on the top-most Game Object in the display list (emulating DOM behavior) - // and ignoring any GOs below it, or call them all? (TODO: Set via Input config) - - this.processOptions = { - up: CONST.TOP, - down: CONST.TOP, - over: CONST.TOP, - out: CONST.TOP - }; - - // How often should the pointer input be checked? - // Time given in ms - // Pointer will *always* be checked if it has been moved by the user. - // This controls how often it will be polled if it hasn't been moved. - // Set to 0 to poll constantly. Set to -1 to only poll on user movement. - this.pollRate = -1; - - this._pollTimer = 0; - - this._size = 0; - - // All list of all Game Objects that have been input enabled - this._list = []; - - // Only those which are currently below a pointer (any pointer) - this._over = []; - - // Only Game Objects which have been flagged as draggable are added to this array - this._draggable = []; - - // Objects waiting to be inserted or removed from the active list - this._pendingInsertion = []; - this._pendingRemoval = []; - - this._validTypes = [ 'onDown', 'onUp', 'onOver', 'onOut' ]; - }, - - boot: function () + /* + processOverOutEvents: function (pointer, results) { - this.cameras = this.scene.sys.cameras.cameras; - - this.displayList = this.scene.sys.displayList; - }, - - begin: function () - { - var toRemove = this._pendingRemoval.length; - var toInsert = this._pendingInsertion.length; - - if (toRemove === 0 && toInsert === 0) - { - // Quick bail - return; - } - - var i; var gameObject; - // Delete old gameObjects - for (i = 0; i < toRemove; i++) + // Go through the results + for (var i = 0; i < results.length; i++) { - gameObject = this._pendingRemoval[i]; + gameObject = results[i]; - var index = this._list.indexOf(gameObject); + // Was this GO previously in an 'over' state? - if (index > -1) + + + // Loop through the tested array and work out which game objects were 'over' previously and which are 'just over' (brand new) + for (i = 0; i < results.length; i++) + { + gameObject = results[i]; + + if (previouslyOver.indexOf(gameObject) === -1) { - this._list.splice(index, 1); - - gameObject.input = null; + justOver.push(gameObject); + } + else + { + stillOver.push(gameObject); } } - // Move pending to active (can swap for concat splice if we don't need anything extra here) - - for (i = 0; i < toInsert; i++) - { - gameObject = this._pendingInsertion[i]; - - // Swap for Input Enabled Object - this._list.push(gameObject); - } - - this._size = this._list.length; - - // Clear the lists - this._pendingRemoval.length = 0; - this._pendingInsertion.length = 0; - }, - - setPollAlways: function () - { - this.pollRate = 0; - this._pollTimer = 0; - - return this; - }, - - setPollOnMove: function () - { - this.pollRate = -1; - this._pollTimer = 0; - - return this; - }, - - setPoll: function (value) - { - this.pollRate = value; - this._pollTimer = 0; - - return this; - }, - - update: function (time, delta) - { - if (this._size === 0) - { - return; - } - - var pointer = this.manager.activePointer; - - var runUpdate = (pointer.dirty || this.pollRate === 0); - - if (this.pollRate > -1) - { - this._pollTimer -= delta; - - if (this._pollTimer < 0) - { - runUpdate = true; - - // Discard timer diff - this._pollTimer = this.pollRate; - } - } - - if (runUpdate) - { - this.hitTestPointer(pointer); - - this.processUpDownEvents(pointer); - - if (pointer.justMoved) - { - this.processMovementEvents(pointer); - } - } }, + */ + /* hitTestPointer: function (pointer) { var i; @@ -193,7 +52,7 @@ var InputManager = new Class({ var justOut = []; var justOver = []; var stillOver = []; - var currentlyOver = this._over; + var previouslyOver = this._over; var gameObject; // Get a list of all objects that can be seen by all the cameras in the scene and store in 'tested' array. @@ -208,25 +67,27 @@ var InputManager = new Class({ } } + + // Loop through the tested array and work out which game objects were 'over' previously and which are 'just over' (brand new) for (i = 0; i < tested.length; i++) { gameObject = tested[i]; - if (currentlyOver.indexOf(gameObject) !== -1) - { - stillOver.push(gameObject); - } - else + if (previouslyOver.indexOf(gameObject) === -1) { justOver.push(gameObject); } + else + { + stillOver.push(gameObject); + } } - // Loop through the list of 'currently over' objects (from the previous frame) and any missing are now 'just out' - for (i = 0; i < currentlyOver.length; i++) + // Loop through the list of 'previously over' objects (from the last update) and any missing from it are now 'just out' + for (i = 0; i < previouslyOver.length; i++) { - gameObject = currentlyOver[i]; + gameObject = previouslyOver[i]; if (tested.indexOf(gameObject) === -1) { @@ -238,39 +99,45 @@ var InputManager = new Class({ // Fire a global onOut event that contains all objects that have moved to 'out' status this update - gameObject = this.getTopInteractiveObject(justOut); - - this.events.dispatch(new InputEvent.OUT(pointer, gameObject, justOut)); - - // Call onOut for everything in the justOut array - for (i = 0; i < justOut.length; i++) + if (justOut.length > 0) { - gameObject = justOut[i]; + this.sortInteractiveObjects(justOut); - this.gameObjectOnOut(pointer, gameObject); - - if (this.processOptions.out === CONST.TOP) + // Call onOut for everything in the justOut array + for (i = 0; i < justOut.length; i++) { - break; + gameObject = justOut[i]; + + this.events.dispatch(new InputEvent.OUT(pointer, gameObject, justOut)); + + this.gameObjectOnOut(pointer, gameObject); + + if (this.topOnly) + { + break; + } } } // Fire a global onOut event that contains all objects that have moved to 'over' status this update - gameObject = this.getTopInteractiveObject(justOver); - - this.events.dispatch(new InputEvent.OVER(pointer, gameObject, justOver)); - - // Call onOver for everything in the justOver array - for (i = 0; i < justOver.length; i++) + if (justOver.length > 0) { - gameObject = justOver[i]; + this.sortInteractiveObjects(justOver); - this.gameObjectOnOver(pointer, gameObject); - - if (this.processOptions.over === CONST.TOP) + // Call onOver for everything in the justOver array + for (i = 0; i < justOver.length; i++) { - break; + gameObject = justOver[i]; + + this.events.dispatch(new InputEvent.OVER(pointer, gameObject, justOver)); + + this.gameObjectOnOver(pointer, gameObject); + + if (this.topOnly) + { + break; + } } } @@ -278,14 +145,17 @@ var InputManager = new Class({ this._over = stillOver.concat(justOver); // Then sort it into display list order - this.sortInteractiveObjects(this._over); + this._over = this.sortInteractiveObjects(this._over); }, + */ + + /* // Given an array of Game Objects, sort the array and return it, // so that the objects are in index order with the lowest at the bottom. sortInteractiveObjects: function (interactiveObjects) { - this.displayList.depthSort(); + this.scene.sys.depthSort(); return interactiveObjects.sort(this.sortIndexHandler.bind(this)); }, @@ -323,44 +193,59 @@ var InputManager = new Class({ // Has it been pressed down or released in this update? processUpDownEvents: function (pointer) { - // _over is now in display list order, top to bottom + // _over is now in display list order, top to bottom, already sorted previously var i; - var gameObject = this.getTopInteractiveObject(this._over); + var gameObject; + var len = this._over.length; if (pointer.justDown) { - this.events.dispatch(new InputEvent.DOWN(pointer, gameObject, this._over)); - - if (this.processOptions.down === CONST.TOP) + if (len === 0) { - this.gameObjectOnDown(pointer, gameObject); + // Dispatch global DOWN event, even though nothing was clicked on + this.events.dispatch(new InputEvent.DOWN(pointer)); } else { - for (i = 0; i < this._over.length; i++) + for (i = 0; i < len; i++) { gameObject = this._over[i]; + this.events.dispatch(new InputEvent.DOWN(pointer, gameObject, this._over)); + this.gameObjectOnDown(pointer, gameObject); + + if (this.topOnly) + { + break; + } } + } + } else if (pointer.justUp) { - this.events.dispatch(new InputEvent.UP(pointer, gameObject, this._over)); - - if (this.processOptions.up === CONST.TOP) + if (len === 0) { - this.gameObjectOnUp(pointer, gameObject); + // Dispatch global UP event, even though nothing was under the pointer when released + this.events.dispatch(new InputEvent.UP(pointer)); } else { - for (i = 0; i < this._over.length; i++) + for (i = 0; i < len; i++) { gameObject = this._over[i]; + this.events.dispatch(new InputEvent.UP(pointer, gameObject, this._over)); + this.gameObjectOnUp(pointer, gameObject); + + if (this.topOnly) + { + break; + } } } } @@ -456,8 +341,6 @@ var InputManager = new Class({ // Don't dispatch if we're dragging the gameObject, as the pointer often gets away from it if (!input.isDragged) { - // this.events.dispatch(new InputEvent.OUT(pointer, gameObject)); - input.onOut(gameObject, pointer); } }, @@ -471,279 +354,11 @@ var InputManager = new Class({ // Don't dispatch if we're dragging the gameObject, as the pointer often gets away from it if (!input.isDragged) { - // this.events.dispatch(new InputEvent.OVER(pointer, gameObject)); - input.onOver(gameObject, pointer, input.localX, input.localY); } }, - enable: function (gameObject, shape, callback) - { - if (gameObject.input) - { - // If it is already has an InteractiveObject then just enable it and return - gameObject.input.enabled = true; - } - else - { - // Create an InteractiveObject and enable it - this.setHitArea(gameObject, shape, callback); - } - - return this; - }, - - disable: function (gameObject) - { - gameObject.input.enabled = false; - }, - - // Queues a Game Object for insertion into this Input Manager on the next update. - queueForInsertion: function (child) - { - if (this._pendingInsertion.indexOf(child) === -1 && this._list.indexOf(child) === -1) - { - this._pendingInsertion.push(child); - } - - return this; - }, - - // Queues a Game Object for removal from this Input Manager on the next update. - queueForRemoval: function (child) - { - this._pendingRemoval.push(child); - - return this; - }, - - // Set Hit Areas - - setHitArea: function (gameObjects, shape, callback) - { - if (shape === undefined) - { - return this.setHitAreaFromTexture(gameObjects); - } - - if (!Array.isArray(gameObjects)) - { - gameObjects = [ gameObjects ]; - } - - for (var i = 0; i < gameObjects.length; i++) - { - var gameObject = gameObjects[i]; - - gameObject.input = InteractiveObject(gameObject, shape, callback); - - this.queueForInsertion(gameObject); - } - - return this; - }, - - setHitAreaFromTexture: function (gameObjects, callback) - { - if (callback === undefined) { callback = RectangleContains; } - - if (!Array.isArray(gameObjects)) - { - gameObjects = [ gameObjects ]; - } - - for (var i = 0; i < gameObjects.length; i++) - { - var gameObject = gameObjects[i]; - - if (gameObject.frame) - { - gameObject.input = InteractiveObject(gameObject, new Rectangle(0, 0, gameObject.frame.width, gameObject.frame.height), callback); - - this.queueForInsertion(gameObject); - } - } - - return this; - }, - - setHitAreaRectangle: function (gameObjects, x, y, width, height, callback) - { - if (callback === undefined) { callback = RectangleContains; } - - var shape = new Rectangle(x, y, width, height); - - return this.setHitArea(gameObjects, shape, callback); - }, - - setHitAreaCircle: function (gameObjects, x, y, radius, callback) - { - if (callback === undefined) { callback = CircleContains; } - - var shape = new Circle(x, y, radius); - - return this.setHitArea(gameObjects, shape, callback); - }, - - setHitAreaEllipse: function (gameObjects, x, y, width, height, callback) - { - if (callback === undefined) { callback = EllipseContains; } - - var shape = new Ellipse(x, y, width, height); - - return this.setHitArea(gameObjects, shape, callback); - }, - - setHitAreaTriangle: function (gameObjects, x1, y1, x2, y2, x3, y3, callback) - { - if (callback === undefined) { callback = TriangleContains; } - - var shape = new Triangle(x1, y1, x2, y2, x3, y3); - - return this.setHitArea(gameObjects, shape, callback); - }, - - // type = onDown, onUp, onOver, onOut - - setOnDownCallback: function (gameObjects, callback, context) - { - return this.setCallback(gameObjects, 'onDown', callback, context); - }, - - setOnUpCallback: function (gameObjects, callback, context) - { - return this.setCallback(gameObjects, 'onUp', callback, context); - }, - - setOnOverCallback: function (gameObjects, callback, context) - { - return this.setCallback(gameObjects, 'onOver', callback, context); - }, - - setOnOutCallback: function (gameObjects, callback, context) - { - return this.setCallback(gameObjects, 'onOut', callback, context); - }, - - setCallbacks: function (gameObjects, onDown, onUp, onOver, onOut, context) - { - if (onDown) - { - this.setOnDownCallback(gameObjects, onDown, context); - } - - if (onUp) - { - this.setOnDownCallback(gameObjects, onUp, context); - } - - if (onOver) - { - this.setOnDownCallback(gameObjects, onOver, context); - } - - if (onOut) - { - this.setOnDownCallback(gameObjects, onOut, context); - } - - return this; - }, - - setCallback: function (gameObjects, type, callback, context) - { - if (this._validTypes.indexOf(type) === -1) - { - return this; - } - - if (!Array.isArray(gameObjects)) - { - gameObjects = [ gameObjects ]; - } - - for (var i = 0; i < gameObjects.length; i++) - { - var gameObject = gameObjects[i]; - - if (gameObject.input) - { - gameObject.input[type] = callback; - - if (context) - { - gameObject.input.callbackContext = context; - } - } - } - - return this; - }, - - // Drag Events - // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API - - setDraggable: function (gameObjects, value) - { - if (value === undefined) { value = true; } - - if (!Array.isArray(gameObjects)) - { - gameObjects = [ gameObjects ]; - } - - for (var i = 0; i < gameObjects.length; i++) - { - var gameObject = gameObjects[i]; - var index = this._draggable.indexOf(gameObject); - - if (value) - { - // Make draggable - gameObject.input.draggable = true; - - if (index === -1) - { - this._draggable.push(gameObject); - } - } - else - { - // Disable drag - gameObject.input.draggable = false; - - if (index === -1) - { - this._draggable.splice(index, 1); - } - } - } - - return true; - }, - - // Scene that owns this is shutting down - shutdown: function () - { - this._list = []; - this._over = []; - this._draggable = []; - this._pendingRemoval = []; - this._pendingInsertion = []; - }, - - // Game level nuke - destroy: function () - { - this.shutdown(); - - this.scene = undefined; - this.cameras = undefined; - this.manager = undefined; - this.events = undefined; - this.keyboard = undefined; - this.mouse = undefined; - } + */ });