feat: Introduce footstep audio effects with context activation and set camera rotation order.

This commit is contained in:
2026-01-03 08:36:53 +00:00
parent eb5b086c13
commit cf4704c71b

View File

@@ -6,6 +6,7 @@ import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockCont
export class Player {
constructor(camera, colliders) {
this.camera = camera;
this.camera.rotation.order = 'YXZ'; // Standard FPS rotation order to prevent gimbal lock
this.colliders = colliders;
// Player stats
@@ -35,6 +36,14 @@ export class Player {
this.battery = 100.0;
this.baseDrain = 0.5; // Drain per second at base intensity
// Animation
this.headBobTimer = 0;
this.lastStepTime = 0;
// Audio
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
this.audioEnabled = false;
// Animation
this.headBobTimer = 0;
@@ -59,6 +68,12 @@ export class Player {
setupInput() {
const onKeyDown = (event) => {
// Resume Audio Context on first interaction
if (this.ctx && this.ctx.state === 'suspended') {
this.ctx.resume();
this.audioEnabled = true;
}
switch (event.code) {
case 'KeyW': this.moveForward = true; break;
case 'KeyA': this.moveLeft = true; break;
@@ -166,8 +181,21 @@ export class Player {
}
}
// Keep player on ground
this.camera.position.y = this.height;
// Keep player on ground (Base height)
const baseHeight = this.height;
playerPos.y = baseHeight;
// Audio Only Trigger
if (this.moveForward || this.moveBackward || this.moveLeft || this.moveRight) {
// Step every 0.6 seconds
this.lastStepTime += dt;
if (this.lastStepTime > 0.6) {
this.lastStepTime = 0;
this.playFootstep();
}
} else {
this.lastStepTime = 0.5; // Ready to step properly next time
}
// Flashlight flicker effect (subtle) & Battery Logic
if (this.flashlight && this.flashlightOn) {
@@ -216,4 +244,39 @@ export class Player {
}
}
}
playFootstep() {
if (!this.ctx) return;
const t = this.ctx.currentTime;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
const filter = this.ctx.createBiquadFilter();
// Noise buffer for texture
const bufferSize = this.ctx.sampleRate * 0.1; // 0.1s duration
const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = (Math.random() * 2 - 1) * 0.5;
}
const noise = this.ctx.createBufferSource();
noise.buffer = buffer;
// Filter to make it sound dull (floor/carpet)
filter.type = 'lowpass';
filter.frequency.setValueAtTime(400, t); // Low muffled thud
// Envelope
gain.gain.setValueAtTime(0.3, t);
gain.gain.exponentialRampToValueAtTime(0.01, t + 0.1);
// Connect
noise.connect(filter);
filter.connect(gain);
gain.connect(this.ctx.destination);
noise.start();
noise.stop(t + 0.1);
}
}