var Class = require('../utils/Class'); var CONST = require('./const'); var EventEmitter = require('eventemitter3'); var Keyboard = require('./keyboard/KeyboardManager'); var Mouse = require('./mouse/MouseManager'); var Pointer = require('./Pointer'); var Rectangle = require('../geom/rectangle/Rectangle'); var Touch = require('./touch/TouchManager'); var TransformMatrix = require('../gameobjects/components/TransformMatrix'); var TransformXY = require('../math/TransformXY'); var InputManager = new Class({ initialize: function InputManager(game, config){ this.game = game; this.canvas; this.config = config; this.enabled = true ; this.events = new EventEmitter(); this.queue = [] ; this.domCallbacks = { up: [] , down: [] , move: [] , upOnce: [] , downOnce: [] , moveOnce: [] } ; this.isOver = true ; this._emitIsOverEvent = false ; this._hasUpCallback = false ; this._hasDownCallback = false ; this._hasMoveCallback = false ; this._customCursor = ''; this._setCursor = 0; this.defaultCursor = ''; this.keyboard = (config.inputKeyboard)? new Keyboard(this): null ; this.mouse = (config.inputMouse)? new Mouse(this): null ; this.touch = (config.inputTouch)? new Touch(this): null ; this.pointers = [] ; this.pointersTotal = config.inputActivePointers; if (config.inputTouch && this.pointersTotal === 1) { this.pointersTotal = 2; } for (var i = 0; i <= this.pointersTotal; i++ ){ var pointer = new Pointer(this, i); pointer.smoothFactor = config.inputSmoothFactor; this.pointers.push(pointer); } this.mousePointer = (config.inputMouse)? this.pointers[0]: null ; this.activePointer = this.pointers[0]; this.dirty = false ; this.scale = { x: 1, y: 1} ; this.globalTopOnly = true ; this.ignoreEvents = false ; this.bounds = new Rectangle(); this._tempPoint = { x: 0, y: 0} ; this._tempHitTest = [] ; this._tempMatrix = new TransformMatrix(); this._tempMatrix2 = new TransformMatrix(); game.events.once('boot', this.boot, this); } , boot: function (){ this.canvas = this.game.canvas; this.updateBounds(); this.events.emit('boot'); this.game.events.on('prestep', this.update, this); this.game.events.on('poststep', this.postUpdate, this); this.game.events.once('destroy', this.destroy, this); } , updateBounds: function (){ var bounds = this.bounds; var clientRect = this.canvas.getBoundingClientRect(); bounds.x = clientRect.left + window.pageXOffset - document.documentElement.clientLeft; bounds.y = clientRect.top + window.pageYOffset - document.documentElement.clientTop; bounds.width = clientRect.width; bounds.height = clientRect.height; } , resize: function (){ this.updateBounds(); var gw = this.game.config.width; var gh = this.game.config.height; var bw = this.bounds.width; var bh = this.bounds.height; this.scale.x = gw / bw; this.scale.y = gh / bh; } , setCanvasOver: function (event){ this.isOver = true ; this._emitIsOverEvent = event; } , setCanvasOut: function (event){ this.isOver = false ; this._emitIsOverEvent = event; } , update: function (time){ var i; this._setCursor = 0; this.events.emit('update'); this.ignoreEvents = false ; this.dirty = false ; var len = _AN_Read_length('length', this.queue); var pointers = this.pointers; for (i = 0; i < this.pointersTotal; i++ ){ pointers[i].reset(time); } if (!this.enabled || len === 0) { for (i = 0; i < this.pointersTotal; i++ ){ pointers[i].updateMotion(); } return ; } this.dirty = true ; this.updateBounds(); this.scale.x = this.game.config.width / this.bounds.width; this.scale.y = this.game.config.height / this.bounds.height; var queue = this.queue.splice(0, len); var mouse = this.mousePointer; for (i = 0; i < len; i += 2){ var type = queue[i]; var event = queue[i + 1]; switch (type){ case CONST.MOUSE_DOWN: mouse.down(event, time); break ; case CONST.MOUSE_MOVE: mouse.move(event, time); break ; case CONST.MOUSE_UP: mouse.up(event, time); break ; case CONST.TOUCH_START: this.startPointer(event, time); break ; case CONST.TOUCH_MOVE: this.updatePointer(event, time); break ; case CONST.TOUCH_END: this.stopPointer(event, time); break ; case CONST.TOUCH_CANCEL: this.cancelPointer(event, time); break ; case CONST.POINTER_LOCK_CHANGE: this.events.emit('pointerlockchange', event, this.mouse.locked); break ; } } for (i = 0; i < this.pointersTotal; i++ ){ pointers[i].updateMotion(); } } , postUpdate: function (){ if (this._setCursor === 1) { _AN_Write_cursor('cursor', this.canvas.style, false , this._customCursor); } else if (this._setCursor === 2) { _AN_Write_cursor('cursor', this.canvas.style, false , this.defaultCursor); } this._emitIsOverEvent = null ; } , setDefaultCursor: function (cursor){ this.defaultCursor = cursor; if (this.canvas.style.cursor !== cursor) { _AN_Write_cursor('cursor', this.canvas.style, false , cursor); } } , setCursor: function (interactiveObject){ if (interactiveObject.cursor) { this._setCursor = 1; this._customCursor = interactiveObject.cursor; } } , resetCursor: function (interactiveObject){ if (interactiveObject.cursor) { this._setCursor = 2; } } , startPointer: function (event, time){ var pointers = this.pointers; for (var c = 0; c < (_AN_Read_length('length', event.changedTouches)); c++ ){ var changedTouch = event.changedTouches[c]; for (var i = 1; i < this.pointersTotal; i++ ){ var pointer = pointers[i]; if (!pointer.active) { pointer.touchstart(changedTouch, time); this.activePointer = pointer; break ; } } } } , updatePointer: function (event, time){ var pointers = this.pointers; for (var c = 0; c < (_AN_Read_length('length', event.changedTouches)); c++ ){ var changedTouch = event.changedTouches[c]; for (var i = 1; i < this.pointersTotal; i++ ){ var pointer = pointers[i]; if (pointer.active && pointer.identifier === changedTouch.identifier) { pointer.touchmove(changedTouch, time); this.activePointer = pointer; break ; } } } } , stopPointer: function (event, time){ var pointers = this.pointers; for (var c = 0; c < (_AN_Read_length('length', event.changedTouches)); c++ ){ var changedTouch = event.changedTouches[c]; for (var i = 1; i < this.pointersTotal; i++ ){ var pointer = pointers[i]; if (pointer.active && pointer.identifier === changedTouch.identifier) { pointer.touchend(changedTouch, time); break ; } } } } , cancelPointer: function (event, time){ var pointers = this.pointers; for (var c = 0; c < (_AN_Read_length('length', event.changedTouches)); c++ ){ var changedTouch = event.changedTouches[c]; for (var i = 1; i < this.pointersTotal; i++ ){ var pointer = pointers[i]; if (pointer.active && pointer.identifier === changedTouch.identifier) { pointer.touchend(changedTouch, time); break ; } } } } , addPointer: function (quantity){ if (quantity === undefined) { quantity = 1; } var output = [] ; if (this.pointersTotal + quantity > 10) { quantity = 10 - this.pointersTotal; } for (var i = 0; i < quantity; i++ ){ var id = _AN_Read_length('length', this.pointers); var pointer = new Pointer(this, id); pointer.smoothFactor = this.config.inputSmoothFactor; this.pointers.push(pointer); this.pointersTotal++ ; output.push(pointer); } return output; } , processDomCallbacks: function (once, every, event){ var i = 0; for (i = 0; i < (_AN_Read_length('length', once)); i++ ){ once[i](event); } for (i = 0; i < (_AN_Read_length('length', every)); i++ ){ every[i](event); } return ((_AN_Read_length('length', every)) > 0); } , queueTouchStart: function (event){ this.queue.push(CONST.TOUCH_START, event); if (this._hasDownCallback) { var callbacks = this.domCallbacks; this._hasDownCallback = this.processDomCallbacks(callbacks.downOnce, callbacks.down, event); callbacks.downOnce = [] ; } } , queueTouchMove: function (event){ this.queue.push(CONST.TOUCH_MOVE, event); if (this._hasMoveCallback) { var callbacks = this.domCallbacks; this._hasMoveCallback = this.processDomCallbacks(callbacks.moveOnce, callbacks.move, event); callbacks.moveOnce = [] ; } } , queueTouchEnd: function (event){ this.queue.push(CONST.TOUCH_END, event); if (this._hasUpCallback) { var callbacks = this.domCallbacks; this._hasUpCallback = this.processDomCallbacks(callbacks.upOnce, callbacks.up, event); callbacks.upOnce = [] ; } } , queueTouchCancel: function (event){ this.queue.push(CONST.TOUCH_CANCEL, event); } , queueMouseDown: function (event){ this.queue.push(CONST.MOUSE_DOWN, event); if (this._hasDownCallback) { var callbacks = this.domCallbacks; this._hasDownCallback = this.processDomCallbacks(callbacks.downOnce, callbacks.down, event); callbacks.downOnce = [] ; } } , queueMouseMove: function (event){ this.queue.push(CONST.MOUSE_MOVE, event); if (this._hasMoveCallback) { var callbacks = this.domCallbacks; this._hasMoveCallback = this.processDomCallbacks(callbacks.moveOnce, callbacks.move, event); callbacks.moveOnce = [] ; } } , queueMouseUp: function (event){ this.queue.push(CONST.MOUSE_UP, event); if (this._hasUpCallback) { var callbacks = this.domCallbacks; this._hasUpCallback = this.processDomCallbacks(callbacks.upOnce, callbacks.up, event); callbacks.upOnce = [] ; } } , addUpCallback: function (callback, isOnce){ if (isOnce === undefined) { isOnce = true ; } if (isOnce) { this.domCallbacks.upOnce.push(callback); } else { this.domCallbacks.up.push(callback); } this._hasUpCallback = true ; return this; } , addDownCallback: function (callback, isOnce){ if (isOnce === undefined) { isOnce = true ; } if (isOnce) { this.domCallbacks.downOnce.push(callback); } else { this.domCallbacks.down.push(callback); } this._hasDownCallback = true ; return this; } , addMoveCallback: function (callback, isOnce){ if (isOnce === undefined) { isOnce = false ; } if (isOnce) { this.domCallbacks.moveOnce.push(callback); } else { this.domCallbacks.move.push(callback); } this._hasMoveCallback = true ; return this; } , inputCandidate: function (gameObject, camera){ var input = gameObject.input; if (!input || !input.enabled || !gameObject.willRender(camera)) { return false ; } var visible = true ; var parent = gameObject.parentContainer; if (parent) { do { if (!parent.willRender(camera)) { visible = false ; break ; } parent = parent.parentContainer; } while(parent)} return visible; } , hitTest: function (pointer, gameObjects, camera, output){ if (output === undefined) { output = this._tempHitTest; } var tempPoint = this._tempPoint; var csx = camera.scrollX; var csy = camera.scrollY; output.length = 0; var x = pointer.x; var y = pointer.y; if (camera.resolution !== 1) { x += camera._x; y += camera._y; } camera.getWorldPoint(x, y, tempPoint); pointer.worldX = tempPoint.x; pointer.worldY = tempPoint.y; var point = { x: 0, y: 0} ; var matrix = this._tempMatrix; var parentMatrix = this._tempMatrix2; for (var i = 0; i < (_AN_Read_length('length', gameObjects)); i++ ){ var gameObject = gameObjects[i]; if (!this.inputCandidate(gameObject, camera)) { continue ; } var px = tempPoint.x + (csx * gameObject.scrollFactorX) - csx; var py = tempPoint.y + (csy * gameObject.scrollFactorY) - csy; if (gameObject.parentContainer) { gameObject.getWorldTransformMatrix(matrix, parentMatrix); matrix.applyInverse(px, py, point); } else { TransformXY(px, py, gameObject.x, gameObject.y, gameObject.rotation, gameObject.scaleX, gameObject.scaleY, point); } if (this.pointWithinHitArea(gameObject, point.x, point.y)) { output.push(gameObject); } } return output; } , pointWithinHitArea: function (gameObject, x, y){ x += gameObject.displayOriginX; y += gameObject.displayOriginY; var input = gameObject.input; if (input && input.hitAreaCallback(input.hitArea, x, y, gameObject)) { input.localX = x; input.localY = y; return true ; } else { return false ; } } , pointWithinInteractiveObject: function (object, x, y){ if (!object.hitArea) { return false ; } x += object.gameObject.displayOriginX; y += object.gameObject.displayOriginY; object.localX = x; object.localY = y; return object.hitAreaCallback(object.hitArea, x, y, object); } , transformPointer: function (pointer, pageX, pageY, wasMove){ var p0 = pointer.position; var p1 = pointer.prevPosition; p1.x = p0.x; p1.y = p0.y; var x = (pageX - this.bounds.left) * this.scale.x; var y = (pageY - this.bounds.top) * this.scale.y; var a = pointer.smoothFactor; if (!wasMove || a === 0) { p0.x = x; p0.y = y; } else { p0.x = x * a + p1.x * (1 - a); p0.y = y * a + p1.y * (1 - a); } } , transformX: function (pageX){ return (pageX - this.bounds.left) * this.scale.x; } , transformY: function (pageY){ return (pageY - this.bounds.top) * this.scale.y; } , getOffsetX: function (){ return this.bounds.left; } , getOffsetY: function (){ return this.bounds.top; } , getScaleX: function (){ return this.game.config.width / this.bounds.width; } , getScaleY: function (){ return this.game.config.height / this.bounds.height; } , destroy: function (){ this.events.removeAllListeners(); if (this.keyboard) { this.keyboard.destroy(); } if (this.mouse) { this.mouse.destroy(); } if (this.touch) { this.touch.destroy(); } for (var i = 0; i < (_AN_Read_length('length', this.pointers)); i++ ){ this.pointers[i].destroy(); } this.domCallbacks = { } ; this.pointers = [] ; this.queue = [] ; this._tempHitTest = [] ; this._tempMatrix.destroy(); this.canvas = null ; this.game = null ; } } ); module.exports = InputManager;