The AnimatorStateMachine (API) is a tool used to control and manage animation transitions. You can use it to add various animation states and their transition rules, allowing characters or animated objects to switch naturally between different actions.
Represents a single state in the AnimatorStateMachine
, i.e., the animation being played at a certain moment in the animation system, such as "Standing", "Running", or "Jumping". Each state has a corresponding Animation Clip
. For the complete API, please refer to AnimatorState.
Property | Description |
---|---|
Name | Modify the name of the AnimatorState , which must be unique within the layer. |
AnimationClip | Used to bind the AnimationClip asset, which stores the animation data of the model. |
WrapMode | Whether the AnimatorState plays in a loop or once, the default is Once , which means it plays once. |
Speed | The playback speed of the AnimatorState , the default value is 1.0, the larger the value, the faster the animation speed. |
StartTime | The time from which the AnimatorState starts playing the AnimationClip , the time is the normalized time relative to the duration of the AnimationClip . The default value is 0, which means it starts playing from the beginning. For example, if the value is 1.0, it is the last frame of the AnimationClip . |
EndTime | The time at which the AnimatorState stops playing the AnimationClip , the time is the normalized time relative to the duration of the AnimationClip . The default value is 1.0, which means it plays to the end. |
StateMachineScripts | Allows developers to write custom script logic to execute specific code during different events (such as state enter, exit, update, etc.) of the AnimatorStateMachine. It is similar to Script but specifically for the AnimatorStateMachine. |
entry
: Represents the entry point of the AnimatorStateMachine. When entering the AnimatorStateMachine, it always enters entry
first, and then jumps to other states according to the defined transition conditions. entry
itself does not play animations; it mainly connects the starting point of the state machine to the initial AnimatorState
. Typically, you should connect it to the default state of the character or animated object, such as the character's Idle
state.
any
: Allows any state in the AnimatorStateMachine to transition to the target state when specific conditions are met. This is useful for handling global events or emergency animations (such as being injured or dying).
The any
state has the highest priority, so use any
with caution, as it can disrupt the normal flow of the current animation, potentially leading to unnatural animation transitions. Developers need to ensure that any
is used only under clear conditions.
exit
: Represents the exit point of the AnimatorStateMachine. When the state machine enters exit
, it usually means the state machine ends. The state machine will re-enter the entry
state.
Used to define the transition rules and conditions between two AnimatorState
in the AnimatorStateMachine
. It determines when and how to switch from one AnimatorState
to another. For the complete API, please refer to AnimatorStateTransition.
Property | Description |
---|---|
Duration | The transition duration, the time is the normalized time relative to the target state, the default value is 0.25 |
Offset | The forward offset time of the target state, the time is the normalized time relative to the target state, the default value is 0 |
ExitTime | The start time of the transition from the initial state, the time is the normalized time relative to the initial state, the default value is 0.75 |
Solo | Makes the selected animation transition the only active state. Other animation transitions will be ignored. |
Mute | Disables the selected animation transition |
Conditions | The conditions for the transition to pass. If there are multiple conditions, the transition will only start when all conditions are met. |
Solo and Mute are usually used for debugging, helping developers test and debug the AnimatorStateMachine
more efficiently.
Connecting the AnimatorState
to entry
will automatically play the animation on it when you run the exported project, without needing to call animator.play
. Click the entity
bound to the Animation Control Component
(detailed introduction) to preview the animation.
You can use the animatorStateMachine.addEntryStateTransition method to connect the AnimatorState
to the entry
of the AnimatorStateMachine
.
const animatorStateMachine = animator.animatorController.layers[0].stateMachine;
animatorStateMachine.addEntryStateTransition('Idle');
Connecting two AnimatorState
will achieve the effect of animation transition. Click the line between the two AnimatorState
to modify the parameters of the animation transition to adjust the effect.
Click the line to set the parameters of the AnimatorStateTransition
, such as adding conditions:
If multiple conditions are added, the transition will only start when all conditions are met.
You can add an AnimatorStateTransition
to the AnimatorState
to achieve the transition effect between AnimatorState
.
const walkState = animatorStateMachine.addState('walk');
walkState.clip = walkClip;
const runState = animatorStateMachine.addState('run');
runState.clip = runClip;
const transition = new AnimatorStateTransition();
transition.duration = 1;
transition.offset = 0;
transition.exitTime = 0.5;
transition.destinationState = runState;
walkState.addTransition(transition);
animator.play("walk");
In this way, every time you play the walk
animation in the animation layer
(detailed introduction) where the AnimatorStateMachine
is located, it will start transitioning to the run
animation halfway through.
You can use the animatorStateTransition.addCondition method to add transition conditions
to the AnimatorStateTransition
.
const idleState = animatorStateMachine.addState('idle');
idleState.clip = idleClip;
const walkState = animatorStateMachine.findStateByName('walk');
const transition = new AnimatorStateTransition();
transition.addCondition(AnimatorConditionMode.Greater, 'speed', 0);
transition.destinationState = walkState;
idleState.addTransition(transition);
In this way, every time you play the idle
animation in the layer where the AnimatorStateMachine
is located and the speed
parameter is greater than 0
, the animation will transition to the walk
animation.
AnimatorControllerParameter
are used to control the AnimatorState
transitions of the AnimatorStateMachine
. By setting the value of the AnimatorControllerParameter
to meet the conditions of the AnimatorStateTransition
, the AnimatorStateTransition
will be triggered, switching to the target AnimatorState
.
You can use the animatorController.addParameter method to add AnimatorControllerParameter
and the animatorController.removeParameter method to remove AnimatorControllerParameter
.
const animatorController = animator.animatorController;
animatorController.addParameter('speed', 0);
// Remove parameter
animatorController.removeParameter('speed');
You can use the animator.setParameterValue method to set the value of AnimatorControllerParameter
.
class AnimationScriptExample extends Script {
animator: Animator;
onStart() {
this.animator = this.entity.getComponent(Animator);
}
onUpdate(deltaTime: number) {
const inputManager = this.engine.inputManager;
// If the user presses the W key, set the speed parameter value to 1, meeting the condition to switch to the walking state, and the animation switches to walking.
if (inputManager.isKeyHeldDown(Keys.KeyW)) {
this.animator.setParameterValue('speed', 1);
}
// If the user releases the W key, set the speed parameter value to 0, meeting the condition to switch to the standing state, and the animation switches to standing.
if (inputManager.isKeyUp(Keys.KeyW)) {
this.animator.setParameterValue('speed', 0);
}
}
}
You can use the animator.getParameterValue method to get the value of AnimatorControllerParameter
:
class AnimationScriptExample extends Script {
animator: Animator;
onStart() {
this.animator = this.entity.getComponent(Animator);
}
onUpdate(deltaTime: number) {
const speed = this.animator.getParameterValue('speed');
if (speed === 1) {
console.log("The player is walking")
}
}
}
You can use the animator.getParameter method to get the AnimatorControllerParameter
object:
class AnimationScriptExample extends Script {
animator: Animator;
onStart() {
this.animator = this.entity.getComponent(Animator);
const speedParameter = this.animator.getParameter('speed');
// Set the default value of speed
speedParameter.defaultValue = 0;
}
}
Connecting the AnimatorState
to the exit
state will cause the AnimatorStateMachine
to exit and re-enter the entry
, making the overall process loop.
You can use the state.addExitTransition method to connect the AnimatorState
to the exit
of the AnimatorStateMachine
.
const runState = animatorStateMachine.addState('run');
runState.addExitTransition();
In this way, every time you play the Run
animation in the Animation Layer
where the AnimatorStateMachine
is located, it will enter the exit
state after playing and then start again from entry
.
You can add State Machine Scripts
to each AnimatorState
, allowing you to receive callbacks during different events (such as state enter, exit, update, etc.) of the AnimatorStateMachine
see details.
StateMachineScript
provide three AnimatorState
cycles:
onStateEnter
: Callback when the AnimatorState
starts playing.onStateUpdate
: Callback when the AnimatorState
updates.onStateExit
: Callback when the AnimatorState
ends.class theScript extends StateMachineScript {
/**
* onStateEnter is called when a transition starts and the state machine starts to evaluate this state.
* @param animator - The animator
* @param animatorState - The state be evaluated
* @param layerIndex - The index of the layer where the state is located
*/
onStateEnter(animator: Animator, animatorState: AnimatorState, layerIndex: number): void {
console.log(`Enter ${animatorState.name}`)
}
/**
* onStateUpdate is called on each Update frame between onStateEnter and onStateExit callbacks.
* @param animator - The animator
* @param animatorState - The state be evaluated
* @param layerIndex - The index of the layer where the state is located
*/
onStateUpdate(animator: Animator, animatorState: AnimatorState, layerIndex: number): void {
console.log(`Update ${animatorState.name}`)
}
/**
* onStateExit is called when a transition ends and the state machine finishes evaluating this state.
* @param animator - The animator
* @param animatorState - The state be evaluated
* @param layerIndex - The index of the layer where the state is located
*/
onStateExit(animator: Animator, animatorState: AnimatorState, layerIndex: number): void {
console.log(`Exit ${animatorState.name}`)
}
}
animatorState.addStateMachineScript(theScript)
If your script does not need to be reused, you can also write it like this:
state.addStateMachineScript(
class extends StateMachineScript {
onStateEnter(
animator: Animator,
animatorState: AnimatorState,
layerIndex: number
): void {
console.log("onStateEnter: ", animatorState);
}
}
);
Each Animation Layer
has an AnimatorStateMachine
, and the final animation performance is blended by multiple Animation Layer
. For how to use Animation Layer
, please refer to the Animation Layer documentation.