你好,我是郑洪智,你可以叫我大智。
先问你一个问题:播放动画不想用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,否则是没有任何作用的。
为了避免GC,所有类型都是使用struct实现的。
构建PlayableGraph一般有如下的流程:
- 创建一个PlayableGraph,方法是
PlayableGraph.Create("graph的名字")
- 创建输出节点,常用的有
AnimationPlayableOutput.Create(playableGraph, "name", GetComponent<Animator>());
AudioPlayableOutput.Create(playableGraph, "name", GetComponent<AudioSource>());
- 还可以创建自定义的输出节点
- 创建各种playables。所有的Playable都有一个静态的
Create()
方法,用来创建playable实例。需要注意的是自定义的PlayableBehaviour需要使用ScriptPlayable<T>.Create(playableGraph);
来创建。AnimationClipPlayable.Create(playableGraph, animationClip);
AudioClipPlayable.Create(playableGraph, audioClip, true);
ScriptPlayable<T>.Create(playableGraph);
- 连接playable和output:
PlayableOutput.SetSourcePlayable()
- playable之间的连接:
PlayableGraph.Connect()
。 - 播放graph:
PlayableGraph.Play()
- 如果graph不再使用,记得销毁:
PlayableGraph.Destroy()
。调用这个方法后会销毁所有的playbles和output。
好了,到这说的差不多了,再多的内容可以等我后续的更新。着急的话可以在Unity文档或者官方blogs中搜索Playable
。
在使用Timeline时,如果想要扩展Timeline,需要大量用到Payable API。如果你对Timeline和Playable感兴趣,可以到洪流学堂公众号中回复timeline
,查看该专题所有内容。