上一节视频中,鼠标已经已经可以识别到敌人,并且更改对应的样式。在这一节中,我们需要实现:点击敌人,角色跑到敌人旁边,然后攻击敌人。
1. 移动到敌人边上
移动到敌人边上的逻辑和之前的人物移动逻辑类似,我们在 MouseManager 脚本中添加逻辑。如代码清单 1 所示,我们增加了一个攻击敌人事件(第 4 行),传递的参数为敌人对象;鼠标左键敌人时触发(第 14 行)。
接着我们到 PlayerController 脚本中实现攻击事件的响应。
如代码清单 2 所示,将 DoAttackAction 函数绑定到攻击事件(第 27 行);DoAttackAction 中会另起一个协程来实现攻击逻辑。目前协程中只实现了移动到敌人身边的逻辑:如果角色和敌人之间的距离不够,则反复设置 Nav Mesh Agent 的 destination 值。跑到敌人身边后需要停止移动(isStopped = true),以免发生碰撞。
第一次接触协程,这边记录一下自己目前的理解。协程是在线程层面调度的(和线程不同,线程在进程层面调度)。线程的调度好理解,多处理器上真正并行,单处理器上时间片分配。但是协程的调度还不太清楚,视频以及其他资料看说,执行 "yield return" 协程会挂起,执行权给到调度者,等待下一次调度恢复。这边如何实现的挂起和恢复操作比较费解,因为之前理解的这些操作是在操作系统层面实现的,留作问题。
2. 设置攻击动画
以上,我们已经实现点击敌人,移动到敌人身边的功能了。在移动到敌人身边之后,我们需要播放攻击动画。
如图 1 所示,我们回到之前人物的动画设置窗体。首先我们在人物素材包里选择攻击动画,将其拖拽到界面中,并将生成的状态命名。接着我们右键选择 Make Transition,建立和移动 Blend Tree 之间的进入和退出连接。然后新建一个 Trigger 类型变量 Attack,用于触发攻击。
最后如图 2 所示进行转移设置。Blend Tree 到 Attack 之间转移使用 Attack 变量触发,不需要退出时间;Fixed Duration 和 Transition Duration 也按照图上设置,含义不明。Attack 到 Blend Tree 之间的转移,需要退出时间,这边设置为 1,确保攻击动画完整播放。
注意触发转移不需要退出时间,否则会造成攻击动画播放延迟。
3. 实现攻击逻辑
在设置好攻击动画之后,我们继续完善协程中的攻击逻辑。如代码清单 3 所示,我们使用 Animator.SetTrigger 触发攻击动画(第 18 行)。此外,我们还设置了一个攻击冷却时间(第 3 行),时间在 Update() 函数中进行更新。
至此,我们已经实现了跑到敌人身边并攻击。但是还有一个问题:攻击敌人后,人物无法继续移动。点击地板无法移动的原因是之前把人物停止了,如代码清单 4 所示,现在需要恢复回来(第 4 行)。
还有一个比较大的问题是,当攻击阶段时,点击地板无法打断。这边解决的方案是随即使用 StopAllCoroutines() 停止正在运行的协程(第 3 行)。但是这个方案还是解决不了打断时继续播放攻击动画的问题。
最终的移动、攻击和打断效果如图 3 所示。