aframe-extras
Version:
Add-ons and examples for A-Frame VR.
163 lines (135 loc) • 4.97 kB
JavaScript
/* global AFRAME, THREE */
/* eslint-disable no-prototype-builtins */
import '../../lib/keyboard.polyfill.js';
const PROXY_FLAG = '__keyboard-controls-proxy';
const KeyboardEvent = window.KeyboardEvent;
/**
* Keyboard Controls component.
*
* Stripped-down version of: https://github.com/donmccurdy/aframe-keyboard-controls
*
* Bind keyboard events to components, or control your entities with the WASD keys.
*
* Why use KeyboardEvent.code? "This is set to a string representing the key that was pressed to
* generate the KeyboardEvent, without taking the current keyboard layout (e.g., QWERTY vs.
* Dvorak), locale (e.g., English vs. French), or any modifier keys into account. This is useful
* when you care about which physical key was pressed, rather thanwhich character it corresponds
* to. For example, if you’re a writing a game, you might want a certain set of keys to move the
* player in different directions, and that mapping should ideally be independent of keyboard
* layout. See: https://developers.google.com/web/updates/2016/04/keyboardevent-keys-codes
*
* @namespace wasd-controls
* keys the entity moves and if you release it will stop. Easing simulates friction.
* to the entity when pressing the keys.
* @param {bool} [enabled=true] - To completely enable or disable the controls
*/
AFRAME.registerComponent('keyboard-controls', {
schema: {
enabled: { default: true },
debug: { default: false }
},
init: function () {
this.dVelocity = new THREE.Vector3();
this.localKeys = {};
this.listeners = {
keydown: this.onKeyDown.bind(this),
keyup: this.onKeyUp.bind(this),
blur: this.onBlur.bind(this),
onContextMenu: this.onContextMenu.bind(this),
};
},
/*******************************************************************
* Movement
*/
isVelocityActive: function () {
return this.data.enabled && !!Object.keys(this.getKeys()).length;
},
getVelocityDelta: function () {
const data = this.data;
const keys = this.getKeys();
this.dVelocity.set(0, 0, 0);
if (data.enabled) {
if (keys.KeyW || keys.ArrowUp) { this.dVelocity.z -= 1; }
if (keys.KeyA || keys.ArrowLeft) { this.dVelocity.x -= 1; }
if (keys.KeyS || keys.ArrowDown) { this.dVelocity.z += 1; }
if (keys.KeyD || keys.ArrowRight) { this.dVelocity.x += 1; }
// Move faster when the shift key is down.
if (keys.ShiftLeft) { this.dVelocity = this.dVelocity.multiplyScalar(2); }
}
return this.dVelocity.clone();
},
/*******************************************************************
* Events
*/
play: function () {
this.attachEventListeners();
},
pause: function () {
this.removeEventListeners();
},
attachEventListeners: function () {
window.addEventListener("contextmenu", this.listeners.onContextMenu, false);
window.addEventListener("keydown", this.listeners.keydown, false);
window.addEventListener("keyup", this.listeners.keyup, false);
window.addEventListener("blur", this.listeners.blur, false);
},
onContextMenu: function () {
for (const code in this.localKeys) {
if (this.localKeys.hasOwnProperty(code)) {
delete this.localKeys[code];
}
}
},
removeEventListeners: function () {
window.removeEventListener('keydown', this.listeners.keydown);
window.removeEventListener('keyup', this.listeners.keyup);
window.removeEventListener('blur', this.listeners.blur);
},
onKeyDown: function (event) {
if (AFRAME.utils.shouldCaptureKeyEvent(event)) {
this.localKeys[event.code] = true;
this.emit(event);
}
},
onKeyUp: function (event) {
if (AFRAME.utils.shouldCaptureKeyEvent(event)) {
delete this.localKeys[event.code];
this.emit(event);
}
},
onBlur: function () {
for (const code in this.localKeys) {
if (this.localKeys.hasOwnProperty(code)) {
delete this.localKeys[code];
}
}
},
emit: function (event) {
// TODO - keydown only initially?
// TODO - where the f is the spacebar
// Emit original event.
if (PROXY_FLAG in event) {
// TODO - Method never triggered.
this.el.emit(event.type, event);
}
// Emit convenience event, identifying key.
this.el.emit(event.type + ':' + event.code, new KeyboardEvent(event.type, event));
if (this.data.debug) console.log(event.type + ':' + event.code);
},
/*******************************************************************
* Accessors
*/
isPressed: function (code) {
return code in this.getKeys();
},
getKeys: function () {
if (this.isProxied()) {
return this.el.sceneEl.components['proxy-controls'].getKeyboard();
}
return this.localKeys;
},
isProxied: function () {
const proxyControls = this.el.sceneEl.components['proxy-controls'];
return proxyControls && proxyControls.isConnected();
}
});