feat: add footsteps
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -54,10 +54,32 @@ export default function Player() {
|
||||
const confirmedSegment = useRef<number>(0);
|
||||
const hasTriggeredThisSegment = useRef<boolean>(false);
|
||||
|
||||
const footstepAudio = useRef<HTMLAudioElement[]>([]);
|
||||
const hasStepped = useRef<boolean>(false);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
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) => {
|
||||
const dt = Math.min(delta, 0.1);
|
||||
|
||||
@@ -73,7 +95,7 @@ export default function Player() {
|
||||
if (moveForward !== 0) targetVelocity.addScaledVector(forward, moveForward);
|
||||
if (moveSide !== 0) targetVelocity.addScaledVector(side, moveSide);
|
||||
|
||||
if (targetVelocity.lengthSq() > 0)
|
||||
if (targetVelocity.lengthSq() > 0)
|
||||
targetVelocity.normalize().multiplyScalar(FEAR_SETTINGS.PLAYER_SPEED);
|
||||
|
||||
currentVelocity.lerp(targetVelocity, 10 * dt);
|
||||
@@ -86,15 +108,25 @@ export default function Player() {
|
||||
playerRoot.x = THREE.MathUtils.clamp(playerRoot.x, minX, maxX);
|
||||
|
||||
const isMoving = controls.Forward || controls.Backward || controls.Left || controls.Right;
|
||||
|
||||
|
||||
bobIntensity.current = THREE.MathUtils.lerp(bobIntensity.current, isMoving ? 1 : 0, 8 * dt);
|
||||
|
||||
if (isMoving)
|
||||
|
||||
if (isMoving)
|
||||
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;
|
||||
|
||||
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 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.updateMatrixWorld();
|
||||
|
||||
flashlightRef.current.intensity =
|
||||
FEAR_SETTINGS.FLASHLIGHT_INTENSITY_BASE +
|
||||
flashlightRef.current.intensity =
|
||||
FEAR_SETTINGS.FLASHLIGHT_INTENSITY_BASE +
|
||||
Math.sin(state.clock.elapsedTime * 30) * 0.15 * Math.cos(state.clock.elapsedTime * 3);
|
||||
}
|
||||
|
||||
const length = FEAR_SETTINGS.HALLWAY_LENGTH;
|
||||
const absoluteZ = -playerRoot.z;
|
||||
const absoluteZ = -playerRoot.z;
|
||||
const rawSegmentIndex = Math.floor(absoluteZ / length);
|
||||
const progressZ = ((absoluteZ % length) + length) % length / length;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user