rg/naloga_3/engine/controllers/FirstPersonController.js
Gašper Dobrovoljc a20a45ebd0
Naloga 3 WIP
2024-12-28 19:58:17 +01:00

132 lines
3.9 KiB
JavaScript

import { quat, vec3, mat4 } from 'glm';
import { Transform } from '../core/Transform.js';
export class FirstPersonController {
constructor(node, domElement, {
pitch = 0,
yaw = 0,
velocity = [0, 0, 0],
acceleration = 50,
maxSpeed = 5,
decay = 0.99999,
pointerSensitivity = 0.002,
} = {}) {
this.node = node;
this.domElement = domElement;
this.keys = {};
this.pitch = pitch;
this.yaw = yaw;
this.velocity = velocity;
this.acceleration = acceleration;
this.maxSpeed = maxSpeed;
this.decay = decay;
this.pointerSensitivity = pointerSensitivity;
this.initHandlers();
}
initHandlers() {
this.pointermoveHandler = this.pointermoveHandler.bind(this);
this.keydownHandler = this.keydownHandler.bind(this);
this.keyupHandler = this.keyupHandler.bind(this);
const element = this.domElement;
const doc = element.ownerDocument;
doc.addEventListener('keydown', this.keydownHandler);
doc.addEventListener('keyup', this.keyupHandler);
element.addEventListener('click', e => element.requestPointerLock());
doc.addEventListener('pointerlockchange', e => {
if (doc.pointerLockElement === element) {
doc.addEventListener('pointermove', this.pointermoveHandler);
} else {
doc.removeEventListener('pointermove', this.pointermoveHandler);
}
});
}
update(t, dt) {
// Calculate forward and right vectors.
const cos = Math.cos(this.yaw);
const sin = Math.sin(this.yaw);
const forward = [-sin, 0, -cos];
const right = [cos, 0, -sin];
// Map user input to the acceleration vector.
const acc = vec3.create();
if (this.keys['KeyW']) {
vec3.add(acc, acc, forward);
}
if (this.keys['KeyS']) {
vec3.sub(acc, acc, forward);
}
if (this.keys['KeyD']) {
vec3.add(acc, acc, right);
}
if (this.keys['KeyA']) {
vec3.sub(acc, acc, right);
}
// Update velocity based on acceleration.
vec3.scaleAndAdd(this.velocity, this.velocity, acc, dt * this.acceleration);
// If there is no user input, apply decay.
if (!this.keys['KeyW'] &&
!this.keys['KeyS'] &&
!this.keys['KeyD'] &&
!this.keys['KeyA'])
{
const decay = Math.exp(dt * Math.log(1 - this.decay));
vec3.scale(this.velocity, this.velocity, decay);
}
// Limit speed to prevent accelerating to infinity and beyond.
const speed = vec3.length(this.velocity);
if (speed > this.maxSpeed) {
vec3.scale(this.velocity, this.velocity, this.maxSpeed / speed);
}
const transform = this.node.getComponentOfType(Transform);
if (transform) {
// Update translation based on velocity.
vec3.scaleAndAdd(transform.translation,
transform.translation, this.velocity, dt);
// Update rotation based on the Euler angles.
const rotation = quat.create();
quat.rotateY(rotation, rotation, this.yaw);
quat.rotateX(rotation, rotation, this.pitch);
transform.rotation = rotation;
}
}
pointermoveHandler(e) {
const dx = e.movementX;
const dy = e.movementY;
this.pitch -= dy * this.pointerSensitivity;
this.yaw -= dx * this.pointerSensitivity;
const twopi = Math.PI * 2;
const halfpi = Math.PI / 2;
this.pitch = Math.min(Math.max(this.pitch, -halfpi), halfpi);
this.yaw = ((this.yaw % twopi) + twopi) % twopi;
}
keydownHandler(e) {
this.keys[e.code] = true;
}
keyupHandler(e) {
this.keys[e.code] = false;
}
}