feat: add MaterialAnimator component to handle 3D material animation with play/pause functionality.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { usePauseButtonStore, usePlayButtonStore } from '../../../../../store/ui/usePlayButtonStore';
|
||||
import { useSceneContext } from '../../../../scene/sceneContext';
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { usePauseButtonStore, usePlayButtonStore } from "../../../../../store/ui/usePlayButtonStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
|
||||
interface MaterialAnimatorProps {
|
||||
matRef: React.RefObject<THREE.Mesh>;
|
||||
@@ -11,12 +11,7 @@ interface MaterialAnimatorProps {
|
||||
onAnimationComplete?: () => void;
|
||||
}
|
||||
|
||||
function MaterialAnimator({
|
||||
matRef,
|
||||
material,
|
||||
currentSpeed,
|
||||
onAnimationComplete
|
||||
}: MaterialAnimatorProps) {
|
||||
function MaterialAnimator({ matRef, material, currentSpeed, onAnimationComplete }: MaterialAnimatorProps) {
|
||||
const { scene } = useThree();
|
||||
const [targetPosition, setTargetPosition] = useState<THREE.Vector3 | null>(null);
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
@@ -28,7 +23,7 @@ function MaterialAnimator({
|
||||
totalDistance: 0,
|
||||
pausedTime: 0,
|
||||
isPaused: false,
|
||||
lastFrameTime: 0
|
||||
lastFrameTime: 0,
|
||||
});
|
||||
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
@@ -38,7 +33,7 @@ function MaterialAnimator({
|
||||
const shouldPause = isGlobalPaused || material.isPaused || conveyor?.isPaused;
|
||||
|
||||
const getWorldPosition = (uuid: string): THREE.Vector3 | null => {
|
||||
const obj = scene.getObjectByProperty('uuid', uuid);
|
||||
const obj = scene.getObjectByProperty("uuid", uuid);
|
||||
if (!obj) return null;
|
||||
const position = new THREE.Vector3();
|
||||
obj.getWorldPosition(position);
|
||||
@@ -65,15 +60,18 @@ function MaterialAnimator({
|
||||
}
|
||||
const newTarget = getWorldPosition(material.next.pointUuid);
|
||||
if (newTarget && matRef.current && !material.isPaused) {
|
||||
animationState.current.startPosition.copy(matRef.current.position);
|
||||
animationState.current.totalDistance = animationState.current.startPosition.distanceTo(newTarget);
|
||||
animationState.current.startTime = performance.now() - animationState.current.pausedTime;
|
||||
animationState.current.pausedTime = 0;
|
||||
animationState.current.isPaused = false;
|
||||
setTargetPosition(newTarget);
|
||||
setIsAnimating(true);
|
||||
// Only reset if target changed or we were previously stopped/done
|
||||
if (!isAnimating || !targetPosition || !newTarget.equals(targetPosition)) {
|
||||
animationState.current.startPosition.copy(matRef.current.position);
|
||||
animationState.current.totalDistance = animationState.current.startPosition.distanceTo(newTarget);
|
||||
animationState.current.startTime = performance.now() - animationState.current.pausedTime;
|
||||
animationState.current.pausedTime = 0;
|
||||
animationState.current.isPaused = false;
|
||||
setTargetPosition(newTarget);
|
||||
setIsAnimating(true);
|
||||
}
|
||||
}
|
||||
}, [material, isPlaying]);
|
||||
}, [material.current.pointUuid, material.next?.pointUuid, material.isPaused, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldPause) {
|
||||
@@ -100,11 +98,7 @@ function MaterialAnimator({
|
||||
const elapsed = (currentTime - animationState.current.startTime) / 1000;
|
||||
const progress = Math.min(1, (currentSpeed * elapsed) / animationState.current.totalDistance);
|
||||
|
||||
matRef.current.position.lerpVectors(
|
||||
animationState.current.startPosition,
|
||||
targetPosition,
|
||||
progress
|
||||
);
|
||||
matRef.current.position.lerpVectors(animationState.current.startPosition, targetPosition, progress);
|
||||
|
||||
if (progress >= 1) {
|
||||
matRef.current.position.copy(targetPosition);
|
||||
@@ -116,7 +110,7 @@ function MaterialAnimator({
|
||||
totalDistance: 0,
|
||||
pausedTime: 0,
|
||||
isPaused: false,
|
||||
lastFrameTime: 0
|
||||
lastFrameTime: 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -124,4 +118,4 @@ function MaterialAnimator({
|
||||
return null;
|
||||
}
|
||||
|
||||
export default React.memo(MaterialAnimator);
|
||||
export default React.memo(MaterialAnimator);
|
||||
|
||||
Reference in New Issue
Block a user