pillar jib animation bug fix
This commit is contained in:
@@ -167,7 +167,7 @@ function PillarJibAnimator({
|
|||||||
const trolley = model.getObjectByName('trolley');
|
const trolley = model.getObjectByName('trolley');
|
||||||
const hook = model.getObjectByName('hook');
|
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();
|
const baseWorld = new THREE.Vector3();
|
||||||
base.getWorldPosition(baseWorld);
|
base.getWorldPosition(baseWorld);
|
||||||
@@ -175,18 +175,6 @@ function PillarJibAnimator({
|
|||||||
const hookWorld = new THREE.Vector3();
|
const hookWorld = new THREE.Vector3();
|
||||||
hook.getWorldPosition(hookWorld);
|
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 hookSpeed = (model.userData.hookSpeed || 0.01) * speed;
|
||||||
const rotationSpeed = (model.userData.rotationSpeed || 0.005) * speed;
|
const rotationSpeed = (model.userData.rotationSpeed || 0.005) * speed;
|
||||||
const trolleySpeed = (model.userData.trolleySpeed || 0.01) * speed;
|
const trolleySpeed = (model.userData.trolleySpeed || 0.01) * speed;
|
||||||
@@ -197,28 +185,37 @@ function PillarJibAnimator({
|
|||||||
case 'init-hook-adjust': {
|
case 'init-hook-adjust': {
|
||||||
const hookWorld = new THREE.Vector3();
|
const hookWorld = new THREE.Vector3();
|
||||||
hook.getWorldPosition(hookWorld);
|
hook.getWorldPosition(hookWorld);
|
||||||
|
|
||||||
const targetY = clampedPoints[0].y;
|
const targetY = clampedPoints[0].y;
|
||||||
const direction = Math.sign(targetY - hookWorld.y);
|
const diff = targetY - hookWorld.y;
|
||||||
|
|
||||||
hook.position.y = THREE.MathUtils.lerp(
|
if (Math.abs(diff) > threshold) {
|
||||||
hook.position.y,
|
const step = Math.sign(diff) * hookSpeed;
|
||||||
hook.position.y + direction * 0.1,
|
if (Math.abs(step) > Math.abs(diff)) {
|
||||||
Math.min(hookSpeed, 0.9)
|
const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone());
|
||||||
);
|
hook.position.y = localTarget.y;
|
||||||
|
setAnimationPhase('init-rotate-base');
|
||||||
if (Math.abs(hookWorld.y - targetY) < threshold) {
|
} else {
|
||||||
hook.position.y = targetY - baseWorld.y;
|
hook.position.y += step;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone());
|
||||||
|
hook.position.y = localTarget.y;
|
||||||
setAnimationPhase('init-rotate-base');
|
setAnimationPhase('init-rotate-base');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'init-rotate-base': {
|
case 'init-rotate-base': {
|
||||||
|
const baseWorld = new THREE.Vector3();
|
||||||
|
base.getWorldPosition(baseWorld);
|
||||||
|
|
||||||
const baseForward = new THREE.Vector3(1, 0, 0);
|
const baseForward = new THREE.Vector3(1, 0, 0);
|
||||||
base.localToWorld(baseForward);
|
base.localToWorld(baseForward);
|
||||||
baseForward.sub(baseWorld);
|
baseForward.sub(baseWorld);
|
||||||
|
|
||||||
const currentDir = new THREE.Vector2(baseForward.x, baseForward.z).normalize();
|
const currentDir = new THREE.Vector2(baseForward.x, baseForward.z).normalize();
|
||||||
|
|
||||||
const targetWorld = clampedPoints[0];
|
const targetWorld = clampedPoints[0];
|
||||||
const targetDir = new THREE.Vector2(
|
const targetDir = new THREE.Vector2(
|
||||||
targetWorld.x - baseWorld.x,
|
targetWorld.x - baseWorld.x,
|
||||||
@@ -228,79 +225,102 @@ function PillarJibAnimator({
|
|||||||
const currentAngle = Math.atan2(currentDir.y, currentDir.x);
|
const currentAngle = Math.atan2(currentDir.y, currentDir.x);
|
||||||
const targetAngle = Math.atan2(targetDir.y, targetDir.x);
|
const targetAngle = Math.atan2(targetDir.y, targetDir.x);
|
||||||
let angleDiff = currentAngle - targetAngle;
|
let angleDiff = currentAngle - targetAngle;
|
||||||
|
|
||||||
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
|
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
|
||||||
|
|
||||||
if (Math.abs(angleDiff) > threshold) {
|
if (parseFloat(Math.abs(angleDiff).toFixed(2)) > 0.05) {
|
||||||
base.rotation.y = THREE.MathUtils.lerp(
|
const step = Math.sign(angleDiff) * rotationSpeed;
|
||||||
base.rotation.y,
|
|
||||||
base.rotation.y - angleDiff,
|
if (Math.abs(step) > Math.abs(angleDiff)) {
|
||||||
Math.min(rotationSpeed, 0.9)
|
base.rotation.y += angleDiff;
|
||||||
);
|
setAnimationPhase('init-move-trolley');
|
||||||
|
} else {
|
||||||
|
base.rotation.y += step;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
base.rotation.y -= angleDiff;
|
base.rotation.y += angleDiff;
|
||||||
const localTarget = trolley.parent.worldToLocal(clampedPoints[0].clone());
|
|
||||||
animationData.targetTrolleyX = localTarget?.x;
|
|
||||||
setAnimationPhase('init-move-trolley');
|
setAnimationPhase('init-move-trolley');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'init-move-trolley': {
|
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(
|
const targetWorld = clampedPoints[0].clone();
|
||||||
trolley.position.x,
|
const localTarget = trolley.parent.worldToLocal(targetWorld.clone());
|
||||||
animationData.targetTrolleyX,
|
|
||||||
Math.min(trolleySpeed, 0.9)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Math.abs(dx) < threshold) {
|
const diff = localTarget.x - trolley.position.x;
|
||||||
trolley.position.x = animationData.targetTrolleyX;
|
|
||||||
animationData.finalHookTargetY = clampedPoints[0].y - baseWorld.y;
|
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');
|
setAnimationPhase('init-final-hook-adjust');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'init-final-hook-adjust': {
|
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(
|
const targetY = clampedPoints[0].y;
|
||||||
hook.position.y,
|
const diff = targetY - hookWorld.y;
|
||||||
targetY,
|
|
||||||
Math.min(hookSpeed, 0.9)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Math.abs(hook.position.y - targetY) < threshold) {
|
if (Math.abs(diff) > threshold) {
|
||||||
hook.position.y = targetY;
|
const step = Math.sign(diff) * hookSpeed;
|
||||||
|
if (Math.abs(step) > Math.abs(diff)) {
|
||||||
model.userData.animationData = {
|
const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone());
|
||||||
originalHookY: hook.position.y,
|
hook.position.y = localTarget.y;
|
||||||
targetHookY: clampedPoints[1].y - baseWorld.y + 0.5,
|
setAnimationPhase('first-hook-adjust');
|
||||||
targetDirection: new THREE.Vector2(),
|
} else {
|
||||||
targetTrolleyX: 0,
|
hook.position.y += step;
|
||||||
targetWorldPosition: clampedPoints[1].clone(),
|
}
|
||||||
finalHookTargetY: 0,
|
} else {
|
||||||
};
|
const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone());
|
||||||
|
hook.position.y = localTarget.y;
|
||||||
setAnimationPhase('starting');
|
setAnimationPhase('first-hook-adjust');
|
||||||
onAnimationComplete('starting');
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'first-hook-adjust': {
|
case 'first-hook-adjust': {
|
||||||
const direction = Math.sign(animationData.targetHookY - hook.position.y);
|
const hookWorld = new THREE.Vector3();
|
||||||
hook.position.y += direction * hookSpeed;
|
hook.getWorldPosition(hookWorld);
|
||||||
|
|
||||||
if (parseFloat(Math.abs(hook.position.y - animationData.targetHookY).toFixed(2)) < 0.05) {
|
const targetWorld = clampedPoints[1].clone().add(new THREE.Vector3(0, 0.5, 0));
|
||||||
hook.position.y = animationData.targetHookY;
|
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');
|
setAnimationPhase('first-rotate-base');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'first-rotate-base': {
|
case 'first-rotate-base': {
|
||||||
|
const baseWorld = new THREE.Vector3();
|
||||||
|
base.getWorldPosition(baseWorld);
|
||||||
|
|
||||||
const baseForward = new THREE.Vector3(1, 0, 0);
|
const baseForward = new THREE.Vector3(1, 0, 0);
|
||||||
base.localToWorld(baseForward);
|
base.localToWorld(baseForward);
|
||||||
baseForward.sub(baseWorld);
|
baseForward.sub(baseWorld);
|
||||||
@@ -320,37 +340,70 @@ function PillarJibAnimator({
|
|||||||
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
|
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
|
||||||
|
|
||||||
if (parseFloat(Math.abs(angleDiff).toFixed(2)) > 0.05) {
|
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 {
|
} else {
|
||||||
base.rotation.y += angleDiff;
|
base.rotation.y += angleDiff;
|
||||||
const localTarget = trolley.parent.worldToLocal(clampedPoints[1].clone());
|
|
||||||
animationData.targetTrolleyX = localTarget?.x;
|
|
||||||
setAnimationPhase('first-move-trolley');
|
setAnimationPhase('first-move-trolley');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'first-move-trolley': {
|
case 'first-move-trolley': {
|
||||||
const dx = animationData.targetTrolleyX - trolley.position.x;
|
const baseWorld = new THREE.Vector3();
|
||||||
const direction = Math.sign(dx);
|
base.getWorldPosition(baseWorld);
|
||||||
trolley.position.x += direction * trolleySpeed;
|
|
||||||
|
|
||||||
if (parseFloat(Math.abs(dx).toFixed(2)) < 0.05) {
|
const targetWorld = clampedPoints[1].clone();
|
||||||
trolley.position.x = animationData.targetTrolleyX;
|
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');
|
setAnimationPhase('first-final-hook-adjust');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'first-final-hook-adjust': {
|
case 'first-final-hook-adjust': {
|
||||||
const dy = animationData.finalHookTargetY - hook.position.y;
|
const hookWorld = new THREE.Vector3();
|
||||||
const direction = Math.sign(dy);
|
hook.getWorldPosition(hookWorld);
|
||||||
hook.position.y += direction * hookSpeed;
|
|
||||||
|
|
||||||
if (parseFloat(Math.abs(dy).toFixed(2)) < 0.05) {
|
const targetY = clampedPoints[1].y;
|
||||||
hook.position.y = animationData.finalHookTargetY;
|
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') {
|
if (crane.currentPhase === 'init-pickup') {
|
||||||
setAnimationPhase('picking');
|
setAnimationPhase('picking');
|
||||||
onAnimationComplete('picking');
|
onAnimationComplete('picking');
|
||||||
|
|||||||
Reference in New Issue
Block a user