feat: Introduce animation components for worker, manufacturer, and operator humans, model animators, and a new vehicle state management store.

This commit is contained in:
2025-12-20 12:29:12 +05:30
parent d0e18d5010
commit 036164155f
5 changed files with 42 additions and 59 deletions

View File

@@ -60,14 +60,16 @@ export function ModelAnimator({ asset, gltfScene }: ModelAnimatorProps) {
if (isPlaying && currentAction && !isPaused) { if (isPlaying && currentAction && !isPaused) {
blendFactor.current = 0; blendFactor.current = 0;
Object.values(actions.current).forEach((action) => {
if (action !== currentAction) {
action.stop();
}
});
currentAction.reset(); currentAction.reset();
currentAction.setLoop(loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce, loopAnimation ? Infinity : 1); currentAction.setLoop(loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce, loopAnimation ? Infinity : 1);
currentAction.clampWhenFinished = true; currentAction.clampWhenFinished = true;
if (previousAction && previousAction !== currentAction) {
previousAction.crossFadeTo(currentAction, blendDuration, false);
}
currentAction.play(); currentAction.play();
mixerRef.current.addEventListener("finished", handleAnimationComplete); mixerRef.current.addEventListener("finished", handleAnimationComplete);
setPreviousAnimation(current); setPreviousAnimation(current);

View File

@@ -108,15 +108,8 @@ function ManufacturerAnimator({ path, handleCallBack, human, reset }: Readonly<M
const isAligned = angle < 0.01; const isAligned = angle < 0.01;
if (isAligned) { if (isAligned) {
const distanceStep = delta * (speed * human.speed); progressRef.current = Math.min(progressRef.current + delta * (speed * human.speed), totalDistance);
const previousProgress = progressRef.current; incrementDistanceTraveled(human.modelUuid, delta * (speed * human.speed));
progressRef.current = Math.min(progressRef.current + distanceStep, totalDistance);
const actualStep = progressRef.current - previousProgress;
if (actualStep > 0) {
incrementDistanceTraveled(human.modelUuid, actualStep);
}
const t = (progressRef.current - accumulatedDistance) / segmentDistance; const t = (progressRef.current - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t); const position = start.clone().lerp(end, t);
object.position.copy(position); object.position.copy(position);

View File

@@ -116,15 +116,8 @@ function OperatorAnimator({ path, handleCallBack, human, reset }: Readonly<Worke
const isAligned = angle < 0.01; const isAligned = angle < 0.01;
if (isAligned) { if (isAligned) {
const distanceStep = delta * (speed * human.speed); progressRef.current = Math.min(progressRef.current + delta * (speed * human.speed), totalDistance);
const previousProgress = progressRef.current; incrementDistanceTraveled(human.modelUuid, delta * (speed * human.speed));
progressRef.current = Math.min(progressRef.current + distanceStep, totalDistance);
const actualStep = progressRef.current - previousProgress;
if (actualStep > 0) {
incrementDistanceTraveled(human.modelUuid, actualStep);
}
const t = (progressRef.current - accumulatedDistance) / segmentDistance; const t = (progressRef.current - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t); const position = start.clone().lerp(end, t);
object.position.copy(position); object.position.copy(position);

View File

@@ -118,15 +118,8 @@ function WorkerAnimator({ path, handleCallBack, human, reset, startUnloadingProc
const isAligned = angle < 0.01; const isAligned = angle < 0.01;
if (isAligned) { if (isAligned) {
const distanceStep = delta * (speed * human.speed); progressRef.current = Math.min(progressRef.current + delta * (speed * human.speed), totalDistance);
const previousProgress = progressRef.current; incrementDistanceTraveled(human.modelUuid, delta * (speed * human.speed));
progressRef.current = Math.min(progressRef.current + distanceStep, totalDistance);
const actualStep = progressRef.current - previousProgress;
if (actualStep > 0) {
incrementDistanceTraveled(human.modelUuid, actualStep);
}
const t = (progressRef.current - accumulatedDistance) / segmentDistance; const t = (progressRef.current - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t); const position = start.clone().lerp(end, t);
object.position.copy(position); object.position.copy(position);

View File

@@ -6,10 +6,7 @@ interface VehiclesStore {
addVehicle: (productUuid: string, event: VehicleEventSchema) => void; addVehicle: (productUuid: string, event: VehicleEventSchema) => void;
removeVehicle: (modelUuid: string) => void; removeVehicle: (modelUuid: string) => void;
updateVehicle: ( updateVehicle: (modelUuid: string, updates: Partial<Omit<VehicleStatus, "modelUuid" | "productUuid">>) => void;
modelUuid: string,
updates: Partial<Omit<VehicleStatus, "modelUuid" | "productUuid">>
) => void;
addPathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], point: VehicleAction["paths"]["initPickup"][number]) => VehicleAction["paths"]; addPathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], point: VehicleAction["paths"]["initPickup"][number]) => VehicleAction["paths"];
updatePathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], pointId: string, updates: Partial<VehicleAction["paths"]["initPickup"][number]>) => VehicleAction["paths"]; updatePathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], pointId: string, updates: Partial<VehicleAction["paths"]["initPickup"][number]>) => VehicleAction["paths"];
deletePathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], pointId: string) => VehicleAction["paths"]; deletePathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], pointId: string) => VehicleAction["paths"];
@@ -22,17 +19,15 @@ interface VehiclesStore {
incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void; incrementVehicleLoad: (modelUuid: string, incrementBy: number) => void;
decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void; decrementVehicleLoad: (modelUuid: string, decrementBy: number) => void;
setVehicleLoad: (modelUuid: string, load: number) => void; setVehicleLoad: (modelUuid: string, load: number) => void;
setVehicleState: ( setVehicleState: (modelUuid: string, newState: VehicleStatus["state"]) => void;
modelUuid: string,
newState: VehicleStatus["state"]
) => void;
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void; addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void; setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined; removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string } | undefined;
getLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined; getLastMaterial: (modelUuid: string) => { materialId: string; materialType: string } | undefined;
clearCurrentMaterials: (modelUuid: string) => void; clearCurrentMaterials: (modelUuid: string) => void;
incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
incrementIdleTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
incrementDistanceTraveled: (modelUuid: string, incrementBy: number) => void;
resetTime: (modelUuid: string) => void; resetTime: (modelUuid: string) => void;
getVehicleById: (modelUuid: string) => VehicleStatus | undefined; getVehicleById: (modelUuid: string) => VehicleStatus | undefined;
@@ -53,7 +48,7 @@ export const createVehicleStore = () => {
state.vehicles.push({ state.vehicles.push({
...event, ...event,
productUuid, productUuid,
currentPhase: 'stationed', currentPhase: "stationed",
isActive: false, isActive: false,
isPicking: false, isPicking: false,
idleTime: 0, idleTime: 0,
@@ -61,7 +56,7 @@ export const createVehicleStore = () => {
currentLoad: 0, currentLoad: 0,
currentMaterials: [], currentMaterials: [],
distanceTraveled: 0, distanceTraveled: 0,
state: 'idle' state: "idle",
}); });
} }
}); });
@@ -69,9 +64,7 @@ export const createVehicleStore = () => {
removeVehicle: (modelUuid) => { removeVehicle: (modelUuid) => {
set((state) => { set((state) => {
state.vehicles = state.vehicles.filter( state.vehicles = state.vehicles.filter((v) => v.modelUuid !== modelUuid);
(v) => v.modelUuid !== modelUuid
);
}); });
}, },
@@ -87,7 +80,7 @@ export const createVehicleStore = () => {
addPathPoint: (modelUuid, pathKey, point) => { addPathPoint: (modelUuid, pathKey, point) => {
let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] }; let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] };
set((state) => { set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
const path = vehicle.point.action.paths[pathKey]; const path = vehicle.point.action.paths[pathKey];
path.push(point); path.push(point);
@@ -100,10 +93,10 @@ export const createVehicleStore = () => {
updatePathPoint: (modelUuid, pathKey, pointId, updates) => { updatePathPoint: (modelUuid, pathKey, pointId, updates) => {
let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] }; let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] };
set((state) => { set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
const path = vehicle.point.action.paths[pathKey]; const path = vehicle.point.action.paths[pathKey];
const index = path.findIndex(p => p.pointId === pointId); const index = path.findIndex((p) => p.pointId === pointId);
if (index !== -1) { if (index !== -1) {
Object.assign(path[index], updates); Object.assign(path[index], updates);
updatedPaths = vehicle.point.action.paths; updatedPaths = vehicle.point.action.paths;
@@ -116,10 +109,10 @@ export const createVehicleStore = () => {
deletePathPoint: (modelUuid, pathKey, pointId) => { deletePathPoint: (modelUuid, pathKey, pointId) => {
let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] }; let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] };
set((state) => { set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
const path = vehicle.point.action.paths[pathKey]; const path = vehicle.point.action.paths[pathKey];
vehicle.point.action.paths[pathKey] = path.filter(p => p.pointId !== pointId); vehicle.point.action.paths[pathKey] = path.filter((p) => p.pointId !== pointId);
updatedPaths = vehicle.point.action.paths; updatedPaths = vehicle.point.action.paths;
} }
}); });
@@ -134,7 +127,7 @@ export const createVehicleStore = () => {
setCurrentPhase: (modelUuid, phase) => { setCurrentPhase: (modelUuid, phase) => {
set((state) => { set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
vehicle.currentPhase = phase; vehicle.currentPhase = phase;
} }
@@ -223,7 +216,7 @@ export const createVehicleStore = () => {
}, },
removeLastMaterial: (modelUuid) => { removeLastMaterial: (modelUuid) => {
let removedMaterial: { materialId: string; materialType: string; } | undefined; let removedMaterial: { materialId: string; materialType: string } | undefined;
set((state) => { set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
@@ -239,14 +232,14 @@ export const createVehicleStore = () => {
}, },
getLastMaterial: (modelUuid) => { getLastMaterial: (modelUuid) => {
let removedMaterial: { materialId: string; materialType: string; } | undefined; let removedMaterial: { materialId: string; materialType: string } | undefined;
set((state) => { set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) { if (vehicle) {
if (vehicle.currentMaterials.length > 0) { if (vehicle.currentMaterials.length > 0) {
removedMaterial = { removedMaterial = {
materialId: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialId, materialId: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialId,
materialType: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialType materialType: vehicle.currentMaterials[vehicle.currentMaterials.length - 1].materialType,
}; };
} }
} }
@@ -281,6 +274,15 @@ export const createVehicleStore = () => {
}); });
}, },
incrementDistanceTraveled: (modelUuid, incrementBy) => {
set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) {
vehicle.distanceTraveled += incrementBy;
}
});
},
resetTime: (modelUuid) => { resetTime: (modelUuid) => {
set((state) => { set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid); const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
@@ -307,7 +309,7 @@ export const createVehicleStore = () => {
return get().vehicles.filter((v) => v.isActive); return get().vehicles.filter((v) => v.isActive);
}, },
})) }))
) );
} };
export type VehicleStoreType = ReturnType<typeof createVehicleStore>; export type VehicleStoreType = ReturnType<typeof createVehicleStore>;