AnimationUtility.GetAnimationEvents 获取的动画片段信息中 time 和 SerializedObject 对象中保存的 time 字段信息的区别

今天的工作中原本是需要做一个小工具来批量给某些动画加上一个事件,也就是 AnimationEvent 这货。查了一下官方文档,也 Google 了一番,最终在这里找到一个比较符合我需求的解决方案,方案是由 Unity Technologies 的童鞋提供的,看上去还是蛮靠谱的,传送地址在这里

我也就果断拿过来用了,当然前提还是我们自己需要做一番修改的,因为我的需求是只需要在原有的 AnimationClip 已有的 AnimationEvent 列表的最后面添加一个 OnSkillEnd 的 AnimationEvent,所以我需要先获取到已有的 AnimationEvent 信息列表,这里我就想着直接用 AnimationUtility.GetAnimationEvents 方法来搞定了,而且我看到前面提到的 Unity Technologies 的童鞋也是这么做的,那么我也就想着这么搞应该就 OK 了。

不过事实证明这样还是有问题的,因为通过 AnimationUtility.GetAnimationEvents 获得的 AnimationEvent 信息列表中得所有 AnimationEvent 实例中的 time 字段确实是触发时间,也就是动画播放的具体时间,是绝对时间。而 Unity 实际保存到动画 FBX 文件对应的 meta 文件中的 time 字段是相对动画播放进度,可以认为是相对时间。

当我们使用文本方式打开动画 FBX 的 meta 文件时,我们会发现在这个 YAML 文件中有一个 events 节点,这个节点下面保存的就都是这个 AnimationClip 上绑定的所有 AnimationEvent 信息,我们找到 time 字段看一下就会发现,所有 Event 节点中的 time 字段都小于等于 1.0,然后我们再通过 AnimationUtility.GetAnimationEvents 方法将 AnimationClip 中的 AnimationEvent 信息读取出来,我们会发现,这个 AnimationEvent 中 time 实际上就是等于 meta 文件中的 time 字段(动画播放进度百分比)乘以 AnimationClip 的完整时长。

我们可以看一段 YAML 文件:

events:
      - time: .0572792366
        functionName: OnSkillTrigger
        data: a_ke_zhan_attack_1#0
        objectReferenceParameter: {instanceID: 0}
        floatParameter: 0
        intParameter: 0
        messageOptions: 0
      - time: .143198088
        functionName: OnSkillTrigger
        data: a_ke_zhan_attack_1#1
        objectReferenceParameter: {instanceID: 0}
        floatParameter: 0
        intParameter: 0
        messageOptions: 0
      - time: .393794745
        functionName: OnSkillTrigger
        data: a_ke_zhan_attack_1#2
        objectReferenceParameter: {instanceID: 0}
        floatParameter: 0
        intParameter: 0
        messageOptions: 0
      - time: .744630039
        functionName: OnSkillTrigger
        data: a_ke_zhan_attack_1#3
        objectReferenceParameter: {instanceID: 0}
        floatParameter: 0
        intParameter: 0
        messageOptions: 0

所以为了避免出现使用实际时间来作为相对时间保存,我们可以选择自行换算或者直接采用同一个标准进行计算,例如我们读取的时候采用直接读取 SerializedObject 对象中的 SerializedProperty 来获取 time 字段,保存的时候也通过 SerializedObject 对象中 SerializedProperty 来设置新的 time 字段就可以了。