added pillarJib trigger
This commit is contained in:
@@ -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');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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)]
|
|
||||||
}
|
|
||||||
/> */}
|
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user