Unity Animation System 动画播放控制

0x00

这是又一次翻以前的代码,用协程写了控制动画播放的逻辑,比如通过时间,检测动画是否播放完成等等。

为了更加通用的场景,这次决定用 Animation Event 来实现,进行尝试。

前面有用过一个 UIEventListener 的脚本组件作为 UI 对象统一添加事件,感兴趣可以点这里去看看……

0x01

在开发过程中,判断一个动画是否播放完成是一个常见的需求,如何在 Unity 中处理这些,首先来解决这些小问题:

  • 控制播放流

在 Animator 组件中,播放特定动画片段

1
animator.Play(string stateName, int layer, float normalizedTime);
  • 停止播放
1
animator.speed = 0;
  • 获取当前状态机的全部动画片段(AnimationClip[])
1
var clips = animator.runtimeAnimatorController.animationClips;
  • 获取当前播放的动画片段
1
animator.GetCurrentAnimatorClipInfo();
  • 获取当前播放的动画信息
1
2
3
4
AnimatorClipInfo info = anim.GetCurrentAnimatorStateInfo(0);
if (info.IsName(statename)){
...
}

0x02

使用 Animation Event,在动画 Animation clip 中添加

(1)在编辑器中添加

此处添在动画结尾处添加了一个事件,回调 AnimCallback 函数。

对于动画事件的回调函数,必须是在 Animator 组件同级的脚本组件中的公共方法。

(2)在代码中添加动画事件

限制:只能在 animator 同级的 gameobject 绑定组件回调函数

目前的解决方法是通过添加事件分发的组件,来回调当前控制器中的事件处理程序。

同时要修改 clip 转换的参数设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using UnityEngine;

public class AnimationEventTrigger : MonoBehaviour
{
public delegate void AnimDelegate(GameObject go, AnimatorStateInfo info);

public event AnimDelegate AnimOnEvent;

public static AnimationEventTrigger GetListener(GameObject go)
{
AnimationEventTrigger listener = go.GetComponent<AnimationEventTrigger>();

if (null == listener)
{
listener = go.AddComponent<AnimationEventTrigger>();
}

return listener;
}

public void AddEventToClip(string clipName, float triggerTime)
{
var animator = gameObject.GetComponent<Animator>();

if (animator != null)
{
AnimationEvent evt = new AnimationEvent()
{
time = triggerTime,
functionName = "AnimCallback",
};

var clips = animator.runtimeAnimatorController.animationClips;
foreach (var c in clips)
{
if (c.name == clipName)
{
c.AddEvent(evt);
}
}
}

}

public void AnimCallback()
{
if (null != AnimOnEvent)
{
AnimOnEvent(gameObject, gameObject.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0));
}
}
}

0x03

其他问题:

在 Game 视图下,对动画中子对象激活状态的控制无效,测试时 起始状态为无效时就能正常显示,否则显示动画显示错误。

在对象没有激活时,是没有办法获取到对象的组件的。

0x04

很多时候不犯错是记不得的,

很多时候很久没犯错也会忘记了错误是怎么避免的,

可能不对,但我就是想瞎白话。

絮叨模式开启,

我作为菜狗子经常犯的错误是让不同的对象同时访问同一份数据,期望他们足够聪明,能知道我想让谁先用,并且,别把东西弄坏了,任何东西,但是……

好吧,感觉多线程要解决的就是这个问题吧。

之所以这么说,是因为前段时间有做一个上色的小功能,当时在区分不同区域时用了 static 原本是想作为标记,因为所有公用一个变量,让我觉得是互斥的关系,也就同一时刻,无论是谁修改了这个值,大家都知道了,但碰上了update更新顺序的问题,扑街,那时候了解了其实要进行这种操作,在控制器脚本的位置进行处理时最好的,在事件发生时转到控制器脚本进行处理就可以了,是我之前的一篇文章里的解决方案。(好像都是在处理事件的时候出现的诶)。

这次又是同样,其实是一个尝试性的需求,同时对四个对象进行相同的操作,让他们同时访问了同一个当前值作为显示,用同一个值进行检测判断停止,然后……反正就跑起来很诡异了。