Dwinzo_dev/app/src/modules/builder/agv/pathNavigator.tsx

182 lines
5.7 KiB
TypeScript
Raw Normal View History

import React, { useEffect, useState, useRef } from "react";
2025-03-26 12:58:14 +00:00
import * as THREE from "three";
2025-04-02 13:42:14 +00:00
import { useFrame, useThree } from "@react-three/fiber";
2025-03-26 12:58:14 +00:00
import { NavMeshQuery } from "@recast-navigation/core";
import { Line } from "@react-three/drei";
2025-04-02 13:42:14 +00:00
import { useActiveTool } from "../../../store/store";
2025-04-04 04:16:18 +00:00
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
2025-03-26 12:58:14 +00:00
interface PathNavigatorProps {
navMesh: any;
selectedPoints: any;
2025-04-02 13:42:14 +00:00
id: string;
2025-04-04 04:16:18 +00:00
speed: number;
bufferTime: number;
2025-04-04 11:23:57 +00:00
hitCount: number;
}
2025-03-26 12:58:14 +00:00
export default function PathNavigator({
navMesh,
selectedPoints,
2025-04-02 13:42:14 +00:00
id,
2025-04-04 04:16:18 +00:00
speed,
bufferTime,
2025-04-04 11:23:57 +00:00
hitCount,
}: PathNavigatorProps) {
const [path, setPath] = useState<[number, number, number][]>([]);
const progressRef = useRef(0);
2025-04-02 13:42:14 +00:00
const distancesRef = useRef<number[]>([]);
const totalDistanceRef = useRef(0);
const currentSegmentIndex = useRef(0);
2025-04-04 04:16:18 +00:00
const [stop, setStop] = useState<boolean>(true);
2025-04-02 13:42:14 +00:00
const { scene } = useThree();
2025-04-04 04:16:18 +00:00
const { isPlaying, setIsPlaying } = usePlayButtonStore();
2025-04-02 13:42:14 +00:00
const [startPoint, setStartPoint] = useState(new THREE.Vector3());
2025-04-04 04:16:18 +00:00
const isWaiting = useRef<boolean>(false); // Flag to track waiting state
const delayTime = bufferTime;
2025-04-04 11:23:57 +00:00
2025-04-04 04:16:18 +00:00
const movingForward = useRef<boolean>(true); // Tracks whether the object is moving forward
// Compute distances and total distance when the path changes
2025-04-02 13:42:14 +00:00
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;
2025-04-04 04:16:18 +00:00
progressRef.current = 0;
2025-04-02 13:42:14 +00:00
}, [path]);
2025-04-04 04:16:18 +00:00
2025-04-04 11:23:57 +00:00
// Compute the path using NavMeshQuery
useEffect(() => {
2025-04-02 13:42:14 +00:00
if (!navMesh || selectedPoints.length === 0) return;
2025-03-26 12:58:14 +00:00
2025-04-02 13:42:14 +00:00
const allPoints = selectedPoints.flat();
const computedPath: [number, number, number][] = [];
2025-04-04 04:16:18 +00:00
2025-04-02 13:42:14 +00:00
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)
);
2025-03-26 12:58:14 +00:00
2025-04-02 13:42:14 +00:00
const end = allPoints[i + 1];
try {
const navMeshQuery = new NavMeshQuery(navMesh);
const { path: segmentPath } = navMeshQuery.computePath(start, end);
2025-04-04 04:16:18 +00:00
if (!segmentPath || segmentPath.length === 0) {
continue;
2025-04-02 13:42:14 +00:00
}
2025-04-04 04:16:18 +00:00
computedPath.push(
...segmentPath.map(({ x, y, z }): [number, number, number] => [
x,
y + 0.1,
z,
])
);
2025-04-02 13:42:14 +00:00
} catch (error) {}
}
if (computedPath.length > 0) {
setPath(computedPath);
2025-04-04 04:16:18 +00:00
currentSegmentIndex.current = 0;
2025-03-26 12:58:14 +00:00
}
2025-04-04 04:16:18 +00:00
}, [selectedPoints, navMesh]);
2025-03-26 12:58:14 +00:00
useFrame((_, delta) => {
2025-04-02 13:42:14 +00:00
if (!scene || !id || path.length < 2) return;
2025-04-04 04:16:18 +00:00
// Find the object in the scene by its UUID
2025-04-02 13:42:14 +00:00
const findObject = scene.getObjectByProperty("uuid", id);
2025-04-04 04:16:18 +00:00
if (!findObject) return;
2025-04-02 13:42:14 +00:00
2025-04-04 04:16:18 +00:00
if (isPlaying) {
const fast = speed;
progressRef.current += delta * fast;
2025-03-26 12:58:14 +00:00
let coveredDistance = progressRef.current;
let accumulatedDistance = 0;
let index = 0;
2025-04-02 13:42:14 +00:00
// Determine the current segment of the path
2025-03-26 12:58:14 +00:00
while (
2025-04-02 13:42:14 +00:00
index < distancesRef.current.length &&
coveredDistance > accumulatedDistance + distancesRef.current[index]
2025-03-26 12:58:14 +00:00
) {
2025-04-02 13:42:14 +00:00
accumulatedDistance += distancesRef.current[index];
2025-03-26 12:58:14 +00:00
index++;
}
2025-04-02 13:42:14 +00:00
if (index >= distancesRef.current.length) {
progressRef.current = totalDistanceRef.current;
2025-04-04 04:16:18 +00:00
if (!isWaiting.current) {
isWaiting.current = true; // Set waiting flag
2025-04-04 11:23:57 +00:00
if (movingForward.current) {
// Moving forward: reached the end, wait for `delay`
// console.log(
// "Reached end position. Waiting for delay:",
// delayTime,
// "seconds"
// );
setTimeout(() => {
// After delay, reverse direction
movingForward.current = false;
progressRef.current = 0; // Reset progress
path.reverse(); // Reverse the path
distancesRef.current.reverse();
isWaiting.current = false; // Reset waiting flag
}, delayTime * 1000); // Wait for `delay` seconds
}
2025-04-04 04:16:18 +00:00
}
2025-04-02 13:42:14 +00:00
return;
2025-03-26 12:58:14 +00:00
}
2025-04-02 13:42:14 +00:00
// 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];
2025-04-04 04:16:18 +00:00
const t = Math.min(
(coveredDistance - accumulatedDistance) / segmentDistance,
1
); // Clamp t to avoid overshooting
2025-04-02 13:42:14 +00:00
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();
2025-04-04 04:16:18 +00:00
const targetYRotation = Math.atan2(direction.x, direction.z);
findObject.rotation.y += (targetYRotation - findObject.rotation.y) * 0.1;
} else {
findObject.position.copy(startPoint);
2025-03-26 12:58:14 +00:00
}
});
2025-04-04 11:23:57 +00:00
2025-03-26 12:58:14 +00:00
return (
<>
2025-04-04 04:16:18 +00:00
{path.length > 0 && (
<>
<Line points={path} color="blue" lineWidth={3} />
{selectedPoints.map((val: any, i: any) => (
<mesh position={[val[0], val[1] + 1, val[2]]} key={i}>
<sphereGeometry args={[50, 5, 5]} />
<meshBasicMaterial color={"red"} />
</mesh>
))}
</>
)}
2025-03-26 12:58:14 +00:00
</>
);
}