import { useTexture, PositionalAudio } from "@react-three/drei"; import { useFrame, useThree } from "@react-three/fiber"; import { useEffect, useRef, useState } from "react"; import * as THREE from "three"; import { FEAR_SETTINGS, fearState } from "../state"; export default function TheCreature() { const texture = useTexture('fear/img/creature.png'); const meshRef = useRef(null); const audioRef = useRef(null); const { camera } = useThree(); const [hasTriggered, setHasTriggered] = useState(false); const [isSpawned, setIsSpawned] = useState(false); const globalDistance = useRef(32); const [finaleTriggered, setFinaleTriggered] = useState(fearState.finaleTriggered); const audioPlaying = useRef(false); useEffect(() => { const unsubscribe = fearState.subscribe(() => { setFinaleTriggered(fearState.finaleTriggered); if (!fearState.finaleTriggered) { setIsSpawned(false); setHasTriggered(false); globalDistance.current = 32; audioPlaying.current = false; if (audioRef.current && audioRef.current.isPlaying) audioRef.current.stop(); } }); return () => unsubscribe(); }, []); useFrame((state, delta) => { if (!fearState.finaleTriggered) return; const creature = meshRef.current; if (!creature) return; if (!isSpawned) { setIsSpawned(true); globalDistance.current = 32; } if (!hasTriggered) { if (globalDistance.current < 40) { setHasTriggered(true); } } if (hasTriggered) { globalDistance.current -= FEAR_SETTINGS.CREATURE_SPEED * delta; if (audioRef.current && !audioPlaying.current) { audioPlaying.current = true; if (audioRef.current.context.state === 'suspended') audioRef.current.context.resume(); audioRef.current.play(); } const shakeIntensity = Math.max(0, 1 - (globalDistance.current / 32)) * 0.22; camera.position.x += (Math.random() - 0.5) * shakeIntensity; camera.position.y += (Math.random() - 0.5) * shakeIntensity; if (globalDistance.current <= 0.1) { window.location.href = '/'; fearState.registerCaught(); return; } } const forwardVector = new THREE.Vector3(); camera.getWorldDirection(forwardVector); const lookDirZ = forwardVector.z < 0 ? -1 : 1; const calculatedZ = camera.position.z + (lookDirZ * globalDistance.current); creature.position.set(0, 1.6, calculatedZ); creature.lookAt(camera.position.x, creature.position.y, camera.position.z); }); return ( {finaleTriggered && ( )} ); }