:updated swap"
This commit is contained in:
parent
5fb911f1a1
commit
280fe59a14
|
@ -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;
|
||||
})
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -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;
|
||||
// };
|
Loading…
Reference in New Issue