You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.0 KiB
107 lines
3.0 KiB
import * as THREE from 'three';
|
|
|
|
export class FPSControls {
|
|
constructor(camera, scene, domElement) {
|
|
this.camera = camera;
|
|
this.domElement = domElement || document;
|
|
this.moveForward = false;
|
|
this.moveBack = false;
|
|
this.moveLeft = false;
|
|
this.moveRight = false;
|
|
this.moveSpeed = 10;
|
|
|
|
// Pointer
|
|
this.pointerRaycast = new THREE.Raycaster();
|
|
this.mouseXY = new THREE.Vector2();
|
|
this.selectedObejcts = [];
|
|
this.scene = scene;
|
|
this.maxDistance = 50;
|
|
|
|
this._bindEvents();
|
|
}
|
|
|
|
_bindEvents() {
|
|
window.addEventListener('keydown', (e) => this._onKeyDown(e));
|
|
window.addEventListener('keyup', (e) => this._onKeyUp(e));
|
|
window.addEventListener('mousemove', (e) => this._onMouseMove(e));
|
|
}
|
|
|
|
_onKeyDown(e) {
|
|
switch (e.code) {
|
|
case 'KeyW': this.moveForward = true; break;
|
|
case 'KeyS': this.moveBack = true; break;
|
|
case 'KeyA': this.moveLeft = true; break;
|
|
case 'KeyD': this.moveRight = true; break;
|
|
}
|
|
}
|
|
|
|
_onKeyUp(e) {
|
|
switch (e.code) {
|
|
case 'KeyW': this.moveForward = false; break;
|
|
case 'KeyS': this.moveBack = false; break;
|
|
case 'KeyA': this.moveLeft = false; break;
|
|
case 'KeyD': this.moveRight = false; break;
|
|
}
|
|
}
|
|
|
|
_onMouseMove(e) {
|
|
this.mouseXY.x = (e.clientX / window.innerWidth ) * 2 - 1;
|
|
this.mouseXY.y = - (e.clientY / window.innerHeight ) * 2 + 1;
|
|
}
|
|
|
|
_drawRay() {
|
|
// Remove previous ray line if it exists, seemes to be an issue with updating the camera position
|
|
if (this.scene.getObjectByName('rayHitLine')) {
|
|
this.scene.remove(this.scene.getObjectByName('rayHitLine'));
|
|
}
|
|
|
|
if (this.selectedObejcts.length > 0) {
|
|
const origin = this.pointerRaycast.ray.origin;
|
|
const hitPoint = this.selectedObejcts[0].point;
|
|
|
|
const geometry = new THREE.BufferGeometry().setFromPoints([origin, hitPoint]);
|
|
const material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
|
|
const line = new THREE.Line(geometry, material);
|
|
line.name = 'rayHitLine';
|
|
|
|
this.scene.add(line);
|
|
}
|
|
}
|
|
|
|
_updatePointer() {
|
|
this.pointerRaycast.setFromCamera(this.mouseXY, this.camera);
|
|
|
|
// Filter objects that have been selected
|
|
const intersectedObjects = this.pointerRaycast.intersectObjects(this.scene.children, true);
|
|
this.selectedObejcts = intersectedObjects.filter(obj => obj.object instanceof THREE.Mesh);
|
|
|
|
//this._drawRay();
|
|
}
|
|
|
|
|
|
|
|
update(delta) {
|
|
const dir = new THREE.Vector3();
|
|
const right = new THREE.Vector3();
|
|
this.camera.getWorldDirection(dir);
|
|
dir.y = 0;
|
|
dir.normalize();
|
|
|
|
right.crossVectors(this.camera.up, dir).normalize();
|
|
|
|
let move = new THREE.Vector3();
|
|
if (this.moveForward) move.add(dir);
|
|
if (this.moveBack) move.sub(dir);
|
|
if (this.moveRight) move.sub(right);
|
|
if (this.moveLeft) move.add(right);
|
|
|
|
move.normalize();
|
|
move.multiplyScalar(this.moveSpeed * delta);
|
|
|
|
// Only move in X and Z, keep Y fixed
|
|
this.camera.position.x += move.x;
|
|
this.camera.position.z += move.z;
|
|
|
|
this._updatePointer();
|
|
}
|
|
}
|