Files
Horror-Game/src/Player.js

139 lines
5.0 KiB
JavaScript

import * as THREE from 'three';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
export class Player {
constructor(camera, colliders) {
this.camera = camera;
this.colliders = colliders;
// Player stats
this.speed = 5.0;
this.height = 1.7; // Eyes height
// Init controls
this.controls = new PointerLockControls(camera, document.body);
// Movement state
this.moveForward = false;
this.moveBackward = false;
this.moveLeft = false;
this.moveRight = false;
this.velocity = new THREE.Vector3();
this.direction = new THREE.Vector3();
this.flashlightOn = true; // Started as ON
this.setupInput();
this.setupFlashlight();
}
setupFlashlight() {
this.flashlight = new THREE.SpotLight(0xffffff, 10);
this.flashlight.angle = Math.PI / 6;
this.flashlight.penumbra = 0.3;
this.flashlight.decay = 2;
this.flashlight.distance = 15;
this.camera.add(this.flashlight);
this.flashlight.position.set(0, 0, 0);
this.flashlight.target.position.set(0, 0, -1);
this.camera.add(this.flashlight.target);
}
setupInput() {
const onKeyDown = (event) => {
switch (event.code) {
case 'KeyW': this.moveForward = true; break;
case 'KeyA': this.moveLeft = true; break;
case 'KeyS': this.moveBackward = true; break;
case 'KeyD': this.moveRight = true; break;
case 'KeyF': this.toggleFlashlight(); break;
}
};
const onKeyUp = (event) => {
switch (event.code) {
case 'KeyW': this.moveForward = false; break;
case 'KeyA': this.moveLeft = false; break;
case 'KeyS': this.moveBackward = false; break;
case 'KeyD': this.moveRight = false; break;
}
};
document.addEventListener('keydown', onKeyDown);
document.addEventListener('keyup', onKeyUp);
}
toggleFlashlight() {
if (!this.controls.isLocked) return; // Only toggle when game is active
this.flashlightOn = !this.flashlightOn;
if (this.flashlight) {
this.flashlight.visible = this.flashlightOn;
}
}
lockControls() {
this.controls.lock();
}
getObject() {
return this.controls.getObject();
}
update(dt) {
if (!this.controls.isLocked) return;
// Friction-like dampening
// Simple direct velocity for now
this.velocity.x = 0;
this.velocity.z = 0;
this.direction.z = Number(this.moveForward) - Number(this.moveBackward);
this.direction.x = Number(this.moveRight) - Number(this.moveLeft);
this.direction.normalize(); // Ensure consistent speed in all directions
if (this.moveForward || this.moveBackward) this.velocity.z -= this.direction.z * this.speed * dt;
if (this.moveLeft || this.moveRight) this.velocity.x -= this.direction.x * this.speed * dt;
// Apply movement
this.controls.moveRight(-this.velocity.x);
this.controls.moveForward(-this.velocity.z);
// Simple Collision: Push back
const playerPos = this.controls.getObject().position;
const playerRadius = 0.5; // approximated radius
for (const collider of this.colliders) {
// Assume colliders are BoxGeometry meshes aligned with axes for now
const box = new THREE.Box3().setFromObject(collider);
// Check if player is inside the box (expanded by radius)
// We only check X/Z for walls
if (playerPos.x > box.min.x - playerRadius && playerPos.x < box.max.x + playerRadius &&
playerPos.z > box.min.z - playerRadius && playerPos.z < box.max.z + playerRadius) {
// Very simple resolution: determine closest edge and push out
// This is a naive implementation but works for static orthogonal walls
const dx1 = Math.abs(playerPos.x - (box.min.x - playerRadius));
const dx2 = Math.abs(playerPos.x - (box.max.x + playerRadius));
const dz1 = Math.abs(playerPos.z - (box.min.z - playerRadius));
const dz2 = Math.abs(playerPos.z - (box.max.z + playerRadius));
const minOverlap = Math.min(dx1, dx2, dz1, dz2);
if (minOverlap === dx1) playerPos.x = box.min.x - playerRadius;
else if (minOverlap === dx2) playerPos.x = box.max.x + playerRadius;
else if (minOverlap === dz1) playerPos.z = box.min.z - playerRadius;
else if (minOverlap === dz2) playerPos.z = box.max.z + playerRadius;
}
}
// Keep player on ground
playerPos.y = this.height;
// Flashlight flicker effect (subtle)
if (this.flashlight && this.flashlightOn) {
this.flashlight.intensity = 10 + Math.random() * 0.5;
}
}
}