crane animator
This commit is contained in:
@@ -5,7 +5,19 @@ import { Sphere, Box } from '@react-three/drei';
|
||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
|
||||
function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THREE.Vector3, THREE.Vector3]; }) {
|
||||
function PillarJibAnimator({
|
||||
crane,
|
||||
points,
|
||||
animationPhase,
|
||||
setAnimationPhase,
|
||||
onAnimationComplete
|
||||
}: {
|
||||
crane: CraneStatus;
|
||||
points: [THREE.Vector3, THREE.Vector3];
|
||||
animationPhase: string;
|
||||
setAnimationPhase: (phase: string) => void;
|
||||
onAnimationComplete: (action: string) => void;
|
||||
}) {
|
||||
const { scene } = useThree();
|
||||
const { assetStore } = useSceneContext();
|
||||
const { resetAsset } = assetStore();
|
||||
@@ -15,12 +27,13 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
|
||||
const [clampedPoints, setClampedPoints] = useState<[THREE.Vector3, THREE.Vector3]>();
|
||||
const [isInside, setIsInside] = useState<[boolean, boolean]>([false, false]);
|
||||
const [animationPhase, setAnimationPhase] = useState<string>('idle'); // 0: idle, 1: init-hook-adjust, 2: 'rotate-base', 3: 'move-trolley', 4: 'final-hook-adjust'
|
||||
const [currentTargetIndex, setCurrentTargetIndex] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPlaying) {
|
||||
resetAsset(crane.modelUuid);
|
||||
setAnimationPhase('idle');
|
||||
setCurrentTargetIndex(0);
|
||||
} else if (animationPhase === 'idle') {
|
||||
setAnimationPhase('init-hook-adjust');
|
||||
}
|
||||
@@ -89,10 +102,10 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
|
||||
setClampedPoints(newClampedPoints);
|
||||
setIsInside(newIsInside);
|
||||
}, [scene, points, crane.modelUuid]);
|
||||
}, [crane.modelUuid]);
|
||||
|
||||
useFrame(() => {
|
||||
if (!isPlaying || isPaused || !points || animationPhase === 'idle') return;
|
||||
if (!isPlaying || isPaused || !points || !clampedPoints || animationPhase === 'idle') return;
|
||||
|
||||
const model = scene.getObjectByProperty('uuid', crane.modelUuid);
|
||||
if (!model) return;
|
||||
@@ -101,7 +114,7 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
const trolley = model.getObjectByName('trolley');
|
||||
const hook = model.getObjectByName('hook');
|
||||
|
||||
if (!base || !trolley || !hook || !clampedPoints || !trolley.parent) return;
|
||||
if (!base || !trolley || !hook || !trolley.parent) return;
|
||||
|
||||
const baseWorld = new THREE.Vector3();
|
||||
base.getWorldPosition(baseWorld);
|
||||
@@ -112,10 +125,10 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
if (!model.userData.animationData) {
|
||||
model.userData.animationData = {
|
||||
originalHookY: hook.position.y,
|
||||
targetHookY: points[0].y - baseWorld.y + 0.5,
|
||||
targetHookY: clampedPoints[currentTargetIndex].y - baseWorld.y + 0.5,
|
||||
targetDirection: new THREE.Vector2(),
|
||||
targetTrolleyX: 0,
|
||||
targetWorldPosition: points[0].clone(),
|
||||
targetWorldPosition: clampedPoints[currentTargetIndex].clone(),
|
||||
finalHookTargetY: 0,
|
||||
};
|
||||
}
|
||||
@@ -132,22 +145,19 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
|
||||
if (parseFloat(Math.abs(hook.position.y - animationData.targetHookY).toFixed(2)) < 0.05) {
|
||||
hook.position.y = animationData.targetHookY;
|
||||
setAnimationPhase('rotate-base');
|
||||
setAnimationPhase('init-rotate-base');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'rotate-base': {
|
||||
const baseWorld = new THREE.Vector3();
|
||||
base.getWorldPosition(baseWorld);
|
||||
|
||||
case 'init-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[0];
|
||||
const targetWorld = clampedPoints[currentTargetIndex];
|
||||
const targetDir = new THREE.Vector2(
|
||||
targetWorld.x - baseWorld.x,
|
||||
targetWorld.z - baseWorld.z
|
||||
@@ -163,15 +173,14 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
base.rotation.y += Math.sign(angleDiff) * rotationSpeed;
|
||||
} else {
|
||||
base.rotation.y += angleDiff;
|
||||
const localTarget = trolley.parent.worldToLocal(clampedPoints[0].clone());
|
||||
const localTarget = trolley.parent.worldToLocal(clampedPoints[currentTargetIndex].clone());
|
||||
animationData.targetTrolleyX = localTarget?.x;
|
||||
setAnimationPhase('move-trolley');
|
||||
setAnimationPhase('init-move-trolley');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'move-trolley': {
|
||||
case 'init-move-trolley': {
|
||||
const dx = animationData.targetTrolleyX - trolley.position.x;
|
||||
const direction = Math.sign(dx);
|
||||
trolley.position.x += direction * trolleySpeed;
|
||||
@@ -180,19 +189,38 @@ function PillarJibAnimator({ crane, points }: { crane: CraneStatus; points: [THR
|
||||
trolley.position.x = animationData.targetTrolleyX;
|
||||
|
||||
animationData.finalHookTargetY = hook.position.y - 0.5;
|
||||
setAnimationPhase('final-hook-adjust');
|
||||
setAnimationPhase('init-final-hook-adjust');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'final-hook-adjust': {
|
||||
case 'init-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;
|
||||
setAnimationPhase('idle');
|
||||
|
||||
if (currentTargetIndex < points.length - 1) {
|
||||
setCurrentTargetIndex(currentTargetIndex + 1);
|
||||
|
||||
model.userData.animationData = {
|
||||
originalHookY: hook.position.y,
|
||||
targetHookY: clampedPoints[currentTargetIndex + 1].y - baseWorld.y + 0.5,
|
||||
targetDirection: new THREE.Vector2(),
|
||||
targetTrolleyX: 0,
|
||||
targetWorldPosition: clampedPoints[currentTargetIndex + 1].clone(),
|
||||
finalHookTargetY: 0,
|
||||
};
|
||||
|
||||
setAnimationPhase('picking');
|
||||
onAnimationComplete('picking');
|
||||
|
||||
} else {
|
||||
setAnimationPhase('dropping');
|
||||
onAnimationComplete('dropping');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ function CraneInstances() {
|
||||
<React.Fragment key={crane.modelUuid}>
|
||||
|
||||
{crane.subType === "pillarJib" &&
|
||||
<PillarJibInstance crane={crane} />
|
||||
<PillarJibInstance key={crane.modelUuid} crane={crane} />
|
||||
}
|
||||
|
||||
</React.Fragment>
|
||||
|
||||
@@ -1,21 +1,39 @@
|
||||
import { useState } from 'react';
|
||||
import * as THREE from 'three'
|
||||
import PillarJibAnimator from '../animator/pillarJibAnimator'
|
||||
import PillarJibHelper from '../helper/pillarJibHelper'
|
||||
|
||||
function PillarJibInstance({ crane }: { crane: CraneStatus }) {
|
||||
const [animationPhase, setAnimationPhase] = useState<string>('idle');
|
||||
|
||||
const position1: [number, number, number] = [5, 1, -4];
|
||||
const position2: [number, number, number] = [-2, 2, -2];
|
||||
|
||||
const handleAnimationComplete = (action: string) => {
|
||||
if (action === 'picking') {
|
||||
setTimeout(() => {
|
||||
setAnimationPhase('init-hook-adjust');
|
||||
}, 3000)
|
||||
} else if (action === 'dropping') {
|
||||
setTimeout(() => {
|
||||
setAnimationPhase('idle');
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<PillarJibAnimator
|
||||
key={crane.modelUuid}
|
||||
crane={crane}
|
||||
points={[
|
||||
new THREE.Vector3(...position1),
|
||||
new THREE.Vector3(...position2)
|
||||
]}
|
||||
animationPhase={animationPhase}
|
||||
setAnimationPhase={setAnimationPhase}
|
||||
onAnimationComplete={handleAnimationComplete}
|
||||
/>
|
||||
|
||||
<PillarJibHelper crane={crane} />
|
||||
|
||||
Reference in New Issue
Block a user