Unity3D RPG Core | 13 设置敌人的动画控制器
这节视频完善史莱姆敌人的追击逻辑,并播放相应的动画。
在此之前,我们为史莱姆对象创建预制体,以及更新角色预制体。之前为角色再单独创建一个预制体时,就有疑惑为什么要再创建一个。现在找到原因了,因为在原先预制体上,我们增加了许多组件,比如 Amimator 和 Nav Mesh Agent。创建预制体后,这些添加的组件和属性就也能复用了。
创建预制体的一个原因。
为史莱姆对象创建预制体和之前的操作一样,只需要把现有 Hierarchy 窗体中的史莱姆对象拖拽到 Assets 窗体中就可以了。
更新已有预制体,我们可以在预制体对应的 Inspector 窗体中的 Prefab - Overrides 下,点击 Apply All,更新所有修改。
1. 追击逻辑
如代码清单 1 所示,上一节中我们在发现角色后会将敌人的状态设置为追击状态(第 27 行),现在我们开始完成追击逻辑。
我们改造之前的寻找角色函数,将返回值修改为角色的 GameObject(第 49 至 59 行)。追击的逻辑先简单实现,追击时如果找到角色,则将 NavMeshAgent.destination 设置为角色的位置(第 37 行);如果没找到角色,即脱战了,敌人需要回到原来的位置,这块逻辑留作之后实现。
视频里还实现了一个小细节,敌人追击时候的速度为设置的默认值(第 34 行),当巡逻时速度减慢(第 31 行)。
写完代码后,回到 Unity 窗体中运行验证。可以看到敌人发现角色后,如预期跟着角色,拉开距离后便呆在原地。
2. 设置动画控制器
目前还缺少史莱姆相关的动画,我们为其新建并指定一个动画控制器。首先如图 1 所示,在默认的 Base Layer 下,代表史莱姆守卫和巡逻状态下的动画。我们添加素材中的 IdleNormal 和 WalkFWD 动画,分别代表待机和行走状态。两者之间的状态转移通过 bool 变量控制,这边我们新建 bool 变量 Walking。同时去掉 Has Exit Time、Fixed Duration 的勾选,Transition Duration 设置为 0。
接着如图 2 所示,点击加号按钮,再创建一个新层,命名为 Attack Layer,它代表追击和攻击状态下的动画。层设置界面上,我们将权重设置为 1,融合方式设置为 Override,即新的层和原有的层是覆盖关系。这边我们有三个状态,一个空状态 BaseState、一个战斗待机状态 IdleBattle 以及奔跑 RunFWD。空状态代表其他层的任意状态。BaseState 和 IdleBattle 状态之间的转移通过 bool 变量 Pursuing;IdleBattle 和 RunFWD 状态之间的转移通过 bool 变量 Following。
这边尝试理解层之间的切换逻辑:此例中 Pursuing 和 Walking 是触发层切换的;空的状态代表其他层任意状态。
有一个问题,Base Layer 切到 Attack Layer,Attack Layer 中会有一个空状态。为什么 Attack Layer 切到 Base Layer,Base Layer 中没有空状态。
设置完动画控制器和相关转移变量后,如代码清单 2 所示,我们实现动画的切换逻辑。首先获取史莱姆对象上的 Animator 组件(第 24 行);接着定义对应的动画转移变量,此处定义了 AnimatorState 结构体,转移变量分别对应 isWalking、isPursuing 和 isFollowing(第 11 至 19 行)。
动画切换的逻辑后续可以慢慢实现,因为我们逐帧更新动画对应的变量:在 Update() 中调用 SwitchAnimation() 函数。
我们先实现追击状态下的动画切换逻辑,此时需要切换到 Attack Layr,所以设置 Walking 为 false,Pursuing 为 true。能发现角色时,设置奔跑状态,Following 为 true;否则为待机状态,Following 为 fals。
返回 Unity 界面运行查看效果,当史莱姆发现角色后会如预期播放奔跑动画。但是还有一个小问题,脱战后史莱姆还会保持待机状态移动一段距离,效果有延迟。
为了解决上述问题,如代码清单 3 所示,当拉脱战时,将敌人的 NavMeshAgent.destination 设置为当前的坐标点(第 31 行),实现快速停止。
最终的效果如图 3 所示,可以看到史莱姆发现角色后播放奔跑动画,拉脱战之后播放待机动画。