【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,查看該專題所有內容。

發佈了142 篇原創文章 · 獲贊 77 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章