- 游戏架构:核心技术与面试精粹
- 樊松阳
- 1521字
- 2020-08-28 01:55:24
2.3 动画事件
请简述动画事件的制作与逻辑处理方法,如果有多种备选方案,请对比它们的优劣。
问题分析
在编写战斗系统时,我们需要处理动画事件。所谓动画事件,指的是动画进行到某个时刻触发的事件。例如,当角色跳起,双脚离开地面时,要播放吹起烟尘的特效;当角色落地时,要发出撞地的声响;角色攻击,手举到最高点时,要投掷出飞镖,等等。这些与动作紧密结合的功能都属于动画事件(后面简称事件)。如何制作这些事件,并在运行时控制游戏逻辑,成为战斗逻辑不可或缺的部分。
基于动画的事件
对于显示型事件,比如播放声音或特效,通常采用基于动画的事件。尤其是当动作之间存在复杂的混合时,这种事件编辑方式尤为重要。例如,开枪动画与行走动画进行混合,以求达到边跑边开枪的动画效果。在开枪时要播放弹壳四散的特效,跑步时要播放脚步声,由于开枪动作与跑步动作的时长不同,为了使两者融合后看起来更加合理,美术人员需要反复调整资源或融合参数。在Unreal引擎中,这部分功能更加完善,它提供了详细的参数以帮助美术人员调整事件效果,效果如图2.5所示。
图2.5
在Unity 3D中也可以制作基于动画的事件。为了详细说明这个功能,笔者创建了一个名为AnimEvent.cs的脚本文件,在其中编写如下代码:
using UnityEngine; using System.Collections; public class AnimEvent : MonoBehaviour { public void MyEvent() { Debug.Log("My Event Triggered"); } }
编辑好代码后,选择一个动作的FBX文件。这里我们使用Unity-Chain资源包,它是Unity日本分部开发的一个示例资源,是不少开发者心中的Unity吉祥物,在后面涉及资源相关的内容时均会使用它。
单击Inspector中Animation选项卡底端的Events折叠标签。标签打开后,将动画调整到合适的帧,单击左侧的“添加”按钮,即可添加帧事件的回调函数,我们这里添加刚刚写好的函数,效果如图2.6所示。
图2.6
保存设置后,单击Inspector界面右下角的“Apply”按钮保存更改。
创建一个新场景,将动作对应的模型拖入场景中。接着将动画的AnimationClip文件拖到场景中的模型上,这会创建只有一个动画的Animator。最后将AnimEvent脚本挂载到这个模型上,运行游戏,可以看到当运行到对应帧时,有自定义的日志输出,效果如图2.7所示。
图2.7
基于时间的事件
另一种常见的事件是逻辑型事件。虽然它也与动画的状态紧密相关,但这些事件中包含着逻辑处理。例如,角色在攻击动作的过程中触发伤害;或者在攻击出拳的动作过程中向前移动,遇到敌人就停止移动。这些事件与逻辑紧密相关,不仅取决于美术的表现效果,更多是数值与逻辑的合理性。
对于这种事件,采用基于时间的动画事件就更为合理。在制作事件时,我们记录的是局部时间线的偏移值,并将它以独立文件的形式存储。在上一节中,我们知道游戏中会存在一条游戏时间线。当动作开始时,我们会将这些事件时间偏移量并入游戏时间线,并在游戏时间线的对应时间添加触发事件的回调,这样事件触发就完全脱离了模型动画。
这样做的另一优势是显示与逻辑的分离。在同屏多人的游戏中,有时会有不播放角色动画,只产生技能触发的需求。在这种事件框架下,就可以只运行基于时间的事件而不去加载模型与动画。因为伤害触发与计算不需要依赖于动画,所以一切逻辑都可以正常运行。另外,在有异步数据影响的场景中,这种事件控制方法也有优势,它可以预先做好逻辑计算,再对动画做插值处理,数据优先于动画直接进行同步,将网络延迟对游戏的影响降到最低。
总结
动画事件的制作方法需要灵活选择。一方面需要根据自己游戏的特点,另一方面也要注意自己团队的配置人员能否习惯对应的工作流程。数据载体其实也有多种备选方案。可以通过编写插件,将基于动画的事件帧与3D Max中的动画制作联系在一起。也可以通过编写导出工具,将基于时间的事件配置导出成配置表等。这里要根据实际情况选择处理方式,根据经验做取舍判断,切不可生搬硬套。
扩展问题
在后期优化时发现同屏特效过多,在处理基于动画的特效事件时存在性能瓶颈,请问该如何优化([:animeventopt])?