var Circle = require('../geom/circle/Circle'); var CircleContains = require('../geom/circle/Contains'); var Class = require('../utils/Class'); var DistanceBetween = require('../math/distance/DistanceBetween'); var Ellipse = require('../geom/ellipse/Ellipse'); var EllipseContains = require('../geom/ellipse/Contains'); var EventEmitter = require('eventemitter3'); var InteractiveObject = require('./InteractiveObject'); var PluginManager = require('../boot/PluginManager'); 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 InputPlugin = new Class({ Extends: EventEmitter, initialize: function InputPlugin(scene){ EventEmitter.call(this); this.scene = scene; this.systems = scene.sys; if (!scene.sys.settings.isBooted) { scene.sys.events.once('boot', this.boot, this); } this.manager = scene.sys.game.input; this.displayList; this.cameras; this.keyboard = this.manager.keyboard; this.mouse = this.manager.mouse; this.gamepad = this.manager.gamepad; this.topOnly = true ; this.pollRate = -1; this._pollTimer = 0; this.dragDistanceThreshold = 0; this.dragTimeThreshold = 0; this._temp = [] ; this._tempZones = [] ; this._list = [] ; this._pendingInsertion = [] ; this._pendingRemoval = [] ; this._draggable = [] ; this._drag = { 0: [] , 1: [] , 2: [] , 3: [] , 4: [] , 5: [] , 6: [] , 7: [] , 8: [] , 9: [] } ; this._over = { 0: [] , 1: [] , 2: [] , 3: [] , 4: [] , 5: [] , 6: [] , 7: [] , 8: [] , 9: [] } ; this._validTypes = ['onDown', 'onUp', 'onOver', 'onOut', 'onMove', 'onDragStart', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragLeave', 'onDragOver', 'onDrop'] ; } , boot: function (){ var eventEmitter = this.systems.events; eventEmitter.on('preupdate', this.preUpdate, this); eventEmitter.on('update', this.update, this); eventEmitter.on('shutdown', this.shutdown, this); eventEmitter.on('destroy', this.destroy, this); this.cameras = this.systems.cameras; this.displayList = this.systems.displayList; } , preUpdate: function (){ var removeList = this._pendingRemoval; var insertList = this._pendingInsertion; var toRemove = _AN_Read_length('length', removeList); var toInsert = _AN_Read_length('length', insertList); if (toRemove === 0 && toInsert === 0) { return ; } var current = this._list; for (var i = 0; i < toRemove; i++ ){ var gameObject = removeList[i]; var index = current.indexOf(gameObject); if (index > -1) { current.splice(index, 1); _AN_Call_clear('clear', this, gameObject); } } removeList.length = 0; this._list = current.concat(insertList.splice(0)); } , clear: function (gameObject){ var input = gameObject.input; input.gameObject = undefined; _AN_Write_target('target', input, false , undefined); input.hitArea = undefined; input.hitAreaCallback = undefined; input.callbackContext = undefined; gameObject.input = null ; var index = this._draggable.indexOf(gameObject); if (index > -1) { this._draggable.splice(index, 1); } index = this._drag[0].indexOf(gameObject); if (index > -1) { this._drag[0].splice(index, 1); } index = this._over[0].indexOf(gameObject); if (index > -1) { this._over[0].splice(index, 1); } return gameObject; } , disable: function (gameObject){ gameObject.input.enabled = false ; } , enable: function (gameObject, shape, callback, dropZone){ if (dropZone === undefined) { dropZone = false ; } if (gameObject.input) { gameObject.input.enabled = true ; } else { this.setHitArea(gameObject, shape, callback); } gameObject.input.dropZone = dropZone; return this; } , hitTestPointer: function (pointer){ var camera = this.cameras.getCameraBelowPointer(pointer); if (camera) { pointer.camera = camera; var over = this.manager.hitTest(pointer.x, pointer.y, this._list, camera); for (var i = 0; i < (_AN_Read_length('length', over)); i++ ){ var obj = over[i]; if (obj.input.dropZone) { this._tempZones.push(obj); } } return over; } else { return [] ; } } , processDownEvents: function (pointer){ var currentlyOver = this._temp; this.emit('pointerdown', pointer, currentlyOver); var total = 0; for (var i = 0; i < (_AN_Read_length('length', currentlyOver)); i++ ){ var gameObject = currentlyOver[i]; if (!gameObject.input) { continue ; } total++ ; gameObject.emit('pointerdown', pointer, gameObject.input.localX, gameObject.input.localY, pointer.camera); this.emit('gameobjectdown', pointer, gameObject); } return total; } , processDragEvents: function (pointer, time){ if ((_AN_Read_length('length', this._draggable)) === 0) { return 0; } var i; var gameObject; var list; var input; var currentlyOver = this._temp; if (pointer.dragState === 0 && pointer.primaryDown && pointer.justDown && (_AN_Read_length('length', currentlyOver)) > 0) { pointer.dragState = 1; } else if (pointer.dragState > 0 && !pointer.primaryDown && pointer.justUp) { pointer.dragState = 5; } if (pointer.dragState === 1) { var draglist = [] ; for (i = 0; i < (_AN_Read_length('length', currentlyOver)); i++ ){ gameObject = currentlyOver[i]; if (gameObject.input.draggable) { draglist.push(gameObject); } } if ((_AN_Read_length('length', draglist)) === 0) { pointer.dragState = 0; return 0; } else if ((_AN_Read_length('length', draglist)) > 1) { this.sortGameObjects(draglist); if (this.topOnly) { draglist.splice(1); } } this._drag[pointer.id] = draglist; if (this.dragDistanceThreshold === 0 && this.dragTimeThreshold === 0) { pointer.dragState = 3; } else { pointer.dragState = 2; } } if (pointer.dragState === 2) { if (this.dragDistanceThreshold > 0 && DistanceBetween(pointer.x, pointer.y, pointer.downX, pointer.downY) >= this.dragDistanceThreshold) { pointer.dragState = 3; } if (this.dragTimeThreshold > 0 && (time >= pointer.downTime + this.dragTimeThreshold)) { pointer.dragState = 3; } } if (pointer.dragState === 3) { list = this._drag[pointer.id]; for (i = 0; i < (_AN_Read_length('length', list)); i++ ){ gameObject = list[i]; input = gameObject.input; input.dragState = 2; input.dragX = pointer.x - gameObject.x; input.dragY = pointer.y - gameObject.y; input.dragStartX = gameObject.x; input.dragStartY = gameObject.y; gameObject.emit('dragstart', pointer, input.dragX, input.dragY); this.emit('dragstart', pointer, gameObject); } pointer.dragState = 4; return 1; } if (pointer.dragState === 4 && pointer.justMoved) { var dropZones = this._tempZones; list = this._drag[pointer.id]; for (i = 0; i < (_AN_Read_length('length', list)); i++ ){ gameObject = list[i]; input = gameObject.input; if (input.target) { var index = dropZones.indexOf(_AN_Read_target('target', input)); if (index === 0) { gameObject.emit('dragover', pointer, _AN_Read_target('target', input)); this.emit('dragover', pointer, gameObject, _AN_Read_target('target', input)); } else if (index > 0) { gameObject.emit('dragleave', pointer, _AN_Read_target('target', input)); this.emit('dragleave', pointer, gameObject, _AN_Read_target('target', input)); _AN_Write_target('target', input, false , dropZones[0]); gameObject.emit('dragenter', pointer, _AN_Read_target('target', input)); this.emit('dragenter', pointer, gameObject, _AN_Read_target('target', input)); } else { gameObject.emit('dragleave', pointer, _AN_Read_target('target', input)); this.emit('dragleave', pointer, gameObject, _AN_Read_target('target', input)); if (dropZones[0]) { _AN_Write_target('target', input, false , dropZones[0]); gameObject.emit('dragenter', pointer, _AN_Read_target('target', input)); this.emit('dragenter', pointer, gameObject, _AN_Read_target('target', input)); } else { _AN_Write_target('target', input, false , null ); } } } else if (!(_AN_Read_target('target', input)) && dropZones[0]) { _AN_Write_target('target', input, false , dropZones[0]); gameObject.emit('dragenter', pointer, _AN_Read_target('target', input)); this.emit('dragenter', pointer, gameObject, _AN_Read_target('target', input)); } var dragX = pointer.x - gameObject.input.dragX; var dragY = pointer.y - gameObject.input.dragY; gameObject.emit('drag', pointer, dragX, dragY); this.emit('drag', pointer, gameObject, dragX, dragY); } } if (pointer.dragState === 5) { list = this._drag[pointer.id]; for (i = 0; i < (_AN_Read_length('length', list)); i++ ){ gameObject = list[i]; input = gameObject.input; input.dragState = 0; input.dragX = input.localX - gameObject.displayOriginX; input.dragY = input.localY - gameObject.displayOriginY; var dropped = false ; if (input.target) { gameObject.emit('drop', pointer, _AN_Read_target('target', input)); this.emit('drop', pointer, gameObject, _AN_Read_target('target', input)); _AN_Write_target('target', input, false , null ); dropped = true ; } gameObject.emit('dragend', pointer, input.dragX, input.dragY, dropped); this.emit('dragend', pointer, gameObject, dropped); } pointer.dragState = 0; } return (pointer.dragState > 0); } , processMoveEvents: function (pointer){ var currentlyOver = this._temp; this.emit('pointermove', pointer, currentlyOver); var total = 0; for (var i = 0; i < (_AN_Read_length('length', currentlyOver)); i++ ){ var gameObject = currentlyOver[i]; if (!gameObject.input) { continue ; } total++ ; gameObject.emit('pointermove', pointer, gameObject.input.localX, gameObject.input.localY); this.emit('gameobjectmove', pointer, gameObject); if (this.topOnly) { break ; } } return total; } , processOverOutEvents: function (pointer){ var currentlyOver = this._temp; var i; var gameObject; var justOut = [] ; var justOver = [] ; var stillOver = [] ; var previouslyOver = this._over[pointer.id]; var currentlyDragging = this._drag[pointer.id]; for (i = 0; i < (_AN_Read_length('length', previouslyOver)); i++ ){ gameObject = previouslyOver[i]; if (currentlyOver.indexOf(gameObject) === -1 && currentlyDragging.indexOf(gameObject) === -1) { justOut.push(gameObject); } else { stillOver.push(gameObject); } } for (i = 0; i < (_AN_Read_length('length', currentlyOver)); i++ ){ gameObject = currentlyOver[i]; if (previouslyOver.indexOf(gameObject) === -1) { justOver.push(gameObject); } } var total = _AN_Read_length('length', justOut); if (total > 0) { this.sortGameObjects(justOut); this.emit('pointerout', pointer, justOut); for (i = 0; i < total; i++ ){ gameObject = justOut[i]; if (!gameObject.input) { continue ; } this.emit('gameobjectout', pointer, gameObject); gameObject.emit('pointerout', pointer); } } total = _AN_Read_length('length', justOver); if (total > 0) { this.sortGameObjects(justOver); this.emit('pointerover', pointer, justOver); for (i = 0; i < total; i++ ){ gameObject = justOver[i]; if (!gameObject.input) { continue ; } this.emit('gameobjectover', pointer, gameObject); gameObject.emit('pointerover', pointer, gameObject.input.localX, gameObject.input.localY); } } previouslyOver = stillOver.concat(justOver); this._over[pointer.id] = this.sortGameObjects(previouslyOver); return (_AN_Read_length('length', previouslyOver)); } , processUpEvents: function (pointer){ var currentlyOver = this._temp; this.emit('pointerup', pointer, currentlyOver); for (var i = 0; i < (_AN_Read_length('length', currentlyOver)); i++ ){ var gameObject = currentlyOver[i]; if (!gameObject.input) { continue ; } gameObject.emit('pointerup', pointer, gameObject.input.localX, gameObject.input.localY); this.emit('gameobjectup', pointer, gameObject); } return (_AN_Read_length('length', currentlyOver)); } , queueForInsertion: function (child){ if (this._pendingInsertion.indexOf(child) === -1 && this._list.indexOf(child) === -1) { this._pendingInsertion.push(child); } return this; } , queueForRemoval: function (child){ this._pendingRemoval.push(child); return this; } , setDraggable: function (gameObjects, value){ if (value === undefined) { value = true ; } if (!Array.isArray(gameObjects)) { gameObjects = [gameObjects] ; } for (var i = 0; i < (_AN_Read_length('length', gameObjects)); i++ ){ var gameObject = gameObjects[i]; gameObject.input.draggable = value; var index = this._draggable.indexOf(gameObject); if (value && index === -1) { this._draggable.push(gameObject); } else if (!value && index > -1) { this._draggable.splice(index, 1); } } return this; } , setHitArea: function (gameObjects, shape, callback){ if (shape === undefined) { return this.setHitAreaFromTexture(gameObjects); } if (!Array.isArray(gameObjects)) { gameObjects = [gameObjects] ; } for (var i = 0; i < (_AN_Read_length('length', gameObjects)); i++ ){ var gameObject = gameObjects[i]; gameObject.input = InteractiveObject(gameObject, shape, callback); this.queueForInsertion(gameObject); } return this; } , 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); } , setHitAreaFromTexture: function (gameObjects, callback){ if (callback === undefined) { callback = RectangleContains; } if (!Array.isArray(gameObjects)) { gameObjects = [gameObjects] ; } for (var i = 0; i < (_AN_Read_length('length', gameObjects)); i++ ){ var gameObject = gameObjects[i]; var frame = gameObject.frame; var width = 0; var height = 0; if (frame) { width = frame.realWidth; height = frame.realHeight; } else if (gameObject.width) { width = gameObject.width; height = gameObject.height; } if (width !== 0 && height !== 0) { gameObject.input = InteractiveObject(gameObject, new Rectangle(0, 0, width, 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); } , 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); } , setPollAlways: function (){ this.pollRate = 0; this._pollTimer = 0; return this; } , setPollOnMove: function (){ this.pollRate = -1; this._pollTimer = 0; return this; } , setPollRate: function (value){ this.pollRate = value; this._pollTimer = 0; return this; } , setGlobalTopOnly: function (value){ this.manager.globalTopOnly = value; return this; } , setTopOnly: function (value){ this.topOnly = value; return this; } , sortGameObjects: function (gameObjects){ if ((_AN_Read_length('length', gameObjects)) < 2) { return gameObjects; } this.scene.sys.depthSort(); return gameObjects.sort(this.sortHandlerGO.bind(this)); } , sortHandlerGO: function (childA, childB){ var indexA = this.displayList.getIndex(childA); var indexB = this.displayList.getIndex(childB); if (indexA < indexB) { return 1; } else if (indexA > indexB) { return -1; } return 0; } , sortHandlerIO: function (childA, childB){ var indexA = this.displayList.getIndex(childA.gameObject); var indexB = this.displayList.getIndex(childB.gameObject); if (indexA < indexB) { return 1; } else if (indexA > indexB) { return -1; } return 0; } , sortInteractiveObjects: function (interactiveObjects){ if ((_AN_Read_length('length', interactiveObjects)) < 2) { return interactiveObjects; } this.scene.sys.depthSort(); return interactiveObjects.sort(this.sortHandlerIO.bind(this)); } , stopPropagation: function (){ if (this.manager.globalTopOnly) { this.manager.ignoreEvents = true ; } return this; } , update: function (time, delta){ var manager = this.manager; if (manager.globalTopOnly && manager.ignoreEvents) { return ; } var pointer = manager.activePointer; var runUpdate = (pointer.dirty || this.pollRate === 0); if (this.pollRate > -1) { this._pollTimer -= delta; if (this._pollTimer < 0) { runUpdate = true ; this._pollTimer = this.pollRate; } } if (!runUpdate) { return ; } this._tempZones = [] ; this._temp = this.hitTestPointer(pointer); this.sortGameObjects(this._temp); this.sortGameObjects(this._tempZones); if (this.topOnly) { if (this._temp.length) { this._temp.splice(1); } if (this._tempZones.length) { this._tempZones.splice(1); } } var total = this.processDragEvents(pointer, time); if (!pointer.wasTouch) { total += this.processOverOutEvents(pointer); } if (pointer.justDown) { total += this.processDownEvents(pointer); } if (pointer.justUp) { total += this.processUpEvents(pointer); } if (pointer.justMoved) { total += this.processMoveEvents(pointer); } if (total > 0 && manager.globalTopOnly) { manager.ignoreEvents = true ; } } , shutdown: function (){ this._temp.length = 0; this._list.length = 0; this._draggable.length = 0; this._pendingRemoval.length = 0; this._pendingInsertion.length = 0; for (var i = 0; i < 10; i++ ){ this._drag[i] = [] ; this._over[i] = [] ; } this.removeAllListeners(); } , destroy: function (){ this.shutdown(); this.scene = undefined; this.cameras = undefined; this.manager = undefined; this.events = undefined; this.keyboard = undefined; this.mouse = undefined; this.gamepad = undefined; } , activePointer: { get: function (){ return this.manager.activePointer; } } , x: { get: function (){ return this.manager.activePointer.x; } } , y: { get: function (){ return this.manager.activePointer.y; } } } ); PluginManager.register('InputPlugin', InputPlugin, 'input'); module.exports = InputPlugin;