这是侑虎科技第504篇文章,感谢作者加菲教主供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)
作者主页:https://www.jianshu.com/u/56cdb7666533,作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!
概述
最近在试做一个射击游戏的人物动画Demo,尝试使用了部分Unity的人形动画(Humanoid),以及 Playable Graph + Animation Job的功能。目前和美术同事配合,在Unity 2018.3.0f2 中初步实现了空手移动和持枪瞄准的功能,在此做个小结。为简单起见,不使用Root motion,使用原地动画,并将动画部分视为表现层,可以读取逻辑层提供的数据,但是不写入这些数据。
基本结构
1. 核心类
动画控制器(AnimController)类:所有动画代码的驱动者。根据动画图资产、来构建动画图,并驱动动画逻辑。将数据提供者、Transform绑定等传入动画图实例。
动画数据提供者(IAnimDataProvider) 接口:动画控制代码通过这个接口,以key-value的形式来读取业务逻辑设置的数据。具体的数据类可以实现这个接口,并将其交给 AnimController 来使用。
动画图资产(AnimGraphAsset)基类:从动画图中的节点抽象而成的可配置的模块,运行时可以生成实例。这个做法来自 [1]。
动画图实例(IAnimGraphInstance)接口:动画图资产的实例,最终由这些实例在运行时操作动画图。
节点绑定集合(TransformBindingCollection)类:将骨骼或其他节点通过键值方式存放,以便 AnimGraphAsset 只依赖节点的键就能在运行时获取 Transform,而不需要依赖某个具体的 Transform 对象。
下面类图简单表示了这些类的关系:
类图
2. 逻辑数据的获取
如下 IAnimDataProvider 接口用来将数据传递给控制动画的代码。
public interface IAnimDataProvider
{
float GetFloat(string key);float GetFloat(int keyId);int GetInt(string key);int GetInt(int keyId);bool GetBool(string key);bool GetBool(int keyId);int GetStateId(int stateGroupId);int GetStateId(string stateGroupName);
}
使用这个接口就可以通过给定的关键字(key)去获取相应的数据,以及获取给定的一个状态机的当前状态。具体的数据类可以实现这个接口,每一帧由业务逻辑填充好数据。
为什么每个函数有两个重载版本呢?这是仿照Animator和Material中查找属性的思路,如果具体数据提供者类是以散列表(如 Dictionary)实现,