动画状态机(API)是一种用于控制和管理动画切换的工具,你可以用它添加各种动画状态及其之间的转换规则,使角色或动画对象能够在不同动作之间自然的切换。
代表 动画状态机
中的一个单独状态,即某一时刻动画系统中播放的动画。,比如“站立”、“跑步”或“跳跃”。每个状态都有一个对应的 动画片段
。完整的API请参考AnimatorState。
属性 | 功能说明 |
---|---|
Name | 修改 AnimatorState 的名字,名字在所在的层要是唯一的。 |
AnimationClip | 用于绑定 AnimationClip 资产,AnimationClip 存储了模型的动画数据。 |
WrapMode | AnimatorState 是循环播放还是播放一次,默认为 Once 即播放一次。 |
Speed | AnimatorState 的播放速度,默认值为 1.0 ,值越大动画速度越快 |
StartTime | AnimatorState 从 AnimationClip 的哪个时间开始播放,时间为相对 AnimationClip 时长的归一化时间。默认值为 0 ,即从头开始播放。 例如:值为 1.0 ,则是 AnimationClip 的最后一帧状态。 |
EndTime | AnimatorState 播放到 AnimationClip 的哪个时间结束播放,时间为相对 AnimationClip 时长的归一化时间。默认值为 1.0 ,即播放到最后。 |
StateMachineScripts | 允许开发者编写自定义的脚本逻辑,以在动画状态机的不同事件(如状态进入、退出、更新等)中执行特定的代码。它类似于 Script,但专门用于动画状态机。 |
entry
: 用于表示动画状态机的进入点。进入动画状态机时,总是先进入 entry
,然后根据定义的转换条件跳转到其他状态。 entry
本身不会播放动画,它主要用于连接状态机的起点到初始动画状态。通常情况,你应该将它连接到角色或动画对象的默认状态,比如角色的 Idle(站立)
状态。
any
:允许动画状态机中任意状态发生特定条件时跳转到目标状态,这对于处理全局事件或紧急动画(如受伤、死亡)非常有用。
any
状态具有最高的优先级,因此使用 any
需要谨慎,因为它可以打破当前动画的正常流转,可能会导致动画过渡不自然的情况。开发者需要确保只有在明确的条件下才使用 any
进行转换。
exit
:表示动画状态机的退出点。当状态机进入 exit
时,通常意味着状态机结束。状态机将重新进入 entry
状态。
用于定义 动画状态机
中两个 动画状态
之间的转换规则和条件。它决定了何时以及如何从一个 动画状态
切换到另一个 动画状态
。完整的API请参考AnimatorStateTransition。
属性 | 功能说明 |
---|---|
Duration | 过渡时长,时间为相对目标状态的归一化时间,默认值为 0.25 |
Offset | 目标状态向前的偏移时间,时间为相对目标状态的归一化时间,默认值为 0 |
ExitTime | 起始状态过渡开始时间,时间为相对起始状态的归一化时间,默认值为 0.75 |
Solo | 使选定的动画过渡成为唯一活动的状态。其它动画过渡将被忽略。 |
Mute | 禁用选定的动画过渡 |
Conditions | 过渡通过的条件,如果有多个条件,只有所有条件都满足时,才会开始过渡。 |
Solo 和 Mute 通常用于调试,用于帮助开发者更高效地测试和调试 动画状态机
。
将 动画状态
连接到entry
上你导出的项目运行时就会自动播放其上的动画,而不需再调用 animator.play
。点击 动画控制组件
(详细介绍)绑定的 实体
,即可预览动画。
你可以通过 animatorStateMachine.addEntryStateTransition 方法让 动画状态
连接到 动画状态机
的 entry
const animatorStateMachine = animator.animatorController.layers[0].stateMachine;
animatorStateMachine.addEntryStateTransition('Idle');
将两个想要过渡的 动画状态
连接即可实现动画过渡的效果, 点击两个 动画状态
间的连线,可以修改动画过渡的参数调整效果。
点击连线你可以设置 动画过渡
的参数,如添加条件:
若添加多个条件,只有所有条件都满足时,才会开始过渡。
你可以通过为 动画状态
添加 动画过渡
实现 动画状态
间切换的过渡效果。
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");
通过这样的方式你之后每次在该 动画状态机
所在的 动画层
(详细介绍) 播放 walk
动画时都会在播放一半时开始过渡到 run
动画。
你可以通过 animatorStateTransition.addCondition 方法为 动画过渡
添加 过渡条件
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);
通过这样的方式你之后每次在该 动画状态机
所在的层播放 idle
动画时并且 speed
参数大于 0
时,动画将过渡到 walk
动画。
动画参数
用于控制 动画状态机
的 动画状态
切换,通过设置 动画参数
的值满足 动画过渡
的条件时,动画过渡
会触发,从而切换到目标 动画状态
。
你可以通过 animatorController.addParameter 方法来添加 动画参数
,animatorController.removeParameter 方法来删除 动画参数
。
const animatorController = animator.animatorController;
animatorController.addParameter('speed', 0);
// 删除参数
animatorController.removeParameter('speed');
你可以通过 animator.setParameterValue 方法来设置 动画参数
的值
class AnimationScriptExample extends Script {
animator: Animator;
onStart() {
this.animator = this.entity.getComponent(Animator);
}
onUpdate(deltaTime: number) {
const inputManager = this.engine.inputManager;
// 如果用户按下 W 键,则设置 speed 参数值为 1, 符合切换到走路状态的条件,动画切换到走路
if (inputManager.isKeyHeldDown(Keys.KeyW)) {
this.animator.setParameterValue('speed', 1);
}
// 如果用户松开 W 键,则设置 speed 参数值为 0, 符合切换到站立状态的条件,动画切换到站立
if (inputManager.isKeyUp(Keys.KeyW)) {
this.animator.setParameterValue('speed', 0);
}
}
}
你可以通过 animator.getParameterValue 方法来获取 动画参数
的值:
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")
}
}
}
你可以通过 animator.getParameter 方法来获取 动画参数
对象:
class AnimationScriptExample extends Script {
animator: Animator;
onStart() {
this.animator = this.entity.getComponent(Animator);
const speedParameter = this.animator.getParameter('speed');
// 设置 speed 的默认值
speedParameter.defaultValue = 0;
}
}
将 动画状态
连接到 exit
状态,动画状态机
会退出并重新进入 entry
,使得整体流程循环
你可以通过 state.addExitTransition 方法让 动画状态
连接到 动画状态机
的 exit
const runState = animatorStateMachine.addState('run');
runState.addExitTransition();
通过这样的方式你之后每次在该 动画状态机
所在的 动画层
播放 Run
动画时都会播放结束就会进入 exit
状态之后重新从 entry
开始。
你可以为每个 动画状态
添加 状态机脚本
,它可以让你在 动画状态机
的不同事件(如状态进入、退出、更新等)中接收到回调详见。
状态机脚本
提供了三个动画状态周期:
onStateEnter
:动画状态开始播放时回调。onStateUpdate
:动画状态更新时回调。onStateExit
:动画状态结束时回调。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)
如果你的脚本不用复用的话你也可以这么写:
state.addStateMachineScript(
class extends StateMachineScript {
onStateEnter(
animator: Animator,
animatorState: AnimatorState,
layerIndex: number
): void {
console.log("onStateEnter: ", animatorState);
}
}
);
每个 动画层
都有一个 动画状态机
,动画最终的表现由多个 动画层
进行混合而成,如何使用 动画层
可以参考动画层文档。