demo/client: Make WASD composable

Currently movement works in the direction of the latest key pressed.
Moving diagonally is not possible, and if you are pressing two keys
and release one, movement stops instead of switching over.

This keeps track of the key press state and updates the movement delta
accordingly, leading to much more natural/pleasant WASD navigation.

Note than onKeyDown is called multiple times when you press and hold,
so we must keep track of this state ourselves.
This commit is contained in:
Manish Goregaokar 2017-09-19 16:26:43 -07:00
parent 83cfb1d9d5
commit 9a0fa96d4f
No known key found for this signature in database
GPG Key ID: 3BBF4D3E2EF79F98
1 changed files with 41 additions and 3 deletions

View File

@ -42,6 +42,8 @@ const PERSPECTIVE_INITIAL_ROTATION: glmatrix.vec2 = glmatrix.vec2.clone([Math.PI
const PERSPECTIVE_OUTER_COLLISION_EXTENT: number = 3000.0;
const PERSPECTIVE_HITBOX_RADIUS: number = 1.0;
const KEYCODES = ["W", "A", "S", "D"].map(x => x.charCodeAt(0));
export interface OrthographicCameraOptions {
minScale?: number;
maxScale?: number;
@ -56,6 +58,10 @@ interface PerspectiveMovementVectors {
[keyCode: number]: glmatrix.vec3;
}
interface PerspectiveMovementKeys {
[keyCode: number]: boolean;
}
export abstract class Camera {
constructor(canvas: HTMLCanvasElement) {
this.canvas = canvas;
@ -253,6 +259,13 @@ export class PerspectiveCamera extends Camera {
window.addEventListener('keyup', event => this.onKeyUp(event), false);
this.onChange = null;
this.wasdPress = _.fromPairs([
['W'.charCodeAt(0), false],
['A'.charCodeAt(0), false],
['S'.charCodeAt(0), false],
['D'.charCodeAt(0), false],
]);
}
private onMouseDown(event: MouseEvent): void {
@ -287,14 +300,37 @@ export class PerspectiveCamera extends Camera {
private onKeyDown(event: KeyboardEvent): void {
if (PERSPECTIVE_MOVEMENT_VECTORS.hasOwnProperty(event.keyCode)) {
this.movementDelta = glmatrix.vec3.clone(PERSPECTIVE_MOVEMENT_VECTORS[event.keyCode]);
// keyDown will be repeated on prolonged holds of the key,
// don't do extra computation in that case
if (this.wasdPress[event.keyCode])
return;
this.wasdPress[event.keyCode] = true;
this.updateMovementDelta();
this.startMoving();
}
}
private onKeyUp(event: KeyboardEvent): void {
if (PERSPECTIVE_MOVEMENT_VECTORS.hasOwnProperty(event.keyCode))
this.stopMoving();
if (PERSPECTIVE_MOVEMENT_VECTORS.hasOwnProperty(event.keyCode)) {
this.wasdPress[event.keyCode] = false;
if (this.updateMovementDelta()) {
this.stopMoving();
}
}
}
// Updates the movementDelta vector based on what keys are currently pressed
// Returns true if the vector is now empty
private updateMovementDelta(): boolean {
this.movementDelta = glmatrix.vec3.create();
let empty = true;
for (const key of KEYCODES) {
if (this.wasdPress[key]) {
glmatrix.vec3.add(this.movementDelta, this.movementDelta, PERSPECTIVE_MOVEMENT_VECTORS[key]);
empty = false;
}
}
return empty;
}
private startMoving(): void {
@ -368,6 +404,8 @@ export class PerspectiveCamera extends Camera {
rotation: glmatrix.vec2;
private movementDelta: glmatrix.vec3;
// If W, A, S, D are pressed
private wasdPress: PerspectiveMovementKeys;
private movementInterval: number | null;
private readonly innerCollisionExtent: number;