added vehicle conflict path structure

This commit is contained in:
2025-09-02 09:13:06 +05:30
parent 6da82895b7
commit c60f15db13
4 changed files with 141 additions and 289 deletions

View File

@@ -1,11 +1,12 @@
import { useFrame, useThree } from "@react-three/fiber";
import React, { useEffect, useRef, useState } from "react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Quaternion, Vector3 } from "three";
import {
useAnimationPlaySpeed,
usePlayButtonStore,
} from "../../../../../store/usePlayButtonStore";
import { usePathManager } from "../../pathCreator/function/usePathManager";
import { useCreatedPaths } from "../../../../../store/builder/store";
interface VehicleAnimatorProps {
vehiclesData: VehicleStructure[];
@@ -21,6 +22,7 @@ export default function VehicleAnimator2({
const { scene } = useThree();
const { speed } = useAnimationPlaySpeed();
const { isPlaying } = usePlayButtonStore();
const { paths, allPaths, setAllPaths } = useCreatedPaths();
const vehicleMovementState = useRef<
Record<
string,
@@ -34,138 +36,33 @@ export default function VehicleAnimator2({
>
>({});
const managerRef = useRef<ManagerData>();
// const manager = usePathManager(managerData?.pathId, managerData?.vehicleId);
// Initialize all paths into allPaths store
useEffect(() => {
if (!paths || paths.length === 0) return;
// useFrame((_, delta) => {
// if (!isPlaying) return;
const newPaths = useCreatedPaths.getState().paths.map((val: any) => ({
pathId: val.pathId,
isAvailable: true,
vehicleId: null,
}));
const merged = [...useCreatedPaths.getState().allPaths];
newPaths.forEach((p: any) => {
if (!merged.find((m) => m.pathId === p.pathId)) {
merged.push(p);
}
});
// vehiclesData.forEach((vehicle) => {
// const { vehicleId, route } = vehicle;
// if (
// !route ||
// route.length === 0 ||
// !route[0].pathPoints ||
// route[0].pathPoints.length < 2
// ) {
// return;
// }
// const mesh = scene.getObjectByProperty("uuid", vehicleId); // or getObjectByName
// if (!mesh) return;
// const currentPath = route[0];
// const pathPoints = currentPath.pathPoints;
// const currentPathId = currentPath.pathId;
// // ✅ Call your function here
// setManagerData({ pathId: currentPathId, vehicleId: vehicleId });
// const pathStart = new Vector3(...pathPoints[0].position);
// const uuid = vehicleId;
// // Initialize movement state
// if (!vehicleMovementState.current[uuid]) {
// vehicleMovementState.current[uuid] = {
// index: 0,
// progress: 0,
// hasStarted: false,
// };
// }
// const state = vehicleMovementState.current[uuid];
// // ✳️ Step 1: Move to start point first
// if (!state.hasStarted) {
// const distanceToStart = mesh.position.distanceTo(pathStart);
// const step = speed * delta;
// if (distanceToStart <= step) {
// mesh.position.copy(pathStart);
// mesh.quaternion.identity();
// state.hasStarted = true;
// return;
// }
// const direction = pathStart.clone().sub(mesh.position);
// const distance = direction.length();
// if (distance > step) {
// direction.normalize();
// mesh.position.add(direction.clone().multiplyScalar(step));
// const forward = new Vector3(0, 0, 1);
// const targetQuat = new Quaternion().setFromUnitVectors(
// forward,
// direction
// );
// mesh.quaternion.slerp(targetQuat, 0.1);
// } else {
// mesh.position.copy(pathStart);
// mesh.quaternion.identity();
// state.hasStarted = true;
// state.index = 0;
// state.progress = 0;
// }
// return;
// }
// // ✳️ Step 2: Move along the route
// const currentPoint = new Vector3(...pathPoints[state.index].position);
// const nextPoint = new Vector3(...pathPoints[state.index + 1].position);
// const segmentVector = new Vector3().subVectors(nextPoint, currentPoint);
// const segmentLength = segmentVector.length();
// const direction = segmentVector.clone().normalize();
// const moveDistance = speed * delta;
// state.progress += moveDistance / segmentLength;
// if (state.progress >= 1) {
// state.index++;
// state.progress = 0;
// if (state.index >= pathPoints.length - 1) {
// // Stop at the end
// state.index = pathPoints.length - 2;
// state.progress = 1;
// }
// }
// // Interpolate position
// const newPos = new Vector3().lerpVectors(
// currentPoint,
// nextPoint,
// state.progress
// );
// mesh.position.copy(newPos);
// // Smooth rotation
// const forward = new Vector3(0, 0, 1);
// const targetQuat = new Quaternion().setFromUnitVectors(
// forward,
// direction
// );
// mesh.quaternion.slerp(targetQuat, 0.1);
// });
// });
// ✅ Shared waypoint reservation system
const reservedWaypoints = new Set<string>();
function tryReserveWaypoint(vehicleId: string, waypointId: string) {
if (reservedWaypoints.has(waypointId)) return false; // already reserved
reservedWaypoints.add(waypointId);
return true;
}
function releaseWaypoint(waypointId: string) {
reservedWaypoints.delete(waypointId);
}
if (merged.length !== useCreatedPaths.getState().allPaths.length) {
setAllPaths(merged);
}
}, [paths, allPaths, setAllPaths]);
useFrame((_, delta) => {
if (!isPlaying) return;
vehiclesData.forEach((vehicle) => {
const { vehicleId, route } = vehicle;
if (!route || route.length === 0) return;
const mesh = scene.getObjectByProperty("uuid", vehicleId);
@@ -173,7 +70,7 @@ export default function VehicleAnimator2({
const uuid = vehicleId;
// ✅ Initialize state
// ✅ Initialize state if not already
if (!vehicleMovementState.current[uuid]) {
vehicleMovementState.current[uuid] = {
index: 0,
@@ -196,7 +93,9 @@ export default function VehicleAnimator2({
let pathPoints = currentPath.pathPoints;
const pathStart = new Vector3(...pathPoints[0].position);
// Step 1: move mesh to start
/**
* 🟢 STEP 1: Move vehicle to the starting point of its first path
*/
if (!state.hasStarted) {
const distanceToStart = mesh.position.distanceTo(pathStart);
const step = speed * delta;
@@ -221,14 +120,9 @@ export default function VehicleAnimator2({
return;
}
// ✅ Conflict Resolution: Check reservation before moving
const nextWaypointId = `${currentPath.pathId}-${state.pointIndex + 1}`;
if (!tryReserveWaypoint(uuid, nextWaypointId)) {
// ⏸ Wait here until waypoint becomes free
return;
}
// Step 2: Move along current path
/**
* 🟢 STEP 2: Move along path once at start
*/
const currentPoint = new Vector3(
...pathPoints[state.pointIndex].position
);
@@ -244,30 +138,19 @@ export default function VehicleAnimator2({
state.progress += moveDistance / segmentLength;
if (state.progress >= 1) {
// ✅ Release waypoint once passed
releaseWaypoint(nextWaypointId);
state.pointIndex++;
state.progress = 0;
// ✅ reached end of current path → switch to next path
if (state.pointIndex >= pathPoints.length - 1) {
state.pathIndex++;
state.pointIndex = 0;
state.progress = 0;
// 🔥 refresh path data after advancing
if (state.pathIndex < route.length) {
currentPath = route[state.pathIndex];
pathPoints = currentPath.pathPoints;
} else {
// ✅ Finished ALL paths → stop
state.pathIndex = route.length - 1;
const lastPath = route[state.pathIndex];
const lastPts = lastPath.pathPoints;
state.pointIndex = lastPts.length - 2;
state.progress = 1;
if (state.pathIndex >= route.length) {
return;
}
currentPath = route[state.pathIndex];
pathPoints = currentPath.pathPoints;
}
}
@@ -286,151 +169,129 @@ export default function VehicleAnimator2({
direction
);
mesh.quaternion.slerp(targetQuat, 0.1);
const pathCheck = handlePathCheck(currentPath.pathId, vehicleId);
console.log("pathCheck: ", pathCheck);
//
// 🟢 Log current pathId while moving
// console.log(
// `🚗 Vehicle ${uuid} moving on pathId: ${currentPath.pathId}`,
// "→",
// newPos.toArray()
// );
});
});
// const handlePathCheck = (pathId: string, vehicleId: string) => {
// const { paths, allPaths, setAllPaths } = useCreatedPaths.getState();
// useFrame((_, delta) => {
// if (!isPlaying) return;
// const normalize = (v: any) => String(v ?? "").trim();
// vehiclesData.forEach((vehicle) => {
// console.log("vehiclesData: ", vehiclesData);
// const { vehicleId, route } = vehicle;
// if (!route || route.length === 0) return;
// // Find path
// const path = paths.find(
// (p: any) => normalize(p.pathId) === normalize(pathId)
// );
// if (!path) {
//
// return false;
// }
// const mesh = scene.getObjectByProperty("uuid", vehicleId);
// if (!mesh) return;
// const uuid = vehicleId;
// // ✅ Initialize state
// if (!vehicleMovementState.current[uuid]) {
// vehicleMovementState.current[uuid] = {
// index: 0,
// pointIndex: 0,
// pathIndex: 0,
// progress: 0,
// hasStarted: false,
// };
// }
// const state = vehicleMovementState.current[uuid];
// let currentPath = route[state.pathIndex];
// if (
// !currentPath ||
// !currentPath.pathPoints ||
// currentPath.pathPoints.length < 2
// )
// return;
// let pathPoints = currentPath.pathPoints;
// const pathStart = new Vector3(...pathPoints[0].position);
// // Step 1: move mesh to start
// if (!state.hasStarted) {
// const distanceToStart = mesh.position.distanceTo(pathStart);
// const step = speed * delta;
// if (distanceToStart <= step) {
// mesh.position.copy(pathStart);
// mesh.quaternion.identity();
// state.hasStarted = true;
// return;
// }
// const direction = pathStart.clone().sub(mesh.position).normalize();
// mesh.position.add(direction.clone().multiplyScalar(step));
// const forward = new Vector3(0, 0, 1);
// const targetQuat = new Quaternion().setFromUnitVectors(
// forward,
// direction
// );
// mesh.quaternion.slerp(targetQuat, 0.1);
// return;
// }
// // managerRef.current = { pathId: currentPath.pathId, vehicleId: uuid };
// // // ✅ only setState when pathId actually changes
// // if (managerData?.pathId !== currentPath.pathId) {
// // setManagerData({ pathId: currentPath.pathId, vehicleId: uuid });
// // }
// if (
// !managerRef.current ||
// managerRef.current.pathId !== currentPath.pathId ||
// managerRef.current.vehicleId !== uuid
// ) {
// managerRef.current = { pathId: currentPath.pathId, vehicleId: uuid };
// }
// // Step 2: Move along current path
// const currentPoint = new Vector3(
// ...pathPoints[state.pointIndex].position
// );
// const nextPoint = new Vector3(
// ...pathPoints[state.pointIndex + 1].position
// // If path already reserved → always reject
// if (!path.isAvailable) {
// console.log(
// `🚨 Path ${pathId} is already reserved by vehicle ${vehicleId}`
// );
// return false;
// }
//
// const segmentVector = new Vector3().subVectors(nextPoint, currentPoint);
// const segmentLength = segmentVector.length();
// const direction = segmentVector.clone().normalize();
// // Reserve the path for this vehicle
// const updated = allPaths.map((p: any) =>
// normalize(p.pathId) === normalize(pathId)
// ? { ...p, vehicleId, isAvailable: false }
// : p
// );
// console.log("speed: ", speed);
// const moveDistance = speed * delta;
// state.progress += moveDistance / segmentLength;
// setAllPaths(updated);
// if (state.progress >= 1) {
// state.pointIndex++;
// state.progress = 0;
//
// return true;
// };
// // ✅ reached end of current path → switch to next path
// if (state.pointIndex >= pathPoints.length - 1) {
// state.pathIndex++;
// state.pointIndex = 0;
// state.progress = 0;
const handlePathCheck = (pathId: string, vehicleId: string) => {
const normalize = (v: any) => String(v ?? "").trim();
// // 🔥 refresh path data after advancing
// if (state.pathIndex < route.length) {
// currentPath = route[state.pathIndex];
// pathPoints = currentPath.pathPoints;
// } else {
// // ✅ Finished ALL paths → stop
// state.pathIndex = route.length - 1;
// const lastPath = route[state.pathIndex];
// const lastPts = lastPath.pathPoints;
// state.pointIndex = lastPts.length - 2;
// state.progress = 1;
// }
// }
// }
// Find path
const path = useCreatedPaths
.getState()
.allPaths.find((p: any) => normalize(p.pathId) === normalize(pathId));
// // Interpolate position
// const newPos = new Vector3().lerpVectors(
// new Vector3(...pathPoints[state.pointIndex].position),
// new Vector3(...pathPoints[state.pointIndex + 1].position),
// state.progress
// );
// mesh.position.copy(newPos);
if (!path) {
return false;
}
// // Smooth rotation
// const forward = new Vector3(0, 0, 1);
// const targetQuat = new Quaternion().setFromUnitVectors(
// forward,
// direction
// );
// mesh.quaternion.slerp(targetQuat, 0.1);
// });
// });
// If path already reserved → reject always
if (!path.isAvailable) {
// console.warn(
// `🚨 Path ${pathId} is already reserved by vehicle ${vehicleId}`
// );
echo.warn(`Path ${pathId}`);
return false;
} else {
console.log("path is reserved");
}
// Reserve the path properly with vehicleId
const updated = allPaths.map((p: any) =>
normalize(p.pathId) === normalize(pathId)
? { ...p, vehicleId, isAvailable: false }
: p
);
console.log("updated: ", updated);
setAllPaths(updated);
return true;
};
// const manager = usePathManager(
// managerRef.current?.pathId,
// managerRef.current?.vehicleId
// );
// useEffect(() => {
// console.log("managerRef.current: ", managerRef.current);
// if (managerRef.current) {
// console.log("Path manager updated:", manager);
// }
// }, [manager, managerRef.current]);
return null;
}
// const handlePathCheck = (pathId: string, vehicleId: string) => {
// const allPaths = useCreatedPaths.getState().allPaths;
// // find the path were checking
// const path = allPaths.find((p: any) => p.pathId === pathId);
// if (!path) {
//
// return false;
// }
// // if path is available, update it with vehicleId and mark unavailable
// if (path.isAvailable) {
// const updated = allPaths.map((p: any) =>
// p.pathId === pathId ? { ...p, vehicleId, isAvailable: false } : p
// );
//
// //
// // setAllPaths(updated); // uncomment if you want to persist update
// return true; // path was available
// }
//
// return false; // path not available
// };
// useEffect(() => {
//
// if (managerRef.current) {
//
// }
// }, [manager, managerRef.current]);

View File

@@ -234,10 +234,6 @@ export default function VehicleInstance2({
const index = vehiclesDataRef.current.findIndex(
(v) => v.vehicleId === modelUuid
);
console.log(
"vehiclesDataRef.current: ",
vehiclesDataRef.current
);
if (index !== -1) {
const updatedVehicles = [...vehiclesDataRef.current];
@@ -265,6 +261,7 @@ export default function VehicleInstance2({
useEffect(() => {
const canvasElement = gl.domElement;
canvasElement.addEventListener("contextmenu", handleContextMenu);
console.log("vehiclesDataRef.current: ", vehiclesDataRef.current);
return () => {
canvasElement.removeEventListener("contextmenu", handleContextMenu);
};

View File

@@ -21,11 +21,7 @@ function VehicleInstances() {
selectedPointId: val.point.uuid,
}));
setVehiclesData(updatedVehicles);
}, [vehicles]);
useEffect(() => {
console.log("vehiclesData", vehiclesData);
}, [vehiclesData]);
}, []);
return (
<>

View File

@@ -63,7 +63,6 @@ export default function PathCreator() {
const POINT_SNAP_THRESHOLD = 0.5;
const CAN_POINT_SNAP = true;
useEffect(() => {}, [paths]);
const getAllOtherPathPoints = useCallback((): PointData[] => {
if (draftPoints.length === 0) return [];
@@ -145,7 +144,6 @@ export default function PathCreator() {
];
});
useEffect(() => {}, [paths]);
const getPathPointById = (uuid: any) => {
for (const path of paths) {