【Playable API】不用Animator如何播放动画?

你好,我是郑洪智,你可以叫我大智。

先问你一个问题:播放动画不想用Animator搞一堆Animator Controller,怎么做?

Unity老玩家可能会先想到:Legacy Animation组件。也就是原来那个贼简单的Animation组件,只要把Animation Clip拖上去就能播放的那个。

虽然现在Legacy Animation还能用,而且还有大把的童鞋在用,但并不是一个完美地答案。

你可能会问了:为什么呢?用着挺不错呀,而且也很顺手。

Legacy Animation对于程序来说是比较直观的,但这就意味着没办法(很麻烦)使用Mecanim动画系统的一些高级功能,例如:动画重定向、Blend Tree、Avatar Mask等功能。

那有没有既能用到新的Mecanim动画系统里的这些新功能,又不用搞那些Animator Controller呢?答案是有的。(小新:都是废话,没有的话这篇文章存在的意义是啥???)

下面就要请出这位神秘嘉宾:Playable。Playable是Unity中的一位隐士高人,可能很多同学对他都不了解。

Playable是一组API,可以用来组合、混合、修改多个数据源,然后通过一个输出,将这些数据源处理完的结果播放出来。

这么说,可能有些难懂。

下面回到最开始的那个问题,用Playable如何解决呢?接下来我们就用Playable API来实现一个Legacy Animation组件。

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;

// 需要同物体上有Animator组件,但是不需要给他赋值Animator Controller
[RequireComponent(typeof(Animator))]
public class PlayAnimationSample : MonoBehaviour
{
    public AnimationClip clip;
    PlayableGraph playableGraph;

    void Start()
    {
        // 创建一个PlayableGraph并给它命名
        playableGraph = PlayableGraph.Create("PlayAnimationSample");
        // 创建一个Output节点,类型是Animation,名字是Animation,目标对象是物体上的Animator组件
        var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", GetComponent<Animator>());
        // 创建一个动画剪辑Playable,将clip传入进去
        var clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);
        // 将playable连接到output
        playableOutput.SetSourcePlayable(clipPlayable);
        // 播放这个graph
        playableGraph.Play();
    }

    void OnDisable()
    {
        // 销毁所有的Playables和PlayableOutputs
        playableGraph.Destroy();
    }
}

上面的几行代码创建了一个PlayableGraph。运行时你可以在PlayableGraph Visualize(可以在Package Manager中安装,安装后在菜单栏Windows > Analysis > Playable Visualizer中打开)中看到它的图(注意左上角选择对应名称的图):

可以看到这里有两个节点:一个Animation clip节点和一个Animation Output节点。这里实现的功能很简单,就是播放一个动画。这是由一个Playable节点形成的一个非常简单的树形结构,每一个PlayableOutput都会形成一个树形结构。

上面的代码可以使用Playables API中的工具类进行简化:

using UnityEngine;
using UnityEngine.Playables;

[RequireComponent(typeof(Animator))]
public class PlayAnimationUtilitiesSample : MonoBehaviour
{
    public AnimationClip clip;
    PlayableGraph playableGraph;

    void Start()
    {
        // 使用AnimationPlayableUtilities中的方法简化代码
        AnimationPlayableUtilities.PlayClip(GetComponent<Animator>(), clip, out playableGraph);
    }

    void OnDisable()
    {
        // 销毁所有的Playables和PlayableOutputs
        playableGraph.Destroy();
    }
}

**为什么还需要一个Animator组件呢?**因为在底层,PlayableGraph的AnimationOutput依然是基于Animator组件的,不过你可以不用关心它了。

到这呢,咱们开始的问题已经解答完了。当然了,这是最简单的播放一个动画的代码,更复杂的适合你项目的代码当然需要你自己撸喽。

不过下面再稍微拓展一下。

用Playable有什么好处?

  • Playable结构简单
    Playable没有复杂交叠的状态机。如果只是播放动画,几行代码就够了,用起来就像旧的Animation组件一样。如果是复杂的动画,也可以预先创建好PlayableGraph子图,在需要时添加到主图中。

  • Playable可以运行时修改
    Animator状态机是没办法运行时修改的,而且只能使用OverrideController来替换动画,有时候不太方便。因为当动画数量非常多的时候,如果不能动态添加、删除State,那就需要预先制作一个巨大的状态机来满足所有状态,维护起来非常麻烦。但是Playable API允许你运行时修改动画的逻辑结构

  • Playable更加灵活,可以直接控制动画各种属性
    Animator中是通过变量来间接控制权重的,而Playable中,你可以直接控制动画的权重和时间。不过需要注意的是,虽然这样很灵活,但是大多数情况下没有Animator的变量控制方便。

  • Playable有强大的混合(blend)能力
    使用Playable不仅能在两个Animation Clip之间混合,还能在Clip和Animator Controller之间混合,甚至多个Animator Controller之间混合。在Animator中,两个State Machine之间是不能过渡的,但是使用Playable就可以。还可以同时使用状态机和Playable,固定的动画状态转换用状态机,需要动态变化的使用Playable。

PlayableGraph的基本结构

PlayableGraph主要由两部分组成:各种Playables和PlayableOutput。这些元素组成的那个抽象的图就叫PlayableGraph。

Playables是基本组成元素。Playable Output是每个Graph必须的组成元素,至少需要一个。而且Playable Output必须连接至少一个Playable,否则是没有任何作用的。

常见的Playable类型

Playable Output类型

为了避免GC,所有类型都是使用struct实现的。

构建PlayableGraph一般有如下的流程:

  1. 创建一个PlayableGraph,方法是PlayableGraph.Create("graph的名字")
  2. 创建输出节点,常用的有
    • AnimationPlayableOutput.Create(playableGraph, "name", GetComponent<Animator>());
    • AudioPlayableOutput.Create(playableGraph, "name", GetComponent<AudioSource>());
    • 还可以创建自定义的输出节点
  3. 创建各种playables。所有的Playable都有一个静态的Create()方法,用来创建playable实例。需要注意的是自定义的PlayableBehaviour需要使用ScriptPlayable<T>.Create(playableGraph);来创建。
    • AnimationClipPlayable.Create(playableGraph, animationClip);
    • AudioClipPlayable.Create(playableGraph, audioClip, true);
    • ScriptPlayable<T>.Create(playableGraph);
  4. 连接playable和output:PlayableOutput.SetSourcePlayable()
  5. playable之间的连接:PlayableGraph.Connect()
  6. 播放graph:PlayableGraph.Play()
  7. 如果graph不再使用,记得销毁:PlayableGraph.Destroy()。调用这个方法后会销毁所有的playbles和output。

好了,到这说的差不多了,再多的内容可以等我后续的更新。着急的话可以在Unity文档或者官方blogs中搜索Playable

在使用Timeline时,如果想要扩展Timeline,需要大量用到Payable API。如果你对Timeline和Playable感兴趣,可以到洪流学堂公众号中回复timeline,查看该专题所有内容。

发布了138 篇原创文章 · 获赞 72 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/zhenghongzhi6/article/details/103581242