feat: add footsteps

This commit is contained in:
2026-06-02 02:47:45 -03:00
parent a0ee50703c
commit 23c39a71a6
7 changed files with 40 additions and 8 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+40 -8
View File
@@ -54,10 +54,32 @@ export default function Player() {
const confirmedSegment = useRef<number>(0); const confirmedSegment = useRef<number>(0);
const hasTriggeredThisSegment = useRef<boolean>(false); const hasTriggeredThisSegment = useRef<boolean>(false);
const footstepAudio = useRef<HTMLAudioElement[]>([]);
const hasStepped = useRef<boolean>(false);
useEffect(() => { useEffect(() => {
playerRoot.set(camera.position.x, FEAR_SETTINGS.PLAYER_HEIGHT, camera.position.z); playerRoot.set(camera.position.x, FEAR_SETTINGS.PLAYER_HEIGHT, camera.position.z);
footstepAudio.current = Array.from({ length: 6 }, (_, i) => {
const audio = new Audio(`fear/snd/footstep${i + 1}.mp3`);
audio.volume = 0.4;
return audio;
});
}, []); }, []);
const playRandomFootstep = () => {
if (footstepAudio.current.length === 0) return;
const randomIndex = Math.floor(Math.random() * footstepAudio.current.length);
const audio = footstepAudio.current[randomIndex];
audio.currentTime = 0;
audio.play().catch((err) => {
console.warn("Footstep playback blocked by browser autocomplete/interaction rules.", err);
});
};
useFrame((state, delta) => { useFrame((state, delta) => {
const dt = Math.min(delta, 0.1); const dt = Math.min(delta, 0.1);
@@ -73,7 +95,7 @@ export default function Player() {
if (moveForward !== 0) targetVelocity.addScaledVector(forward, moveForward); if (moveForward !== 0) targetVelocity.addScaledVector(forward, moveForward);
if (moveSide !== 0) targetVelocity.addScaledVector(side, moveSide); if (moveSide !== 0) targetVelocity.addScaledVector(side, moveSide);
if (targetVelocity.lengthSq() > 0) if (targetVelocity.lengthSq() > 0)
targetVelocity.normalize().multiplyScalar(FEAR_SETTINGS.PLAYER_SPEED); targetVelocity.normalize().multiplyScalar(FEAR_SETTINGS.PLAYER_SPEED);
currentVelocity.lerp(targetVelocity, 10 * dt); currentVelocity.lerp(targetVelocity, 10 * dt);
@@ -86,15 +108,25 @@ export default function Player() {
playerRoot.x = THREE.MathUtils.clamp(playerRoot.x, minX, maxX); playerRoot.x = THREE.MathUtils.clamp(playerRoot.x, minX, maxX);
const isMoving = controls.Forward || controls.Backward || controls.Left || controls.Right; const isMoving = controls.Forward || controls.Backward || controls.Left || controls.Right;
bobIntensity.current = THREE.MathUtils.lerp(bobIntensity.current, isMoving ? 1 : 0, 8 * dt); bobIntensity.current = THREE.MathUtils.lerp(bobIntensity.current, isMoving ? 1 : 0, 8 * dt);
if (isMoving) if (isMoving)
movementCounter.current += dt * 12; movementCounter.current += dt * 12;
const moveBobY = Math.sin(movementCounter.current) * 0.06 * bobIntensity.current; const sinWave = Math.sin(movementCounter.current);
const moveBobY = sinWave * 0.06 * bobIntensity.current;
const moveBobX = Math.cos(movementCounter.current / 2) * 0.04 * bobIntensity.current; const moveBobX = Math.cos(movementCounter.current / 2) * 0.04 * bobIntensity.current;
if (isMoving && sinWave < -0.9) {
if (!hasStepped.current) {
playRandomFootstep();
hasStepped.current = true;
}
} else if (sinWave > 0) {
hasStepped.current = false;
}
const breatheTime = state.clock.elapsedTime * 1.8; const breatheTime = state.clock.elapsedTime * 1.8;
const breatheBobY = Math.sin(breatheTime) * 0.03 * (1 - bobIntensity.current * 0.5); const breatheBobY = Math.sin(breatheTime) * 0.03 * (1 - bobIntensity.current * 0.5);
@@ -113,13 +145,13 @@ export default function Player() {
flashlightRef.current.target.position.lerp(targetDest, 12 * dt); flashlightRef.current.target.position.lerp(targetDest, 12 * dt);
flashlightRef.current.target.updateMatrixWorld(); flashlightRef.current.target.updateMatrixWorld();
flashlightRef.current.intensity = flashlightRef.current.intensity =
FEAR_SETTINGS.FLASHLIGHT_INTENSITY_BASE + FEAR_SETTINGS.FLASHLIGHT_INTENSITY_BASE +
Math.sin(state.clock.elapsedTime * 30) * 0.15 * Math.cos(state.clock.elapsedTime * 3); Math.sin(state.clock.elapsedTime * 30) * 0.15 * Math.cos(state.clock.elapsedTime * 3);
} }
const length = FEAR_SETTINGS.HALLWAY_LENGTH; const length = FEAR_SETTINGS.HALLWAY_LENGTH;
const absoluteZ = -playerRoot.z; const absoluteZ = -playerRoot.z;
const rawSegmentIndex = Math.floor(absoluteZ / length); const rawSegmentIndex = Math.floor(absoluteZ / length);
const progressZ = ((absoluteZ % length) + length) % length / length; const progressZ = ((absoluteZ % length) + length) % length / length;