Open chillbert opened 3 months ago
Unfortunately, at the moment, you will need to combine the animations to your character.glb to make it work. I tried to create a featrue using external fbx animations before, but the transition in between was really bad. I will get back to this feature maybe latter on 😅
So, how to increase the animation amount? e.g. action1, action2 ... action8
I was able to add support for loading external fbx animations in my project.
Here is the updated EcctrlAnimation.tsx file:
import { useEffect, useRef, Suspense, useState, useMemo } from "react";
import * as THREE from "three";
import { useGame, type AnimationSet } from "./stores/useGame";
import React from "react";
import { useFrame, useLoader } from "@react-three/fiber";
import { FBXLoader } from "three-stdlib";
export const ANIMATIONS = {
idle: '/resources/animation/Happy.fbx',
walk: '/resources/animation/Happy Walk.fbx',
run: '/resources/animation/Fast Run.fbx',
dancing: '/resources/animation/Silly Dancing.fbx',
sad: '/resources/animation/Sad Idle.fbx',
excited: '/resources/animation/Excited.fbx',
point: '/resources/animation/Angry Point.fbx',
clap: '/resources/animation/Clapping.fbx',
rally: '/resources/animation/Rallying.fbx',
thankful: '/resources/animation/Thankful.fbx',
jump: '/resources/animation/Jump.fbx',
tpose: '/resources/animation/T-Pose.fbx',
sleep: '/resources/animation/Sleep.fbx',
eating: '/resources/animation/eating.fbx',
};
export function EcctrlAnimation(props: EcctrlAnimationProps) {
const [mixer, setMixer] = useState<THREE.AnimationMixer | null>(null);
// Change the character src to yours
const group = useRef();
// const { animations } = useGLTF(props.characterURL);
const animations = useLoader(FBXLoader, Object.values(ANIMATIONS)).map(f => f.animations[0]);
const actions = useMemo(() => mixer ? Object.keys(ANIMATIONS).reduce<{ [key: string]: THREE.AnimationAction }>((acc, key, index) => {
acc[key] = mixer.clipAction(animations[index], props.character);
return acc;
}, {}) : {}, [mixer, animations]);
useFrame((_, delta) => {
mixer?.update(delta);
// TWEEN.update();
});
useEffect(() => {
if (!props.character) return;
const newMixer = new THREE.AnimationMixer(props.character);
setMixer(newMixer);
return () => {
newMixer.stopAllAction();
newMixer.uncacheRoot(newMixer.getRoot());
};
}, [props.character]);
/**
* Character animations setup
*/
const curAnimation = useGame((state) => state.curAnimation);
const resetAnimation = useGame((state) => state.reset);
const initializeAnimationSet = useGame(
(state) => state.initializeAnimationSet
);
useEffect(() => {
// Initialize animation set
initializeAnimationSet(props.animationSet);
}, [actions]);
useEffect(() => {
// Play animation
const action =
actions[curAnimation ? curAnimation : props.animationSet.jumpIdle];
if(!action) return;
// For jump and jump land animation, only play once and clamp when finish
if (
curAnimation === props.animationSet.jump ||
curAnimation === props.animationSet.jumpLand ||
curAnimation === props.animationSet.action1 ||
curAnimation === props.animationSet.action2 ||
curAnimation === props.animationSet.action3 ||
curAnimation === props.animationSet.action4
) {
action
.reset()
.fadeIn(0.2)
.setLoop(THREE.LoopOnce, undefined as number)
.play();
action.clampWhenFinished = true;
} else {
action?.reset().fadeIn(0.2).play();
}
// When any action is clamp and finished reset animation
mixer?.addEventListener("finished", () => resetAnimation());
return () => {
// Fade out previous action
action.fadeOut(0.2);
// Clean up mixer listener, and empty the _listeners array
// (action as any)._mixer.removeEventListener("finished", () =>
// resetAnimation()
// );
// (action as any)._mixer._listeners = [];
};
}, [curAnimation]);
return (
<Suspense fallback={null}>
<group ref={group} dispose={null} userData={{ camExcludeCollision: true }}>
{/* Replace character model here */}
{props.children}
</group>
</Suspense>
);
}
export type EcctrlAnimationProps = {
character: any;
animationSet: AnimationSet;
children: React.ReactNode;
};
My setup is usually so that I have a character.glb file and then lots of different animations from one or multiple fbx files, which I apply on the character like this:
(this setup makes totally sense when you have multiple characters in a multiplayer game with small size and have only once to load all the animations for all players (since they are all the same right?):
how would I achieve this in this case:
Do I need to manipulte the EcctrlAnimation.tsx by myself?