feat: Enhance human event handling and animation management, including state updates and monitoring

This commit is contained in:
2025-07-03 16:55:30 +05:30
parent 8dd853dd03
commit 1e715cee50
13 changed files with 316 additions and 36 deletions

View File

@@ -49,6 +49,10 @@ function Model({ asset }: { readonly asset: Asset }) {
const { userId, organization } = getUserData();
const mixerRef = useRef<THREE.AnimationMixer>();
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
const [currentAnimation, setCurrentAnimation] = useState<string | null>(null);
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
const [blendFactor, setBlendFactor] = useState(0);
const blendDuration = 0.3;
useEffect(() => {
setDeletableFloorItem(null);
@@ -278,8 +282,16 @@ function Model({ asset }: { readonly asset: Asset }) {
}
}
const handleAnimationComplete = useCallback(() => {
console.log(`Animation "${currentAnimation}" completed`);
}, [currentAnimation]);
useFrame((_, delta) => {
if (mixerRef.current) {
if (blendFactor < 1) {
setBlendFactor(prev => Math.min(prev + delta / blendDuration, 1));
}
mixerRef.current.update(delta);
}
});
@@ -288,17 +300,46 @@ function Model({ asset }: { readonly asset: Asset }) {
if (asset.animationState && asset.animationState.isPlaying) {
if (!mixerRef.current) return;
Object.values(actions.current).forEach((action) => action.stop());
const action = actions.current[asset.animationState.current];
if (action && asset.animationState?.isPlaying) {
const loopMode = asset.animationState.loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce;
action.reset().setLoop(loopMode, loopMode === THREE.LoopRepeat ? Infinity : 1).play();
if (asset.animationState.current !== currentAnimation) {
setPreviousAnimation(currentAnimation);
setCurrentAnimation(asset.animationState.current);
setBlendFactor(0);
}
const currentAction = actions.current[asset.animationState.current];
const previousAction = previousAnimation ? actions.current[previousAnimation] : null;
if (currentAction) {
const loopMode = asset.animationState.loopAnimation ? THREE.LoopRepeat : THREE.LoopOnce;
currentAction.reset();
currentAction.setLoop(loopMode, loopMode === THREE.LoopRepeat ? Infinity : 1);
currentAction.play();
mixerRef.current.addEventListener('finished', handleAnimationComplete);
if (previousAction && blendFactor < 1) {
previousAction.crossFadeTo(currentAction, blendDuration, true);
}
}
Object.entries(actions.current).forEach(([name, action]) => {
if ((asset.animationState && name !== asset.animationState.current) && name !== previousAnimation) {
action.stop();
}
});
} else {
Object.values(actions.current).forEach((action) => action.stop());
setCurrentAnimation(null);
}
}, [asset.animationState])
return () => {
if (mixerRef.current) {
mixerRef.current.removeEventListener('finished', handleAnimationComplete);
}
}
}, [asset.animationState, currentAnimation, previousAnimation, handleAnimationComplete]);
return (
<group