:updated swap"

This commit is contained in:
SreeNath14 2025-04-04 09:54:08 +05:30
parent 5fb911f1a1
commit 280fe59a14
2 changed files with 116 additions and 114 deletions

View File

@ -78,7 +78,7 @@
// const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({ // const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
// processes, // processes,
// }) => { // }) => {
// //
// const gltf = useLoader(GLTFLoader, boxGltb) as GLTF; // const gltf = useLoader(GLTFLoader, boxGltb) as GLTF;
// const { isPlaying } = usePlayButtonStore(); // const { isPlaying } = usePlayButtonStore();
// const groupRef = useRef<THREE.Group>(null); // const groupRef = useRef<THREE.Group>(null);
@ -646,14 +646,13 @@ interface SpawnedObject {
material: THREE.Material; material: THREE.Material;
spawnTime: number; spawnTime: number;
currentMaterialType: string; currentMaterialType: string;
position: THREE.Vector3; // The position of the object position: THREE.Vector3;
} }
interface ProcessAnimationState { interface ProcessAnimationState {
spawnedObjects: { [objectId: string]: SpawnedObject }; spawnedObjects: { [objectId: string]: SpawnedObject };
nextSpawnTime: number; nextSpawnTime: number;
objectIdCounter: number; objectIdCounter: number;
// New fields for process-wide delay
isProcessDelaying: boolean; isProcessDelaying: boolean;
processDelayStartTime: number; processDelayStartTime: number;
processDelayDuration: number; processDelayDuration: number;
@ -662,10 +661,10 @@ interface ProcessAnimationState {
const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
processes, processes,
}) => { }) => {
const gltf = useLoader(GLTFLoader, boxGltb) as GLTF; const gltf = useLoader(GLTFLoader, boxGltb) as GLTF;
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const groupRef = useRef<THREE.Group>(null); const groupRef = useRef<THREE.Group>(null);
const debugRef = useRef<boolean>(false);
const [animationStates, setAnimationStates] = useState< const [animationStates, setAnimationStates] = useState<
Record<string, ProcessAnimationState> Record<string, ProcessAnimationState>
@ -674,15 +673,8 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
// Base materials // Base materials
const baseMaterials = useMemo( const baseMaterials = useMemo(
() => ({ () => ({
Wood: new THREE.MeshStandardMaterial({ color: 0x8b4513 }), Box: new THREE.MeshStandardMaterial({ color: 0x8b4513 }),
Box: new THREE.MeshPhongMaterial({ Crate: new THREE.MeshStandardMaterial({ color: 0x00ff00 }),
color: 0xcccccc,
}),
Crate: new THREE.MeshStandardMaterial({
color: 0x00aaff,
metalness: 0.1,
roughness: 0.5,
}),
Default: new THREE.MeshStandardMaterial({ color: 0x00ff00 }), Default: new THREE.MeshStandardMaterial({ color: 0x00ff00 }),
}), }),
[] []
@ -701,7 +693,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
spawnedObjects: {}, spawnedObjects: {},
nextSpawnTime: 0, nextSpawnTime: 0,
objectIdCounter: 0, objectIdCounter: 0,
// Initialize process-wide delay state
isProcessDelaying: false, isProcessDelaying: false,
processDelayStartTime: 0, processDelayStartTime: 0,
processDelayDuration: 0, processDelayDuration: 0,
@ -710,7 +701,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
setAnimationStates(newStates); setAnimationStates(newStates);
}, [isPlaying, processes]); }, [isPlaying, processes]);
// Find spawn point in a process
const findSpawnPoint = (process: ProcessData): ProcessPoint | null => { const findSpawnPoint = (process: ProcessData): ProcessPoint | null => {
for (const path of process.paths || []) { for (const path of process.paths || []) {
for (const point of path.points || []) { for (const point of path.points || []) {
@ -725,22 +715,16 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
return null; return null;
}; };
// Find the corresponding animation path point for a spawn point
const findAnimationPathPoint = ( const findAnimationPathPoint = (
process: ProcessData, process: ProcessData,
spawnPoint: ProcessPoint spawnPoint: ProcessPoint
): THREE.Vector3 => { ): THREE.Vector3 => {
// If we have an animation path, use the first point
if (process.animationPath && process.animationPath.length > 0) { if (process.animationPath && process.animationPath.length > 0) {
// Find the index of this point in the path
let pointIndex = 0; let pointIndex = 0;
// Try to find the corresponding point in the animation path
for (const path of process.paths || []) { for (const path of process.paths || []) {
for (let i = 0; i < (path.points?.length || 0); i++) { for (let i = 0; i < (path.points?.length || 0); i++) {
const point = path.points?.[i]; const point = path.points?.[i];
if (point && point.uuid === spawnPoint.uuid) { if (point && point.uuid === spawnPoint.uuid) {
// Found the matching point
if (process.animationPath[pointIndex]) { if (process.animationPath[pointIndex]) {
const p = process.animationPath[pointIndex]; const p = process.animationPath[pointIndex];
return new THREE.Vector3(p.x, p.y, p.z); return new THREE.Vector3(p.x, p.y, p.z);
@ -749,16 +733,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
pointIndex++; pointIndex++;
} }
} }
// Fallback to the spawn point's position
return new THREE.Vector3(
spawnPoint.position[0],
spawnPoint.position[1],
spawnPoint.position[2]
);
} }
// If no animation path, use the spawn point's position
return new THREE.Vector3( return new THREE.Vector3(
spawnPoint.position[0], spawnPoint.position[0],
spawnPoint.position[1], spawnPoint.position[1],
@ -766,7 +741,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
); );
}; };
// Create a new spawned object
const createSpawnedObject = ( const createSpawnedObject = (
process: ProcessData, process: ProcessData,
currentTime: number, currentTime: number,
@ -778,8 +752,14 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
...(process.customMaterials || {}), ...(process.customMaterials || {}),
}; };
// Get the position where we should spawn
const spawnPosition = findAnimationPathPoint(process, spawnPoint); const spawnPosition = findAnimationPathPoint(process, spawnPoint);
const material =
processMaterials[materialType as keyof typeof processMaterials] ||
baseMaterials.Default;
if (debugRef.current) {
console.log(`Creating object with material: ${materialType}`, material);
}
return { return {
ref: React.createRef(), ref: React.createRef(),
@ -795,34 +775,50 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
currentPathIndex: 0, currentPathIndex: 0,
}, },
visible: true, visible: true,
material: material: material,
processMaterials[materialType as keyof typeof processMaterials] ||
baseMaterials.Default,
currentMaterialType: materialType, currentMaterialType: materialType,
spawnTime: currentTime, spawnTime: currentTime,
position: spawnPosition, // Store the position directly position: spawnPosition,
}; };
}; };
// Handle material swap for an object
const handleMaterialSwap = ( const handleMaterialSwap = (
processId: string, processId: string,
objectId: string, objectId: string,
materialType: string materialType: string
) => { ) => {
if (debugRef.current) {
console.log(`Attempting material swap to: ${materialType}`);
}
setAnimationStates((prev) => { setAnimationStates((prev) => {
const processState = prev[processId]; const processState = prev[processId];
if (!processState || !processState.spawnedObjects[objectId]) return prev; if (!processState || !processState.spawnedObjects[objectId]) {
if (debugRef.current) console.log("Object not found for swap");
return prev;
}
const process = processes.find((p) => p.id === processId); const process = processes.find((p) => p.id === processId);
if (!process) {
if (debugRef.current) console.log("Process not found");
return prev;
}
const processMaterials = { const processMaterials = {
...baseMaterials, ...baseMaterials,
...(process?.customMaterials || {}), ...(process.customMaterials || {}),
}; };
const newMaterial = const newMaterial =
processMaterials[materialType as keyof typeof processMaterials] || processMaterials[materialType as keyof typeof processMaterials];
baseMaterials.Default; if (!newMaterial) {
if (debugRef.current) console.log(`Material ${materialType} not found`);
return prev;
}
if (debugRef.current) {
console.log(`Swapping material for ${objectId} to ${materialType}`);
}
return { return {
...prev, ...prev,
@ -841,7 +837,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
}); });
}; };
// Handle point actions for an object
const handlePointActions = ( const handlePointActions = (
processId: string, processId: string,
objectId: string, objectId: string,
@ -853,6 +848,10 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
actions.forEach((action) => { actions.forEach((action) => {
if (!action.isUsed) return; if (!action.isUsed) return;
if (debugRef.current) {
console.log(`Processing action: ${action.type} for ${objectId}`);
}
switch (action.type) { switch (action.type) {
case "Delay": case "Delay":
setAnimationStates((prev) => { setAnimationStates((prev) => {
@ -871,18 +870,16 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
...prev, ...prev,
[processId]: { [processId]: {
...processState, ...processState,
// Set process-wide delay instead of object-specific delay
isProcessDelaying: true, isProcessDelaying: true,
processDelayStartTime: currentTime, processDelayStartTime: currentTime,
processDelayDuration: delayDuration, processDelayDuration: delayDuration,
// Update the specific object's state as well
spawnedObjects: { spawnedObjects: {
...processState.spawnedObjects, ...processState.spawnedObjects,
[objectId]: { [objectId]: {
...processState.spawnedObjects[objectId], ...processState.spawnedObjects[objectId],
state: { state: {
...processState.spawnedObjects[objectId].state, ...processState.spawnedObjects[objectId].state,
isAnimating: false, // Explicitly pause animation during delay isAnimating: false,
isDelaying: true, isDelaying: true,
delayStartTime: currentTime, delayStartTime: currentTime,
currentDelayDuration: delayDuration, currentDelayDuration: delayDuration,
@ -931,12 +928,10 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
return shouldStopAnimation; return shouldStopAnimation;
}; };
// Check if point has non-inherit actions
const hasNonInheritActions = (actions: PointAction[] = []): boolean => { const hasNonInheritActions = (actions: PointAction[] = []): boolean => {
return actions.some((action) => action.isUsed && action.type !== "Inherit"); return actions.some((action) => action.isUsed && action.type !== "Inherit");
}; };
// Get point data for current animation index
const getPointDataForAnimationIndex = ( const getPointDataForAnimationIndex = (
process: ProcessData, process: ProcessData,
index: number index: number
@ -958,7 +953,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
return null; return null;
}; };
// Spawn objects for all processes
useFrame((state) => { useFrame((state) => {
if (!isPlaying) return; if (!isPlaying) return;
@ -970,18 +964,14 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
const processState = newStates[process.id]; const processState = newStates[process.id];
if (!processState) return; if (!processState) return;
// Skip spawning if the process is currently in a delay
if (processState.isProcessDelaying) { if (processState.isProcessDelaying) {
// Check if delay is over
if ( if (
currentTime - processState.processDelayStartTime >= currentTime - processState.processDelayStartTime >=
processState.processDelayDuration processState.processDelayDuration
) { ) {
// Reset process delay state
newStates[process.id] = { newStates[process.id] = {
...processState, ...processState,
isProcessDelaying: false, isProcessDelaying: false,
// Reset delay state on all objects in this process
spawnedObjects: Object.entries( spawnedObjects: Object.entries(
processState.spawnedObjects processState.spawnedObjects
).reduce( ).reduce(
@ -993,8 +983,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
...obj.state, ...obj.state,
isDelaying: false, isDelaying: false,
delayComplete: true, delayComplete: true,
isAnimating: true, // Ensure animation resumes isAnimating: true,
// Force a small progress to ensure movement starts
progress: progress:
obj.state.progress === 0 ? 0.001 : obj.state.progress, obj.state.progress === 0 ? 0.001 : obj.state.progress,
}, },
@ -1004,7 +993,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
), ),
}; };
} }
return; // Skip spawning while delaying return;
} }
const spawnPoint = findSpawnPoint(process); const spawnPoint = findSpawnPoint(process);
@ -1022,8 +1011,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
if (currentTime >= processState.nextSpawnTime) { if (currentTime >= processState.nextSpawnTime) {
const objectId = `obj-${process.id}-${processState.objectIdCounter}`; const objectId = `obj-${process.id}-${processState.objectIdCounter}`;
// Create the new object with the spawn point
const newObject = createSpawnedObject( const newObject = createSpawnedObject(
process, process,
currentTime, currentTime,
@ -1047,7 +1034,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
}); });
}); });
// Animate objects for all processes
useFrame((state, delta) => { useFrame((state, delta) => {
if (!isPlaying) return; if (!isPlaying) return;
@ -1059,18 +1045,14 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
const processState = newStates[process.id]; const processState = newStates[process.id];
if (!processState) return; if (!processState) return;
// Check if the process-wide delay is active
if (processState.isProcessDelaying) { if (processState.isProcessDelaying) {
// Check if the delay has completed
if ( if (
currentTime - processState.processDelayStartTime >= currentTime - processState.processDelayStartTime >=
processState.processDelayDuration processState.processDelayDuration
) { ) {
// Reset process delay state AND resume animation
newStates[process.id] = { newStates[process.id] = {
...processState, ...processState,
isProcessDelaying: false, isProcessDelaying: false,
// Reset delay state on all objects in this process AND ensure isAnimating is true
spawnedObjects: Object.entries( spawnedObjects: Object.entries(
processState.spawnedObjects processState.spawnedObjects
).reduce( ).reduce(
@ -1082,8 +1064,7 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
...obj.state, ...obj.state,
isDelaying: false, isDelaying: false,
delayComplete: true, delayComplete: true,
isAnimating: true, // Ensure animation resumes isAnimating: true,
// Important: Force progress to a small positive value to ensure movement
progress: progress:
obj.state.progress === 0 ? 0.005 : obj.state.progress, obj.state.progress === 0 ? 0.005 : obj.state.progress,
}, },
@ -1092,10 +1073,8 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
{} {}
), ),
}; };
// Skip the rest of the processing for this frame to allow the state update to take effect
return newStates; return newStates;
} else { } else {
// If we're still in a process-wide delay, don't animate anything
return newStates; return newStates;
} }
} }
@ -1109,13 +1088,11 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
Object.entries(processState.spawnedObjects).forEach( Object.entries(processState.spawnedObjects).forEach(
([objectId, obj]) => { ([objectId, obj]) => {
// Skip objects that are explicitly not visible
if (!obj.visible) return; if (!obj.visible) return;
const currentRef = gltf?.scene ? obj.ref.current : obj.ref.current; const currentRef = gltf?.scene ? obj.ref.current : obj.ref.current;
if (!currentRef) return; if (!currentRef) return;
// Set the position when the reference is first available
if ( if (
obj.position && obj.position &&
obj.state.currentIndex === 0 && obj.state.currentIndex === 0 &&
@ -1126,27 +1103,21 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
const stateRef = obj.state; const stateRef = obj.state;
// Check if we're delaying at the object level and update accordingly
if (stateRef.isDelaying) { if (stateRef.isDelaying) {
if ( if (
currentTime - stateRef.delayStartTime >= currentTime - stateRef.delayStartTime >=
stateRef.currentDelayDuration stateRef.currentDelayDuration
) { ) {
// Delay is complete, resume animation
stateRef.isDelaying = false; stateRef.isDelaying = false;
stateRef.delayComplete = true; stateRef.delayComplete = true;
stateRef.isAnimating = true; // Explicitly resume animation stateRef.isAnimating = true;
// Force movement from the current point by setting progress to a small value
// if we're at the start of a segment
if (stateRef.progress === 0) { if (stateRef.progress === 0) {
stateRef.progress = 0.005; stateRef.progress = 0.005;
} }
// Force an immediate position update to ensure visually accurate position
const nextPointIdx = stateRef.currentIndex + 1; const nextPointIdx = stateRef.currentIndex + 1;
if (nextPointIdx < path.length) { if (nextPointIdx < path.length) {
// Calculate the position slightly ahead of the current point
const slightProgress = Math.max(stateRef.progress, 0.005); const slightProgress = Math.max(stateRef.progress, 0.005);
currentRef.position.lerpVectors( currentRef.position.lerpVectors(
path[stateRef.currentIndex], path[stateRef.currentIndex],
@ -1157,23 +1128,25 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
); );
} }
} else { } else {
// Still delaying, don't animate this object
updatedObjects[objectId] = { ...obj, state: { ...stateRef } }; updatedObjects[objectId] = { ...obj, state: { ...stateRef } };
return; return;
} }
} }
// Skip animation if the object shouldn't be animating
if (!stateRef.isAnimating) return; if (!stateRef.isAnimating) return;
// Get current point data
const currentPointData = getPointDataForAnimationIndex( const currentPointData = getPointDataForAnimationIndex(
process, process,
stateRef.currentIndex stateRef.currentIndex
); );
// Execute actions when arriving at a new point
if (stateRef.progress === 0 && currentPointData?.actions) { if (stateRef.progress === 0 && currentPointData?.actions) {
if (debugRef.current) {
console.log(
`At point ${stateRef.currentIndex} with actions:`,
currentPointData.actions
);
}
const shouldStop = handlePointActions( const shouldStop = handlePointActions(
process.id, process.id,
objectId, objectId,
@ -1195,10 +1168,6 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
currentPointData.actions currentPointData.actions
); );
if (shouldStop) { if (shouldStop) {
// uncomment this or write own logic to handle the object when reaching the last point of the process
// currentRef.position.copy(path[stateRef.currentIndex]);
// delete updatedObjects[objectId];
return; return;
} }
} }
@ -1210,35 +1179,30 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
path[stateRef.currentIndex].distanceTo(nextPoint); path[stateRef.currentIndex].distanceTo(nextPoint);
const movement = stateRef.speed * delta; const movement = stateRef.speed * delta;
// If we just resumed from a delay, ensure we make actual progress
if (stateRef.delayComplete && stateRef.progress < 0.01) { if (stateRef.delayComplete && stateRef.progress < 0.01) {
// Boost initial movement after delay to ensure visible progress stateRef.progress = 0.05;
stateRef.progress = 0.05; // Small but visible initial progress stateRef.delayComplete = false;
stateRef.delayComplete = false; // Reset flag so we don't do this again
} else { } else {
// Normal progress calculation
stateRef.progress += movement / distance; stateRef.progress += movement / distance;
} }
if (stateRef.progress >= 1) { if (stateRef.progress >= 1) {
// We've reached the next point
stateRef.currentIndex = nextPointIdx; stateRef.currentIndex = nextPointIdx;
stateRef.progress = 0; stateRef.progress = 0;
currentRef.position.copy(nextPoint); currentRef.position.copy(nextPoint);
// Check if we need to execute actions at this new point
const newPointData = getPointDataForAnimationIndex( const newPointData = getPointDataForAnimationIndex(
process, process,
stateRef.currentIndex stateRef.currentIndex
); );
if (newPointData?.actions) { if (newPointData?.actions && debugRef.current) {
// We've arrived at a new point with actions, handle them in the next frame console.log(
// We don't call handlePointActions directly here to avoid state update issues `Reached new point with actions:`,
// The actions will be handled in the next frame when progress is 0 newPointData.actions
);
} }
} else { } else {
// Normal path interpolation
currentRef.position.lerpVectors( currentRef.position.lerpVectors(
path[stateRef.currentIndex], path[stateRef.currentIndex],
nextPoint, nextPoint,
@ -1274,29 +1238,40 @@ const ProcessAnimator: React.FC<{ processes: ProcessData[] }> = ({
const process = processes.find((p) => p.id === processId); const process = processes.find((p) => p.id === processId);
const renderAs = process?.renderAs || "custom"; const renderAs = process?.renderAs || "custom";
return renderAs === "box" ? ( if (renderAs === "box") {
<mesh return (
key={objectId} <mesh
ref={obj.ref as React.RefObject<THREE.Mesh>} key={objectId}
material={obj.material} ref={obj.ref as React.RefObject<THREE.Mesh>}
position={obj.position} // Set position directly in the JSX material={obj.material}
> position={obj.position}
<boxGeometry args={[1, 1, 1]} /> >
</mesh> <boxGeometry args={[1, 1, 1]} />
) : ( </mesh>
gltf?.scene && ( );
}
if (gltf?.scene) {
// Clone the scene and apply the material to all meshes
const clonedScene = gltf.scene.clone();
clonedScene.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material = obj.material;
}
});
return (
<group <group
key={objectId} key={objectId}
ref={obj.ref as React.RefObject<THREE.Group>} ref={obj.ref as React.RefObject<THREE.Group>}
position={obj.position} // Set position directly in the JSX position={obj.position}
> >
<primitive <primitive object={clonedScene} />
object={gltf.scene.clone()}
material={obj.material}
/>
</group> </group>
) );
); }
return null;
}) })
)} )}
</> </>

View File

@ -336,4 +336,31 @@ interface VehicleEventsSchema {
speed: number; speed: number;
}; };
position: [number, number, number]; position: [number, number, number];
} }
// interface ArmSchema {
// modeluuid: string;
// modelName: string;
// type: 'Arm';
// point: {
// uuid: string;
// position: [number, number, number];
// actions: { MaterialId: string, }[] |.;
// connections: { source: { pathUUID: string; pointUUID: string }; targets: { pathUUID: string; pointUUID: string }[] };
// speed: number;
// };
// position: [number, number, number];
// }
// export type FloorItemType = {
// modeluuid: string;
// modelname: string;
// position: [number, number, number];
// rotation: { x: number; y: number; z: number };
// modelfileID: string;
// isLocked: boolean;
// isVisible: boolean;
// };