added pillarJib trigger

This commit is contained in:
2025-08-11 12:23:05 +05:30
parent fcc5fa64e9
commit a7dc3665ca
3 changed files with 138 additions and 52 deletions

View File

@@ -1,18 +1,20 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import * as THREE from 'three'; import * as THREE from 'three';
import { useFrame, useThree } from '@react-three/fiber'; import { useFrame, useThree } from '@react-three/fiber';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useSceneContext } from '../../../../scene/sceneContext'; import { useSceneContext } from '../../../../scene/sceneContext';
function PillarJibAnimator({ function PillarJibAnimator({
crane, crane,
points, points,
setPoints,
animationPhase, animationPhase,
setAnimationPhase, setAnimationPhase,
onAnimationComplete onAnimationComplete
}: { }: {
crane: CraneStatus; crane: CraneStatus;
points: [THREE.Vector3, THREE.Vector3] | null; points: [THREE.Vector3, THREE.Vector3] | null;
setPoints: (points: [THREE.Vector3, THREE.Vector3] | null) => void;
animationPhase: string; animationPhase: string;
setAnimationPhase: (phase: string) => void; setAnimationPhase: (phase: string) => void;
onAnimationComplete: (action: string) => void; onAnimationComplete: (action: string) => void;
@@ -22,20 +24,46 @@ function PillarJibAnimator({
const { resetAsset } = assetStore(); const { resetAsset } = assetStore();
const { isPaused } = usePauseButtonStore(); const { isPaused } = usePauseButtonStore();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { isReset } = useResetButtonStore();
const { speed } = useAnimationPlaySpeed(); const { speed } = useAnimationPlaySpeed();
const [clampedPoints, setClampedPoints] = useState<[THREE.Vector3, THREE.Vector3]>(); const [clampedPoints, setClampedPoints] = useState<[THREE.Vector3, THREE.Vector3]>();
const [currentTargetIndex, setCurrentTargetIndex] = useState<number>(0);
useEffect(() => { useEffect(() => {
if (!isPlaying) { if (!isPlaying || isReset) {
resetAsset(crane.modelUuid); resetAsset(crane.modelUuid);
setAnimationPhase('idle'); setAnimationPhase('idle');
setCurrentTargetIndex(0); setPoints(null);
} else if (animationPhase === 'idle') {
setAnimationPhase('init-hook-adjust');
} }
}, [isPlaying, scene, crane.modelUuid]); }, [isPlaying, scene, crane.modelUuid, isReset]);
useEffect(() => {
const model = scene.getObjectByProperty('uuid', crane.modelUuid);
if (!model) return;
const hook = model.getObjectByName('hook');
if (!hook) return;
const hookWorld = new THREE.Vector3();
hook.getWorldPosition(hookWorld);
if (crane.currentPhase === 'init-pickup') {
if (crane.currentMaterials.length > 0) {
const material = scene.getObjectByProperty('uuid', crane.currentMaterials[0].materialId);
if (material) {
const materialWorld = new THREE.Vector3();
material.getWorldPosition(materialWorld);
setAnimationPhase('init-hook-adjust');
setPoints(
[
new THREE.Vector3(hookWorld.x, hookWorld.y, hookWorld.z),
new THREE.Vector3(materialWorld.x, materialWorld.y + 0.5, materialWorld.z)
]
);
}
}
}
}, [crane.currentPhase])
useEffect(() => { useEffect(() => {
const model = scene.getObjectByProperty('uuid', crane.modelUuid); const model = scene.getObjectByProperty('uuid', crane.modelUuid);
@@ -99,7 +127,7 @@ function PillarJibAnimator({
}); });
setClampedPoints(newClampedPoints); setClampedPoints(newClampedPoints);
}, [crane.modelUuid]); }, [crane.modelUuid, points]);
useFrame(() => { useFrame(() => {
if (!isPlaying || isPaused || !points || !clampedPoints || animationPhase === 'idle') return; if (!isPlaying || isPaused || !points || !clampedPoints || animationPhase === 'idle') return;
@@ -122,10 +150,10 @@ function PillarJibAnimator({
if (!model.userData.animationData) { if (!model.userData.animationData) {
model.userData.animationData = { model.userData.animationData = {
originalHookY: hook.position.y, originalHookY: hook.position.y,
targetHookY: clampedPoints[currentTargetIndex].y - baseWorld.y + 0.5, targetHookY: clampedPoints[0].y - baseWorld.y,
targetDirection: new THREE.Vector2(), targetDirection: new THREE.Vector2(),
targetTrolleyX: 0, targetTrolleyX: 0,
targetWorldPosition: clampedPoints[currentTargetIndex].clone(), targetWorldPosition: clampedPoints[0].clone(),
finalHookTargetY: 0, finalHookTargetY: 0,
}; };
} }
@@ -137,11 +165,12 @@ function PillarJibAnimator({
switch (animationPhase) { switch (animationPhase) {
case 'init-hook-adjust': { case 'init-hook-adjust': {
const direction = Math.sign(animationData.targetHookY - hook.position.y); const hookWorld = new THREE.Vector3();
hook.getWorldPosition(hookWorld);
const direction = Math.sign((clampedPoints[0].y - baseWorld.y) - hookWorld.y);
hook.position.y += direction * hookSpeed; hook.position.y += direction * hookSpeed;
if (parseFloat(Math.abs(hook.position.y - animationData.targetHookY).toFixed(2)) < 0.05) { if (parseFloat(Math.abs(hookWorld.y - clampedPoints[0].y).toFixed(2)) < 0.05) {
hook.position.y = animationData.targetHookY;
setAnimationPhase('init-rotate-base'); setAnimationPhase('init-rotate-base');
} }
break; break;
@@ -154,7 +183,7 @@ function PillarJibAnimator({
const currentDir = new THREE.Vector2(baseForward.x, baseForward.z).normalize(); const currentDir = new THREE.Vector2(baseForward.x, baseForward.z).normalize();
const targetWorld = clampedPoints[currentTargetIndex]; const targetWorld = clampedPoints[0];
const targetDir = new THREE.Vector2( const targetDir = new THREE.Vector2(
targetWorld.x - baseWorld.x, targetWorld.x - baseWorld.x,
targetWorld.z - baseWorld.z targetWorld.z - baseWorld.z
@@ -170,7 +199,7 @@ function PillarJibAnimator({
base.rotation.y += Math.sign(angleDiff) * rotationSpeed; base.rotation.y += Math.sign(angleDiff) * rotationSpeed;
} else { } else {
base.rotation.y += angleDiff; base.rotation.y += angleDiff;
const localTarget = trolley.parent.worldToLocal(clampedPoints[currentTargetIndex].clone()); const localTarget = trolley.parent.worldToLocal(clampedPoints[0].clone());
animationData.targetTrolleyX = localTarget?.x; animationData.targetTrolleyX = localTarget?.x;
setAnimationPhase('init-move-trolley'); setAnimationPhase('init-move-trolley');
} }
@@ -185,7 +214,7 @@ function PillarJibAnimator({
if (parseFloat(Math.abs(dx).toFixed(2)) < 0.05) { if (parseFloat(Math.abs(dx).toFixed(2)) < 0.05) {
trolley.position.x = animationData.targetTrolleyX; trolley.position.x = animationData.targetTrolleyX;
animationData.finalHookTargetY = hook.position.y - 0.5; animationData.finalHookTargetY = hook.position.y;
setAnimationPhase('init-final-hook-adjust'); setAnimationPhase('init-final-hook-adjust');
} }
break; break;
@@ -199,22 +228,87 @@ function PillarJibAnimator({
if (parseFloat(Math.abs(dy).toFixed(2)) < 0.05) { if (parseFloat(Math.abs(dy).toFixed(2)) < 0.05) {
hook.position.y = animationData.finalHookTargetY; hook.position.y = animationData.finalHookTargetY;
if (currentTargetIndex < points.length - 1) { model.userData.animationData = {
setCurrentTargetIndex(currentTargetIndex + 1); originalHookY: hook.position.y,
targetHookY: clampedPoints[1].y - baseWorld.y + 0.5,
targetDirection: new THREE.Vector2(),
targetTrolleyX: 0,
targetWorldPosition: clampedPoints[1].clone(),
finalHookTargetY: 0,
};
model.userData.animationData = { setAnimationPhase('starting');
originalHookY: hook.position.y, onAnimationComplete('starting');
targetHookY: clampedPoints[currentTargetIndex + 1].y - baseWorld.y + 0.5, }
targetDirection: new THREE.Vector2(), break;
targetTrolleyX: 0, }
targetWorldPosition: clampedPoints[currentTargetIndex + 1].clone(),
finalHookTargetY: 0,
};
case 'first-hook-adjust': {
const direction = Math.sign(animationData.targetHookY - hook.position.y);
hook.position.y += direction * hookSpeed;
if (parseFloat(Math.abs(hook.position.y - animationData.targetHookY).toFixed(2)) < 0.05) {
hook.position.y = animationData.targetHookY;
setAnimationPhase('first-rotate-base');
}
break;
}
case 'first-rotate-base': {
const baseForward = new THREE.Vector3(1, 0, 0);
base.localToWorld(baseForward);
baseForward.sub(baseWorld);
const currentDir = new THREE.Vector2(baseForward.x, baseForward.z).normalize();
const targetWorld = clampedPoints[1];
const targetDir = new THREE.Vector2(
targetWorld.x - baseWorld.x,
targetWorld.z - baseWorld.z
).normalize();
const currentAngle = Math.atan2(currentDir.y, currentDir.x);
const targetAngle = Math.atan2(targetDir.y, targetDir.x);
let angleDiff = currentAngle - targetAngle;
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
if (parseFloat(Math.abs(angleDiff).toFixed(2)) > 0.05) {
base.rotation.y += Math.sign(angleDiff) * rotationSpeed;
} else {
base.rotation.y += angleDiff;
const localTarget = trolley.parent.worldToLocal(clampedPoints[1].clone());
animationData.targetTrolleyX = localTarget?.x;
setAnimationPhase('first-move-trolley');
}
break;
}
case 'first-move-trolley': {
const dx = animationData.targetTrolleyX - trolley.position.x;
const direction = Math.sign(dx);
trolley.position.x += direction * trolleySpeed;
if (parseFloat(Math.abs(dx).toFixed(2)) < 0.05) {
trolley.position.x = animationData.targetTrolleyX;
animationData.finalHookTargetY = hook.position.y - 0.5;
setAnimationPhase('first-final-hook-adjust');
}
break;
}
case 'first-final-hook-adjust': {
const dy = animationData.finalHookTargetY - hook.position.y;
const direction = Math.sign(dy);
hook.position.y += direction * hookSpeed;
if (parseFloat(Math.abs(dy).toFixed(2)) < 0.05) {
hook.position.y = animationData.finalHookTargetY;
if (crane.currentPhase === 'init-pickup') {
setAnimationPhase('picking'); setAnimationPhase('picking');
onAnimationComplete('picking'); onAnimationComplete('picking');
} else if (crane.currentPhase === 'pickup-drop') {
} else {
setAnimationPhase('dropping'); setAnimationPhase('dropping');
onAnimationComplete('dropping'); onAnimationComplete('dropping');
} }

View File

@@ -8,7 +8,7 @@ function PillarJibHelper({
points points
}: { }: {
crane: CraneStatus, crane: CraneStatus,
points: [THREE.Vector3, THREE.Vector3]; points: [THREE.Vector3, THREE.Vector3] | null;
}) { }) {
const { scene } = useThree(); const { scene } = useThree();
const [clampedPoints, setClampedPoints] = useState<[THREE.Vector3, THREE.Vector3]>(); const [clampedPoints, setClampedPoints] = useState<[THREE.Vector3, THREE.Vector3]>();
@@ -22,7 +22,7 @@ function PillarJibHelper({
const trolley = model.getObjectByName('trolley'); const trolley = model.getObjectByName('trolley');
const hook = model.getObjectByName('hook'); const hook = model.getObjectByName('hook');
if (!base || !trolley || !hook) return { geometry: null, position: null }; if (!base || !trolley || !hook || !points) return { geometry: null, position: null };
const baseWorld = new THREE.Vector3(); const baseWorld = new THREE.Vector3();
base.getWorldPosition(baseWorld); base.getWorldPosition(baseWorld);
@@ -94,7 +94,7 @@ function PillarJibHelper({
setIsInside(newIsInside); setIsInside(newIsInside);
return { geometry, position }; return { geometry, position };
}, [scene, crane.modelUuid]); }, [scene, crane.modelUuid, points]);
if (!geometry || !position) return null; if (!geometry || !position) return null;
@@ -115,7 +115,7 @@ function PillarJibHelper({
/> />
</mesh> </mesh>
{points.map((point, i) => ( {points && points.map((point, i) => (
<Box <Box
key={`original-${i}`} key={`original-${i}`}
position={point} position={point}

View File

@@ -11,10 +11,9 @@ function PillarJibInstance({ crane }: { crane: CraneStatus }) {
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { craneStore, productStore } = useSceneContext(); const { craneStore, productStore } = useSceneContext();
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
const { getCraneById } = craneStore(); const { getCraneById, setCurrentPhase } = craneStore();
const { selectedProductStore } = useProductContext(); const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore(); const { selectedProduct } = selectedProductStore();
const [currentPhase, setCurrentPhase] = useState<string>('idle');
const [animationPhase, setAnimationPhase] = useState<string>('idle'); const [animationPhase, setAnimationPhase] = useState<string>('idle');
const [points, setPoints] = useState<[THREE.Vector3, THREE.Vector3] | null>(null); const [points, setPoints] = useState<[THREE.Vector3, THREE.Vector3] | null>(null);
@@ -23,22 +22,17 @@ function PillarJibInstance({ crane }: { crane: CraneStatus }) {
const action = getActionByUuid(selectedProduct.productUuid, crane?.currentAction?.actionUuid || ''); const action = getActionByUuid(selectedProduct.productUuid, crane?.currentAction?.actionUuid || '');
if (!action || action.actionType !== 'pickAndDrop') return; if (!action || action.actionType !== 'pickAndDrop') return;
if (!crane.isActive && currentPhase === 'idle' && crane.currentMaterials.length > 0 && action.maxPickUpCount <= crane.currentMaterials.length) { if (!crane.isActive && crane.currentPhase === 'init' && crane.currentMaterials.length > 0 && action.maxPickUpCount <= crane.currentMaterials.length) {
console.log('crane: ', crane); setCurrentPhase(crane.modelUuid, 'init-pickup');
} }
} }
}, [crane, currentPhase]) }, [crane])
const handleAnimationComplete = (action: string) => { const handleAnimationComplete = (action: string) => {
if (action === 'picking') { if (action === 'starting') {
setTimeout(() => { setAnimationPhase('first-hook-adjust');
setAnimationPhase('init-hook-adjust'); } else if (action === 'picking') {
}, 3000) setCurrentPhase(crane.modelUuid, 'picking');
} else if (action === 'dropping') {
setTimeout(() => {
setAnimationPhase('idle');
}, 3000)
} }
} }
@@ -49,18 +43,16 @@ function PillarJibInstance({ crane }: { crane: CraneStatus }) {
key={crane.modelUuid} key={crane.modelUuid}
crane={crane} crane={crane}
points={points} points={points}
setPoints={setPoints}
animationPhase={animationPhase} animationPhase={animationPhase}
setAnimationPhase={setAnimationPhase} setAnimationPhase={setAnimationPhase}
onAnimationComplete={handleAnimationComplete} onAnimationComplete={handleAnimationComplete}
/> />
{/* <PillarJibHelper <PillarJibHelper
crane={crane} crane={crane}
points={[ points={points}
new THREE.Vector3(...position1), />
new THREE.Vector3(...position2)]
}
/> */}
</> </>
) )