1 有限状态机简介
有限状态机(英语:finite-state machine,缩写:FSM),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型
在游戏开发中应用有限状态机,能够将复杂的行为逻辑分解为一组简单的状态和转换规则,每个状态都可以独立地处理其逻辑,使代码更加结构化和组织化。同时可以方便的添加新的状态和转换规则,以适应游戏的需求。而且避免了在每帧中检查所有可能的行为,只需要处理当前状态的逻辑
Unity 中的 Animator Controller 使用状态机来管理各种动画状态和它们之间的过渡。但角色处于不同的状态时,除了播放对应的动画外,也会执行相关的逻辑,使用状态机来控制角色的行为也会为开发带来很大的便利
2 动画状态机
1 动画工作流程
Unity 的动画系统基于动画剪辑的概念;动画剪辑包含某些对象应如何随时间改变其位置、旋转或其他属性的相关信息。每个剪辑可视为单个线性录制。来自外部的动画剪辑由美术师或动画师使用第三方工具(例如 Autodesk® 3ds Max® 或 Autodesk® Maya®)创建而成,或者来自动作捕捉工作室或其他来源
然后,动画剪辑将编入称为 Animator Controller 的一个类似于流程图的结构化系统中。Animator Controller 充当状态机,负责跟踪当前应该播放哪个剪辑以及动画应该何时改变或混合在一起
2 动画状态机
角色或其他动画游戏对象通常具有若干不同的动画,这些动画对应于该角色或对象可在游戏中执行的不同动作。例如,角色可以在空闲时轻微呼吸或摇摆,在得到指令时行走,以及从平台上跌落时恐慌地抬起手臂。Mecanim 使用类似于流程图的可视化布局系统来表示状态机,从而控制需要在角色或对象上使用的动画剪辑并对这些动画剪辑排序
状态机的基本思想是使角色在某一给定时刻进行一个特定的动作。动作类型可因游戏类型的不同而不同,常用的动作包括空闲、行走、跑步、跳跃等,其中每一个动作被称为一种状态。在某种意义上,角色处于行走、空闲或者其它的状态中。一般来说,角色从一个状态立即切换到另一个状态是需要一定的限制条件的。比如角色只能从跑步状态切换到跑跳状态,而不能直接由静止状态切换到跑跳状态。角色从当前状态进入下一个状态的选项被称为状态过渡条件。状态集合、状态过渡条件以及记录当前状态的变量放在一起,形成了一个状态机
状态及其过渡条件可以通过图形来表达,其中的节点表示状态,而弧线(节点间的箭头)表示状态过渡。可以将当前状态视为放置在节点之一上的标记或亮点,然后只能沿箭头之一跳转到另一个节点
状态机对于动画的重要意义在于用户可以通过很少的代码对状态机进行设计和升级。每一个状态有一个与之关联的运动,只要状态机处于此状态,就会播放此运动。从而让动画师或设计师方便地定义动作顺序,而不必去关心底层代码的实现
Unity 的动画状态机提供了一种纵览角色所有动画剪辑的方法,并且允许通过游戏中的各种事件(如用户输入)来触发不同的动画效果
动画状态机可以通过 Animator Controller 窗口来创建,这些状态机如下所示:
动画状态机包括动画状态、动画过渡和动画事件,而复杂的状态机还可以含有简单的子状态机,更多信息请参阅文档「https://docs.unity3d.com/cn/2021.2/Manual/AnimationOverview.html」
3 Animator Controller
1 创建资源
Animator Controller 资源是在 Unity 内创建的,可以为角色或对象维护一组动画,更多信息请参阅:「https://docs.unity3d.com/cn/2021.2/Manual/Animator.html」
可通过以下方式创建 Animator Controller:
-
从 Project 视图中,选择 Create > Animator Controller
-
在 Project 视图中右键单击并选择 Create > Animator Controller
-
从 Assets 菜单中,选择 Assets > Create > Animator Controller
2 查看视图
在 Animator 窗口中可创建、查看和修改 Animator Controller 资源,视图内使用鼠标中键或按住 Alt/Option 键拖拽可平移视图,更多信息请参阅文档:「https://docs.unity3d.com/cn/2021.2/Manual/AnimatorWindow.html」
可通过以下方式查看 Animator Controller 视图:
-
从 Assets 菜单中,选择 Window > Animation > Animator
-
双击 Animator Controller 资源
3 整理状态
双击角色的 Animator Controller,可以看到对应的状态机,当前状态机会把所有的动作依次执行一遍
游戏中暂时需要的状态包括: idle、move、attack、define、skill、die,可以整理已经存在的状态,也可以新建状态
-
整理状态:断开转换,选中状态或者箭头,点击-号
-
新建状态:拖动动画资源到窗口,自动创建状态
整理后的状态机:
3 行为状态机
在 Animator Controller 中可以看到,每个状态机包含多个状态节点,每个状态节点包含一个状态及多个转换:
选中转换,查看转换信息,每个转换包含多个过渡条件,同时转换需要有来源及目标,即从什么状态转换到什么状态
了解 Unity 的动画状态机后,根据这些基本要素,构建行为状态机
1 过渡条件
从当前状态进入下一个状态的选项被称为状态过渡条件,因此,条件类中需要一个有返回值的函数的委托,来判定是否进入目标状态
public class Condition
{
private Func<bool> _func { get; }
public Condition(Func<bool> func)
{
_func = func;
}
public bool Evaluate() => _func.Invoke();
}
2 转换
转换中包含目标状态及过渡条件
public class Transition<TEnum> where TEnum : Enum
{
public TEnum To { get; }
public Condition Condition { get; }
public Transition(TEnum to, Condition condition)
{
To = to;
Condition = condition;
}
}
3 状态
状态中包含进入、更新、退出等事件,为了与角色调用方便,额外增加状态所属者
public class State<TOwner> where TOwner : class
{
public readonly TOwner Owner;
public State(TOwner owner)
{
Owner = owner;
}
public virtual void OnEnter()
{
}
public virtual void OnUpdate()
{
}
public virtual void OnFixedUpdate()
{
}
public virtual void OnExit()
{
}
}
4 状态节点
状态及其对应的转换构成一个状态节点
public class StateNode<TEnum, TOwner> where TEnum : Enum where TOwner : class
{
public TEnum Key { get; }
public State<TOwner> State { get; }
public HashSet<Transition<TEnum>> Transitions { get; }
public StateNode(TEnum key, State<TOwner> state)
{
Key = key;
State = state;
Transitions = new HashSet<Transition<TEnum>>();
}
public void AddTransition(TEnum to, Condition condition)
{
Transitions.Add(new Transition<TEnum>(to, condition));
}
}
5 状态机
状态集合、状态过渡条件以及记录当前状态的变量放在一起,形成了一个状态机