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

View File

@ -336,4 +336,31 @@ interface VehicleEventsSchema {
speed: 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;
// };