Animancer的States(翻译)

原文地址

State

当播放一段动画剪辑(animation clip)时,Animancer会创建一个ClipState来管理它并跟踪其进度。ClipState是最常见的一种AnimancerState,除此之外,有其他类型的AnimancerState,例如Controller StatesMixer States。这些用来在一个state中管理多个动画剪辑。

执行AnimancerComponent.Play函数播放一个animation clip,就返回一个AnimancerState对象,如下代码所示:

1void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
2{
3    // Play the animation and control its state:
4    var state = animancer.Play(clip);
5    state.Time = ...
6    state.NormalizedTime = ...
7    state.Speed = ...
8    state.OnEnd = ...
9}

也可以自己访问和创建状态,而无需立即播放它们:

code description
var state = animancer.States.GetOrCreate(clip); 访问状态而不播放状态(该Play方法在内部使用此状态)。
var state = animancer.States[clip]; 获取状态(如果存在)(否则为null)。
var state = animancer.States.Create(key, clip); 即使该动画已经存在,也要创建一个新状态。注意必须为每个状态提供不同的key。
var state = new ClipState(animancer, clip); 创建一个新状态而不给它一个Key。可以使用其AnimancerState.Key属性分配一个。

Keys

当用AnimancerComponent.Play方法创建一个state时,这个state存储在一个内部的Dictionary容器中,通过指定某个key,用以在以后用这个key来检索使用该state。

  • 默认地,该state所播放的那段动画剪辑所对应的AnimationClip实例对象,将作为该state的key值
  • NameAnimancerComponent将重载其GetKey方法,NameAnimancerComponent类不再使用它播放的AnimationClip对象,而是使用这个动画剪辑的名字字符串去作为key。但在启动时,可以在inspector面板中,在Animation中预先注册好这个
 1void PlayAnimation(AnimancerComponent animancer, AnimationClip clip)
 2{
 3    // Trying to play an animation before registering it does nothing.
 4	// 通过名字的方式试图去播一个animation clip,如果尚未注册的
 5	// 话,通过名字是无法找到对应的animation clip去播放的
 6    animancer.Play("Attack");
 7
 8    // But if you create a state with a key first, then you only need that key to play it later on.
 9	// 如果预先创建一个state,该state通过字符串Attack作为key,指向一个clip,再调用播放接口就能正确播放了
10    animancer.States.Create("Attack", clip);
11    animancer.Play("Attack");
12
13    // Or you can create the state and set its key manually:
14	// 或者直接创建一个ClipState对象,然后显式地设置
15    var state = new ClipState(clip);
16    state.Key = "Attack";
17}
  • 如果不需要,则不需要设置AnimancerState.Key。可以简单地创建一个ClipState(或其他所需的一种AnimancerState)。并在要使用它时保留对其的引用。
  • 如果要让多个state播放同一个animation clip(例如:需要在多个Layer上播放它),则需要使用不同的key注册所有状态(或根本不注册)。FadeMode.FromStart使用此选项可以使剪辑淡出,同时使另一个副本同时淡入。

Enum Keys

枚举值可以用作key,但枚举是值类型,所以用枚举做key的时候,要对它进行装箱操作。相对而言,会带来一些性能消耗

Object Keys

Another approach is to use actual objects as keys. Rather than an enum you could make a class like this: 可以创建一个显式的object来做为key,如下代码:

1public static class CreatureAction
2{
3    public static readonly object Idle = new object();
4    public static readonly object Walk = new object();
5    public static readonly object Run = new object();
6    // Etc.
7}

这些objects实际上不会自行执行任何操作,但可以按类似于enum的方式用来作为key:animancer.States.Create(CreatureAction.Walk, _Walk)

Component Keys

如果脚本只有一个要播放的动画,则可以将其自己用作键,因此Walk脚本可以使用代码animancer.States.Create(this, _Walk);创建state。并使用animancer.Play(this)播放animation clip。但是,如果它实际上是一个Movement将Walk和Run动画作为单独的状态进行处理的脚本,则该方法将无效。

Performance

就像其他操作一样,创建一个AnimancerState,并将其连接到“Playable Graph”需要花费一些时间。在大多数情况下,此成本很小,因此不值得考虑,因此您应该在最方便的地方创建状态。这就是为什么使用Animancer的最常见方法是直接给Play方法传递AnimationClip实例。以便它可以为它创建一个AnimancerState(如果尚不存在),然后在以后每次播放该动画时重新使用它。

初始化启动时创建所有或大多数animancer state会增加一些复杂性,并可以提高性能,但这只能通过增加更大的负载来实现。这在加载屏幕期间可能会很好,但是如果您在游戏过程中实例化一个角色,您已经为此付出了很高的性能成本,这意味着最好不要花更多的时间来预初始化所有其他内容。预先初始化animancer satte的主要方式有两种:

  • 在启动代码中(例如在MonobehaviourAwake或者Start方法中)调用animancer.States.GetOrCreate
  • 使用一个NamedAnimancerComponent类,并将有问题的剪辑分配到Animations检查器中的数组(或使用脚本)。这样子只会在Monobehaviour.Awake方法中简单地调用了一次GetOrCreate。
  • 如果您不再需要这个AnimancerState对象,则可以调用AnimancerState.Destroy将其删除。销毁和随后的垃圾收集也都需要管理性能成本。

性能基准”部分将进一步详细介绍Animancer的性能。