import { useEffect, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import * as THREE from "three"; import { ZONES } from "@/data/zones"; import { useGameStore } from "@/managers/stores/useGameStore"; import { Debug } from "@/utils/debug/Debug"; import type { GameStep } from "@/types/game"; const _playerPos = new THREE.Vector3(); const _zonePos = new THREE.Vector3(); const GAME_STEPS: GameStep[] = [ "intro", "start-intro", "naming", "bienvenue", "star-move", "mission2", "searching", "helped", "manipulation", "outOfFabrik", ]; export function ZoneDetection(): null { const camera = useThree((state) => state.camera); const triggeredZones = useRef>(new Set()); const debug = Debug.getInstance(); const step = useGameStore((state) => state.missionFlow.step); const setStep = useGameStore((state) => state.setFlowStep); useEffect(() => { if (!debug.active) return; const folder = debug.createFolder("Game"); if (!folder) return; const gameState = { step: step }; const playerPos = { x: 0, y: 0, z: 0 }; folder.add(gameState, "step", GAME_STEPS).name("Game Step").disable(); folder.add(playerPos, "x").name("Player X").listen().disable(); folder.add(playerPos, "y").name("Player Y").listen().disable(); folder.add(playerPos, "z").name("Player Z").listen().disable(); const unsubStore = useGameStore.subscribe((state) => { gameState.step = state.missionFlow.step; folder.controllersRecursive().forEach((c) => c.updateDisplay()); }); let frameId: number; const updatePlayerPos = (): void => { camera.getWorldPosition(_playerPos); playerPos.x = Math.round(_playerPos.x * 100) / 100; playerPos.y = Math.round(_playerPos.y * 100) / 100; playerPos.z = Math.round(_playerPos.z * 100) / 100; folder.controllersRecursive().forEach((c) => c.updateDisplay()); frameId = requestAnimationFrame(updatePlayerPos); }; updatePlayerPos(); return () => { cancelAnimationFrame(frameId); debug.destroyFolder("Game"); unsubStore(); }; }, [debug, camera, step]); useFrame(() => { camera.getWorldPosition(_playerPos); for (const zone of ZONES) { if (triggeredZones.current.has(zone.id)) continue; _zonePos.set(...zone.position); const distanceSq = _playerPos.distanceToSquared(_zonePos); if (distanceSq <= zone.radius * zone.radius) { setStep(zone.targetStep); triggeredZones.current.add(zone.id); break; } } }); return null; } interface ZoneVisualProps { position: [number, number, number]; radius: number; height: number; triggered: boolean; } function ZoneVisual({ position, radius, height, triggered, }: ZoneVisualProps): React.JSX.Element { const color = triggered ? "#00ff00" : "#ff0000"; return ( ); } export function ZoneDebugVisuals(): React.JSX.Element | null { const debug = Debug.getInstance(); const camera = useThree((state) => state.camera); const [triggeredZones, setTriggeredZones] = useState>(new Set()); useFrame(() => { camera.getWorldPosition(_playerPos); for (const zone of ZONES) { if (triggeredZones.has(zone.id)) continue; _zonePos.set(...zone.position); const distanceSq = _playerPos.distanceToSquared(_zonePos); if (distanceSq <= zone.radius * zone.radius) { setTriggeredZones((prev) => new Set(prev).add(zone.id)); break; } } }); if (!debug.active) return null; return ( <> {ZONES.map((zone) => ( ))} ); }