From 58007a96dcae5ba9239c742b954a882508b7a038 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 2 Sep 2025 18:00:12 +0530 Subject: [PATCH] pillar jib animation bug fix --- .../instances/animator/pillarJibAnimator.tsx | 209 +++++++++++------- 1 file changed, 131 insertions(+), 78 deletions(-) diff --git a/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx b/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx index cb4d863..a803cad 100644 --- a/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx +++ b/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx @@ -167,7 +167,7 @@ function PillarJibAnimator({ const trolley = model.getObjectByName('trolley'); const hook = model.getObjectByName('hook'); - if (!base || !trolley || !hook || !trolley.parent) return; + if (!base || !trolley || !hook || !trolley.parent || !hook.parent) return; const baseWorld = new THREE.Vector3(); base.getWorldPosition(baseWorld); @@ -175,18 +175,6 @@ function PillarJibAnimator({ const hookWorld = new THREE.Vector3(); hook.getWorldPosition(hookWorld); - if (!model.userData.animationData) { - model.userData.animationData = { - originalHookY: hook.position.y, - targetHookY: clampedPoints[0].y - baseWorld.y, - targetDirection: new THREE.Vector2(), - targetTrolleyX: 0, - targetWorldPosition: clampedPoints[0].clone(), - finalHookTargetY: 0, - }; - } - - const { animationData } = model.userData; const hookSpeed = (model.userData.hookSpeed || 0.01) * speed; const rotationSpeed = (model.userData.rotationSpeed || 0.005) * speed; const trolleySpeed = (model.userData.trolleySpeed || 0.01) * speed; @@ -197,28 +185,37 @@ function PillarJibAnimator({ case 'init-hook-adjust': { const hookWorld = new THREE.Vector3(); hook.getWorldPosition(hookWorld); + const targetY = clampedPoints[0].y; - const direction = Math.sign(targetY - hookWorld.y); + const diff = targetY - hookWorld.y; - hook.position.y = THREE.MathUtils.lerp( - hook.position.y, - hook.position.y + direction * 0.1, - Math.min(hookSpeed, 0.9) - ); - - if (Math.abs(hookWorld.y - targetY) < threshold) { - hook.position.y = targetY - baseWorld.y; + if (Math.abs(diff) > threshold) { + const step = Math.sign(diff) * hookSpeed; + if (Math.abs(step) > Math.abs(diff)) { + const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone()); + hook.position.y = localTarget.y; + setAnimationPhase('init-rotate-base'); + } else { + hook.position.y += step; + } + } else { + const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone()); + hook.position.y = localTarget.y; setAnimationPhase('init-rotate-base'); } break; } case 'init-rotate-base': { + const baseWorld = new THREE.Vector3(); + base.getWorldPosition(baseWorld); + 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 targetDir = new THREE.Vector2( targetWorld.x - baseWorld.x, @@ -228,79 +225,102 @@ function PillarJibAnimator({ 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 (Math.abs(angleDiff) > threshold) { - base.rotation.y = THREE.MathUtils.lerp( - base.rotation.y, - base.rotation.y - angleDiff, - Math.min(rotationSpeed, 0.9) - ); + if (parseFloat(Math.abs(angleDiff).toFixed(2)) > 0.05) { + const step = Math.sign(angleDiff) * rotationSpeed; + + if (Math.abs(step) > Math.abs(angleDiff)) { + base.rotation.y += angleDiff; + setAnimationPhase('init-move-trolley'); + } else { + base.rotation.y += step; + } } else { - base.rotation.y -= angleDiff; - const localTarget = trolley.parent.worldToLocal(clampedPoints[0].clone()); - animationData.targetTrolleyX = localTarget?.x; + base.rotation.y += angleDiff; setAnimationPhase('init-move-trolley'); } break; } case 'init-move-trolley': { - const dx = animationData.targetTrolleyX - trolley.position.x; + const baseWorld = new THREE.Vector3(); + base.getWorldPosition(baseWorld); - trolley.position.x = THREE.MathUtils.lerp( - trolley.position.x, - animationData.targetTrolleyX, - Math.min(trolleySpeed, 0.9) - ); + const targetWorld = clampedPoints[0].clone(); + const localTarget = trolley.parent.worldToLocal(targetWorld.clone()); - if (Math.abs(dx) < threshold) { - trolley.position.x = animationData.targetTrolleyX; - animationData.finalHookTargetY = clampedPoints[0].y - baseWorld.y; + const diff = localTarget.x - trolley.position.x; + + if (Math.abs(diff) > threshold) { + const step = Math.sign(diff) * trolleySpeed; + if (Math.abs(step) > Math.abs(diff)) { + trolley.position.x = localTarget.x; + setAnimationPhase('init-final-hook-adjust'); + } else { + trolley.position.x += step; + } + } else { + trolley.position.x = localTarget.x; setAnimationPhase('init-final-hook-adjust'); } break; } case 'init-final-hook-adjust': { - const targetY = clampedPoints[0].y - baseWorld.y; + const hookWorld = new THREE.Vector3(); + hook.getWorldPosition(hookWorld); - hook.position.y = THREE.MathUtils.lerp( - hook.position.y, - targetY, - Math.min(hookSpeed, 0.9) - ); + const targetY = clampedPoints[0].y; + const diff = targetY - hookWorld.y; - if (Math.abs(hook.position.y - targetY) < threshold) { - hook.position.y = targetY; - - model.userData.animationData = { - originalHookY: hook.position.y, - targetHookY: clampedPoints[1].y - baseWorld.y + 0.5, - targetDirection: new THREE.Vector2(), - targetTrolleyX: 0, - targetWorldPosition: clampedPoints[1].clone(), - finalHookTargetY: 0, - }; - - setAnimationPhase('starting'); - onAnimationComplete('starting'); + if (Math.abs(diff) > threshold) { + const step = Math.sign(diff) * hookSpeed; + if (Math.abs(step) > Math.abs(diff)) { + const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone()); + hook.position.y = localTarget.y; + setAnimationPhase('first-hook-adjust'); + } else { + hook.position.y += step; + } + } else { + const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone()); + hook.position.y = localTarget.y; + setAnimationPhase('first-hook-adjust'); } break; } case 'first-hook-adjust': { - const direction = Math.sign(animationData.targetHookY - hook.position.y); - hook.position.y += direction * hookSpeed; + const hookWorld = new THREE.Vector3(); + hook.getWorldPosition(hookWorld); - if (parseFloat(Math.abs(hook.position.y - animationData.targetHookY).toFixed(2)) < 0.05) { - hook.position.y = animationData.targetHookY; + const targetWorld = clampedPoints[1].clone().add(new THREE.Vector3(0, 0.5, 0)); + const targetY = targetWorld.y; + const diff = targetY - hookWorld.y; + + if (Math.abs(diff) > threshold) { + const step = Math.sign(diff) * hookSpeed; + if (Math.abs(step) > Math.abs(diff)) { + const localTarget = hook.parent.worldToLocal(targetWorld.clone()); + hook.position.y = localTarget.y; + setAnimationPhase('first-rotate-base'); + } else { + hook.position.y += step; + } + } else { + const localTarget = hook.parent.worldToLocal(targetWorld.clone()); + hook.position.y = localTarget.y; setAnimationPhase('first-rotate-base'); } break; } case 'first-rotate-base': { + const baseWorld = new THREE.Vector3(); + base.getWorldPosition(baseWorld); + const baseForward = new THREE.Vector3(1, 0, 0); base.localToWorld(baseForward); baseForward.sub(baseWorld); @@ -320,37 +340,70 @@ function PillarJibAnimator({ 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; + const step = Math.sign(angleDiff) * rotationSpeed; + + if (Math.abs(step) > Math.abs(angleDiff)) { + base.rotation.y += angleDiff; + setAnimationPhase('first-move-trolley'); + } else { + base.rotation.y += step; + } } 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; + const baseWorld = new THREE.Vector3(); + base.getWorldPosition(baseWorld); - if (parseFloat(Math.abs(dx).toFixed(2)) < 0.05) { - trolley.position.x = animationData.targetTrolleyX; + const targetWorld = clampedPoints[1].clone(); + const localTarget = trolley.parent.worldToLocal(targetWorld.clone()); - animationData.finalHookTargetY = hook.position.y - 0.5; + const diff = localTarget.x - trolley.position.x; + + if (Math.abs(diff) > threshold) { + const step = Math.sign(diff) * trolleySpeed; + if (Math.abs(step) > Math.abs(diff)) { + trolley.position.x = localTarget.x; + setAnimationPhase('first-final-hook-adjust'); + } else { + trolley.position.x += step; + } + } else { + trolley.position.x = localTarget.x; 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; + const hookWorld = new THREE.Vector3(); + hook.getWorldPosition(hookWorld); - if (parseFloat(Math.abs(dy).toFixed(2)) < 0.05) { - hook.position.y = animationData.finalHookTargetY; + const targetY = clampedPoints[1].y; + const diff = targetY - hookWorld.y; + + if (Math.abs(diff) > threshold) { + const step = Math.sign(diff) * hookSpeed; + if (Math.abs(step) > Math.abs(diff)) { + const localTarget = hook.parent.worldToLocal(clampedPoints[1].clone()); + hook.position.y = localTarget.y; + if (crane.currentPhase === 'init-pickup') { + setAnimationPhase('picking'); + onAnimationComplete('picking'); + } else if (crane.currentPhase === 'pickup-drop') { + setAnimationPhase('dropping'); + onAnimationComplete('dropping'); + } + } else { + hook.position.y += step; + } + } else { + const localTarget = hook.parent.worldToLocal(clampedPoints[1].clone()); + hook.position.y = localTarget.y; if (crane.currentPhase === 'init-pickup') { setAnimationPhase('picking'); onAnimationComplete('picking');