import * as THREE from 'three'; import { useRef, useState, useEffect } from 'react'; import { Sphere, TransformControls } from '@react-three/drei'; import { useIsConnecting, useRenderDistance, useSelectedEventSphere, useSelectedPath, useSimulationPaths } from '../../../store/store'; import { useFrame, useThree } from '@react-three/fiber'; interface Path { modeluuid: string; points: { uuid: string; position: [number, number, number]; rotation: [number, number, number]; events: { uuid: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean }[] | []; triggers: { uuid: string; type: string; isUsed: boolean }[] | []; }[]; pathPosition: [number, number, number]; pathRotation: [number, number, number]; speed: number; } function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject }) { const { renderDistance } = useRenderDistance(); const { setSelectedEventSphere, selectedEventSphere } = useSelectedEventSphere(); const { setSelectedPath } = useSelectedPath(); const { simulationPaths, setSimulationPaths } = useSimulationPaths(); const { isConnecting, setIsConnecting } = useIsConnecting(); const { camera } = useThree(); const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<'translate' | 'rotate' | null>(null); useEffect(() => { setTransformMode(null); const handleKeyDown = (e: KeyboardEvent) => { if (!selectedEventSphere) return; if (e.key === 'g') { setTransformMode(prev => prev === 'translate' ? null : 'translate'); } if (e.key === 'r') { setTransformMode(prev => prev === 'rotate' ? null : 'rotate'); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [selectedEventSphere]); useFrame(() => { Object.values(groupRefs.current).forEach(group => { if (group) { const distance = new THREE.Vector3(...group.position.toArray()).distanceTo(camera.position); group.visible = distance <= renderDistance; } }); }); const updateSimulationPaths = () => { if (!selectedEventSphere) return; const updatedPaths: Path[] = simulationPaths.map((path) => ({ ...path, points: path.points.map((point) => point.uuid === selectedEventSphere.point.uuid ? { ...point, position: [ selectedEventSphere.point.position.x, selectedEventSphere.point.position.y, selectedEventSphere.point.position.z, ], rotation: [ selectedEventSphere.point.rotation.x, selectedEventSphere.point.rotation.y, selectedEventSphere.point.rotation.z, ] } : point ), })); setSimulationPaths(updatedPaths); }; return ( {simulationPaths.map((path) => { const points = path.points.map(point => new THREE.Vector3(...point.position)); return ( (groupRefs.current[path.modeluuid] = el!)} position={path.pathPosition} rotation={path.pathRotation} onClick={(e) => { if (isConnecting) return; e.stopPropagation(); setSelectedPath({ path, group: groupRefs.current[path.modeluuid] }); setSelectedEventSphere(null); setTransformMode(null); }} onPointerMissed={() => { setSelectedPath(null); }} > {path.points.map((point, index) => ( (sphereRefs.current[point.uuid] = el!)} onClick={(e) => { if (isConnecting) return; e.stopPropagation(); setSelectedEventSphere({ path, point: sphereRefs.current[point.uuid] }); setSelectedPath(null); }} userData={{ point, path }} onPointerMissed={() => setSelectedEventSphere(null)} > ))} {points.slice(0, -1).map((point, index) => { const nextPoint = points[index + 1]; const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]); const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false); return ( ); })} ); })} {selectedEventSphere && transformMode && ( )} ); } export default PathCreation;