/*global Quintus:false */ /** Quintus HTML5 Game Engine - Input Module The code in `quintus_input.js` defines the `Quintus.Input` module, which concerns itself with game-type (pretty anything besides touchscreen input) @module Quintus.Input */ /** * Quintus Input class * * @class Quintus.Input */ Quintus.Input = function(Q) { var KEY_NAMES = { LEFT: 37, RIGHT: 39, SPACE: 32, UP: 38, DOWN: 40, Z: 90, X: 88 }; var DEFAULT_KEYS = { LEFT: 'left', RIGHT: 'right', UP: 'up', DOWN: 'down', SPACE: 'fire', Z: 'fire', X: 'action' }; var DEFAULT_TOUCH_CONTROLS = [ ['left','<' ], ['right','>' ], [], ['action','b'], ['fire', 'a' ]]; // Clockwise from midnight (a la CSS) var DEFAULT_JOYPAD_INPUTS = [ 'up','right','down','left']; Q.inputs = {}; Q.joypad = {}; var hasTouch = !!('ontouchstart' in window); /** * * Convert a canvas point to a stage point, x dimension * * @method Q.canvasToStageX */ Q.canvasToStageX = function(x,stage) { x = x / Q.cssWidth * Q.width; if(stage.viewport) { x /= stage.viewport.scale; x += stage.viewport.x; } return x; }; /** * * Convert a canvas point to a stage point, y dimension * * @method Q.canvasToStageY */ Q.canvasToStageY = function(y,stage) { y = y / Q.cssWidth * Q.width; if(stage.viewport) { y /= stage.viewport.scale; y += stage.viewport.y; } return y; }; /** * * Button and mouse input subsystem for Quintus. * An instance of this class is auto-created as {{#crossLink "Q.input"}}{{/crossLink}} * * @class InputSystem * @extends Evented * @for Quintus.Input */ Q.InputSystem = Q.Evented.extend({ keys: {}, keypad: {}, keyboardEnabled: false, touchEnabled: false, joypadEnabled: false, bindKey: function(key,name) { Q.input.keys[KEY_NAMES[key] || key] = name; }, keyboardControls: function(keys) { keys = keys || DEFAULT_KEYS; Q._each(keys,function(name,key) { this.bindKey(key,name); },Q.input); this.enableKeyboard(); }, enableKeyboard: function() { if(this.keyboardEnabled) { return false; } // Make selectable and remove an :focus outline Q.el.tabIndex = 0; Q.el.style.outline = 0; Q.el.addEventListener("keydown",function(e) { if(Q.input.keys[e.keyCode]) { var actionName = Q.input.keys[e.keyCode]; Q.inputs[actionName] = true; Q.input.trigger(actionName); Q.input.trigger('keydown',e.keyCode); } e.preventDefault(); },false); Q.el.addEventListener("keyup",function(e) { if(Q.input.keys[e.keyCode]) { var actionName = Q.input.keys[e.keyCode]; Q.inputs[actionName] = false; Q.input.trigger(actionName + "Up"); Q.input.trigger('keyup',e.keyCode); } e.preventDefault(); },false); Q.el.focus(); this.keyboardEnabled = true; }, _containerOffset: function() { Q.input.offsetX = 0; Q.input.offsetY = 0; var el = Q.el; do { Q.input.offsetX += el.offsetLeft; Q.input.offsetY += el.offsetTop; } while(el = el.offsetParent); }, touchLocation: function(touch) { var el = Q.el, posX = touch.offsetX, posY = touch.offsetY, touchX, touchY; if(Q._isUndefined(posX) || Q._isUndefined(posY)) { posX = touch.layerX; posY = touch.layerY; } if(Q._isUndefined(posX) || Q._isUndefined(posY)) { if(Q.input.offsetX === void 0) { Q.input._containerOffset(); } posX = touch.pageX - Q.input.offsetX; posY = touch.pageY - Q.input.offsetY; } touchX = Q.width * posX / Q.cssWidth; touchY = Q.height * posY / Q.cssHeight; return { x: touchX, y: touchY }; }, touchControls: function(opts) { if(this.touchEnabled) { return false; } if(!hasTouch) { return false; } Q.input.keypad = opts = Q._extend({ left: 0, gutter:10, controls: DEFAULT_TOUCH_CONTROLS, width: Q.width, bottom: Q.height },opts); opts.unit = (opts.width / opts.controls.length); opts.size = opts.unit - 2 * opts.gutter; function getKey(touch) { var pos = Q.input.touchLocation(touch); for(var i=0,len=opts.controls.length;i 1) { dx /= overage; dy /= overage; dist /= overage; } var triggers = [ dy < -joypad.trigger, dx > joypad.trigger, dy > joypad.trigger, dx < -joypad.trigger ]; for(var k=0;k 0 && (Q.inputs['up'] || Q.inputs['action'])) { p.vy = p.jumpSpeed; p.landed = -dt; } p.landed -= dt; } }); Q.component("stepControls", { added: function() { var p = this.entity.p; if(!p.stepDistance) { p.stepDistance = 32; } if(!p.stepDelay) { p.stepDelay = 0.2; } p.stepWait = 0; this.entity.on("step",this,"step"); this.entity.on("hit", this,"collision"); }, collision: function(col) { var p = this.entity.p; if(p.stepping) { p.stepping = false; p.x = p.origX; p.y = p.origY; } }, step: function(dt) { var p = this.entity.p, moved = false; p.stepWait -= dt; if(p.stepping) { p.x += p.diffX * dt / p.stepDelay; p.y += p.diffY * dt / p.stepDelay; } if(p.stepWait > 0) { return; } if(p.stepping) { p.x = p.destX; p.y = p.destY; } p.stepping = false; p.diffX = 0; p.diffY = 0; if(Q.inputs['left']) { p.diffX = -p.stepDistance; } else if(Q.inputs['right']) { p.diffX = p.stepDistance; } if(Q.inputs['up']) { p.diffY = -p.stepDistance; } else if(Q.inputs['down']) { p.diffY = p.stepDistance; } if(p.diffY || p.diffX ) { p.stepping = true; p.origX = p.x; p.origY = p.y; p.destX = p.x + p.diffX; p.destY = p.y + p.diffY; p.stepWait = p.stepDelay; } } }); };