import React, { useEffect, useState, useRef } from "react"; import * as THREE from "three"; import { useFrame, useThree } from "@react-three/fiber"; import { NavMeshQuery } from "@recast-navigation/core"; import { Line } from "@react-three/drei"; import { useTh } from "leva/dist/declarations/src/styles"; import { useActiveTool } from "../../../store/store"; // Define interface for props interface PathNavigatorProps { navMesh: any; selectedPoints: any; id: string; } export default function PathNavigator({ navMesh, selectedPoints, id, }: PathNavigatorProps) { const [path, setPath] = useState<[number, number, number][]>([]); const progressRef = useRef(0); const distancesRef = useRef([]); const totalDistanceRef = useRef(0); const currentSegmentIndex = useRef(0); const { scene } = useThree(); const { activeTool } = useActiveTool(); const [startPoint, setStartPoint] = useState(new THREE.Vector3()); const meshRef = useRef(null); useEffect(() => { if (!scene || !id || path.length < 2) return; let totalDistance = 0; const distances: number[] = []; for (let i = 0; i < path.length - 1; i++) { const start = new THREE.Vector3(...path[i]); const end = new THREE.Vector3(...path[i + 1]); const segmentDistance = start.distanceTo(end); distances.push(segmentDistance); totalDistance += segmentDistance; } distancesRef.current = distances; totalDistanceRef.current = totalDistance; progressRef.current = 0; // Reset progress when the path changes }, [path]); useEffect(() => { if (!navMesh || selectedPoints.length === 0) return; // Flatten the selectedPoints array into a single list of points const allPoints = selectedPoints.flat(); // Compute paths between consecutive points const computedPath: [number, number, number][] = []; for (let i = 0; i < allPoints.length - 1; i++) { const start = allPoints[i]; setStartPoint( new THREE.Vector3(allPoints[0].x, allPoints[0].y, allPoints[0].z) ); const end = allPoints[i + 1]; try { const navMeshQuery = new NavMeshQuery(navMesh); const { path: segmentPath } = navMeshQuery.computePath(start, end); if (segmentPath && segmentPath.length > 0) { computedPath.push( ...segmentPath.map(({ x, y, z }): [number, number, number] => [ x, y + 0.1, z, ]) ); } } catch (error) {} } // Set the full computed path if (computedPath.length > 0) { setPath(computedPath); currentSegmentIndex.current = 0; // Reset to the first segment } }, [selectedPoints, navMesh, path]); useFrame((_, delta) => { if (!scene || !id || path.length < 2) return; // Find the object in the scene const findObject = scene.getObjectByProperty("uuid", id); if (activeTool === "play") { if (!findObject) return; const speed = 5; progressRef.current += delta * speed; let coveredDistance = progressRef.current; let accumulatedDistance = 0; let index = 0; // Determine the current segment of the path while ( index < distancesRef.current.length && coveredDistance > accumulatedDistance + distancesRef.current[index] ) { accumulatedDistance += distancesRef.current[index]; index++; } // If the object has reached the end of the path, stop moving if (index >= distancesRef.current.length) { progressRef.current = totalDistanceRef.current; return; } // Interpolate position within the current segment const start = new THREE.Vector3(...path[index]); const end = new THREE.Vector3(...path[index + 1]); const segmentDistance = distancesRef.current[index]; const t = (coveredDistance - accumulatedDistance) / segmentDistance; const position = start.clone().lerp(end, t); findObject.position.copy(position); // Rotate the object to face the direction of movement const direction = new THREE.Vector3().subVectors(end, start).normalize(); const targetQuaternion = new THREE.Quaternion().setFromUnitVectors( new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1) direction ); findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation } else if (activeTool === "cursor") { findObject?.position.copy(startPoint); } }); return ( <> {path.length > 0 && } {/* {path.length > 0 && ( 0 ? path[0] : [0, 0.1, 0]}> )} */} ); }