Multiplayer WebXR Project with Vite/Node/Three.js
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

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();
}
}