Spaces:
Running
Running
| import { | |
| Vector3, | |
| Quaternion | |
| } from 'three' | |
| import ControlsBase from './ControlsBase' | |
| export default class KeyboardControls extends ControlsBase { | |
| constructor (player, element) { | |
| super(player, element) | |
| this.element.setAttribute('tabindex', -1) | |
| this.movementSpeedMultiplier = 1 | |
| this.movementSpeed = 1.0 | |
| this.rollSpeed = 0.005 | |
| this.mouseStatus = 0 | |
| this.dragToLook = false | |
| this.autoForward = false | |
| this.moveState = { | |
| up: 0, | |
| down: 0, | |
| left: 0, | |
| right: 0, | |
| forward: 0, | |
| back: 0, | |
| pitchUp: 0, | |
| pitchDown: 0, | |
| yawLeft: 0, | |
| yawRight: 0, | |
| rollLeft: 0, | |
| rollRight: 0 | |
| } | |
| this.moveVector = new Vector3(0, 0, 0) | |
| this.rotationVector = new Vector3(0, 0, 0) | |
| this.contextMenu = this.contextMenu.bind(this) | |
| this.mouseMove = this.mouseMove.bind(this) | |
| this.mouseDown = this.mouseDown.bind(this) | |
| this.mouseUp = this.mouseUp.bind(this) | |
| this.keyDown = this.keyDown.bind(this) | |
| this.keyUp = this.keyUp.bind(this) | |
| } | |
| keyDown (event) { | |
| if (event.altKey) { | |
| return | |
| } | |
| switch (event.keyCode) { | |
| case 16: // Shift | |
| this.movementSpeedMultiplier = 10 | |
| break | |
| case 87: // W | |
| this.moveState.forward = 1 | |
| break | |
| case 83: // S | |
| this.moveState.back = 1 | |
| break | |
| case 65: // A | |
| this.moveState.left = 1 | |
| break | |
| case 68: // D | |
| this.moveState.right = 1 | |
| break | |
| case 82: // R | |
| this.moveState.up = 1 | |
| break | |
| case 70: // F | |
| this.moveState.down = 1 | |
| break | |
| case 38: // Up | |
| this.moveState.pitchUp = 1 | |
| break | |
| case 40: // Down | |
| this.moveState.pitchDown = 1 | |
| break | |
| case 37: // Left | |
| this.moveState.yawLeft = 1 | |
| break | |
| case 39: // Right | |
| this.moveState.yawRight = 1 | |
| break | |
| case 81: // Q | |
| this.moveState.rollLeft = 1 | |
| break | |
| case 69: // E | |
| this.moveState.rollRight = 1 | |
| break | |
| // Control-scheme modifiers: | |
| case 32: | |
| this.dragToLook = !this.dragToLook | |
| this.resetDragToLook() | |
| break | |
| case 27: | |
| this.dragToLook = true | |
| this.resetDragToLook() | |
| break | |
| } | |
| this.updateMovementVector() | |
| this.updateRotationVector() | |
| } | |
| keyUp (event) { | |
| switch (event.keyCode) { | |
| case 16: // Shift | |
| this.movementSpeedMultiplier = 1 | |
| break | |
| case 87: // W | |
| this.moveState.forward = 0 | |
| break | |
| case 83: // S | |
| this.moveState.back = 0 | |
| break | |
| case 65: // A | |
| this.moveState.left = 0 | |
| break | |
| case 68: // D | |
| this.moveState.right = 0 | |
| break | |
| case 82: // R | |
| this.moveState.up = 0 | |
| break | |
| case 70: // F | |
| this.moveState.down = 0 | |
| break | |
| case 38: // Up | |
| this.moveState.pitchUp = 0 | |
| break | |
| case 40: // Down | |
| this.moveState.pitchDown = 0 | |
| break | |
| case 37: // Left | |
| this.moveState.yawLeft = 0 | |
| break | |
| case 39: // Right | |
| this.moveState.yawRight = 0 | |
| break | |
| case 81: // Q | |
| this.moveState.rollLeft = 0 | |
| break | |
| case 69: // E | |
| this.moveState.rollRight = 0 | |
| break | |
| } | |
| this.updateMovementVector() | |
| this.updateRotationVector() | |
| } | |
| resetDragToLook () { | |
| if (this.dragToLook) { | |
| this.moveState.yawLeft = 0 | |
| this.moveState.pitchDown = 0 | |
| } | |
| } | |
| mouseDown (event) { | |
| if (this.element !== document) { | |
| this.element.focus() | |
| } | |
| event.preventDefault() | |
| event.stopPropagation() | |
| if (this.dragToLook) { | |
| this.mouseStatus += 1 | |
| } | |
| else { | |
| switch (event.button) { | |
| case 0: | |
| this.moveState.forward = 1 | |
| break | |
| case 2: | |
| this.moveState.back = 1 | |
| break | |
| } | |
| this.updateMovementVector() | |
| } | |
| } | |
| mouseMove (event) { | |
| if (this.dragToLook && this.mouseStatus === 0) { | |
| return | |
| } | |
| const container = this.getContainerDimensions() | |
| const halfWidth = container.size[0] / 2 | |
| const halfHeight = container.size[1] / 2 | |
| this.moveState.yawLeft = -((event.pageX - container.offset[0]) - halfWidth) / halfWidth | |
| this.moveState.pitchDown = ((event.pageY - container.offset[1]) - halfHeight) / halfHeight | |
| this.updateRotationVector() | |
| } | |
| mouseUp (event) { | |
| event.preventDefault() | |
| event.stopPropagation() | |
| if (this.dragToLook) { | |
| this.mouseStatus -= 1 | |
| this.moveState.yawLeft = this.moveState.pitchDown = 0 | |
| } | |
| else { | |
| switch (event.button) { | |
| case 0: | |
| this.moveState.forward = 0 | |
| break | |
| case 2: | |
| this.moveState.back = 0 | |
| break | |
| } | |
| this.updateMovementVector() | |
| } | |
| this.updateRotationVector() | |
| } | |
| updateMovementVector () { | |
| const forward = (this.moveState.forward || (this.autoForward && !this.moveState.back)) ? 1 : 0 | |
| this.moveVector.x = (-this.moveState.left + this.moveState.right) | |
| this.moveVector.y = (-this.moveState.down + this.moveState.up) | |
| this.moveVector.z = (-forward + this.moveState.back) | |
| } | |
| updateRotationVector () { | |
| this.rotationVector.x = (-this.moveState.pitchDown + this.moveState.pitchUp) | |
| this.rotationVector.y = (-this.moveState.yawRight + this.moveState.yawLeft) | |
| this.rotationVector.z = (-this.moveState.rollRight + this.moveState.rollLeft) | |
| } | |
| getContainerDimensions () { | |
| if (this.element !== document) { | |
| return { | |
| size: [this.element.offsetWidth, this.element.offsetHeight], | |
| offset: [this.element.offsetLeft, this.element.offsetTop] | |
| } | |
| } | |
| else { | |
| return { | |
| size: [window.innerWidth, window.innerHeight], | |
| offset: [0, 0] | |
| } | |
| } | |
| } | |
| contextMenu (event) { | |
| event.preventDefault() | |
| } | |
| enable () { | |
| this.updateMovementVector() | |
| this.updateRotationVector() | |
| this.element.addEventListener('contextmenu', this.contextMenu, false) | |
| this.element.addEventListener('mousemove', this.mouseMove, false) | |
| this.element.addEventListener('mousedown', this.mouseDown, false) | |
| this.element.addEventListener('mouseup', this.mouseUp, false) | |
| window.addEventListener('keydown', this.keyDown, false) | |
| window.addEventListener('keyup', this.keyUp, false) | |
| this.enabled = true | |
| } | |
| disable () { | |
| this.element.removeEventListener('contextmenu', this.contextMenu, false) | |
| this.element.removeEventListener('mousemove', this.mouseMove, false) | |
| this.element.removeEventListener('mousedown', this.mouseDown, false) | |
| this.element.removeEventListener('mouseup', this.mouseUp, false) | |
| window.removeEventListener('keydown', this.keyDown, false) | |
| window.removeEventListener('keyup', this.keyUp, false) | |
| this.enabled = false | |
| } | |
| update () { | |
| const moveMult = this.movementSpeed * this.movementSpeedMultiplier | |
| const rotMult = this.rollSpeed | |
| const worldQuaternion = new Quaternion() | |
| this.player.eyes.getWorldQuaternion(worldQuaternion) | |
| this.player.velocity | |
| .copy(this.moveVector) | |
| .multiplyScalar(moveMult) | |
| .applyQuaternion(worldQuaternion) | |
| this.player.eyeAngularVelocity | |
| .copy(this.rotationVector) | |
| .multiplyScalar(rotMult) | |
| } | |
| } | |