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