Unity動畫系統詳解3:如何播放、切換動畫?

摘要:【長文預警,建議先收藏】有了模型和多個動畫以後,在Unity中如何控制它們的播放和切換呢?本文帶你一站式解析Unity的Animator模塊。

洪流學堂,讓你快人幾步。你好,我是跟着大智學Unity的萌新,我叫小新,這幾週一起來複(yu)習(xi)動畫系統。

大智:“小新,還記得Unity的動畫來源有哪些麼?”

小新:“有Unity中製作和外部導入兩種,哦對!還可以用代碼寫動畫,不過我不會,嘿嘿”

大智:“沒錯,前兩天我們學習的其實主要是Animation Clip的內容,也就是一個物體對應的一段動畫,是整個動畫系統的基本元素。今天我們要着重學習一下Animator。如果把Animation Clip比作是一段視頻的話,那麼Animator就是一個視頻播放器,用來控制多段視頻的播放、切換等等。”

Animator組件

想要在一個物體上播放動畫,需要在這個物體上添加Animator組件。

Animator中有一個很重要的屬性是Controller,這個屬性引用了一種叫Animator Controller的資源,這種資源以文件的形式存儲在工程中,文件內存儲了動畫的各種狀態以及狀態之間的切換規則。本文後半部分會細講。

Avatar 設置使用的骨骼節點映射。

Apply Root Motion 應用根節點運動。如果不啓用,動畫播放時根節點會保持在原地,需要通過腳本控制物體的移動。如果啓用,如果動畫中有運動,動畫中的運動會換算到根節點中,根節點會發生運動。(通常用於人物/動物的運動動畫)

Update Mode 設置Animator更新的時機以及timescale的設置。

  • Normal Animator按正常的方式更新(隨着Update調用更新,timescale減小時,動畫播放也會減慢,timescale的具體含義和用法後續會詳解)
  • Animate Physics Animator會按照物理系統的頻率更新(根據FixedUpdate調用更新,後續會詳解),適用於物理交互,例如角色加上了物理屬性可以推動周圍的其他物體。
  • Unscaled Time 根據Update調用更新,無視timescale。一般用於UI界面,當你使用timescale暫停遊戲時,界面保持正常動畫。

Culling Mode 裁剪模式

  • Always Animate 動畫一直運行,即使物體在屏幕外被裁剪掉並沒有渲染
  • Cull Update Transforms 當物體不可見時,禁用Retarget、IK、Transforms的更新(後續動畫進階模塊會細講)
  • Cull Completely 當物體不可見時,完全禁用動畫

Animator Controller

Animator Controller是Animator組件必須的資源,這種資源以文件的形式存儲在工程中,文件內存儲了動畫的各種狀態以及狀態之間的切換規則。

上圖中有兩個Animator Controller文件

通常一個物體上有不止一段動畫,使用Animator Controller可以很容易地管理各段動畫以及動畫之間的切換。比如角色身上有走、跑、跳、蹲的動畫,使用Animator Controller可以很容易管理它們。不過,即使只有一段動畫,仍然需要給動畫物體添加Animator組件才能播放動畫。

大智之前講過可以使用PlayableAPI繞過Animator Controller來播放動畫,感興趣的話可以去看一下

Animator Controller中使用了一種叫State Machine(狀態機)的技術來管理狀態以及狀態之間的切換。

StateMachine 狀態機

狀態機由State(狀態)和Transition(轉換)組成。State代表一個狀態,在Animator Controller中一個State可以包含一段動畫、一個子狀態機或一個混合樹(後面會細講)。Transition用來設置狀態之間的切換條件,一般會有一個或多個條件,用於從一個狀態切換到另一個狀態。

在Animator窗口中,可以可視化看到State以及Transition。

創建Animator Controller

創建Animator Controller資源有如下幾種方式:

  • 在Unity中創建Animation Clip時,如果選中的GameObject上沒有Animator組件,會自動添加Animator組件並在工程中創建一個Animator Controller文件(和Animation Clip文件同目錄)。
  • 將任意Animation Clip拖到一個物體上時,如果拖到的物體上沒有Animator組件,會自動添加Animator組件並在工程中創建一個Animator Controller文件(和Animation Clip文件同目錄)。
  • 可以在Project窗口中手動創建Animator Controller文件,如下圖所示:

創建Animator Controller文件

編輯Animator Controller

雙擊Animator Controller文件,可以打開Animator窗口,編輯該文件。

今天我們先簡單學習一下如何將導入的動畫播放出來,後續的動畫進階模塊會更詳細講解Animator Controller中的高級功能。

在Project窗口中直接創建Animator Controller時,其中是不包含任何動畫的。如下圖所示:

圖中包含三個節點:

Entry 入口。動畫狀態機會從這個節點開始,根據Transition進入一個默認State。

Any State 任意狀態。用於從任意狀態轉換到特定狀態。比如射擊類遊戲中,如果被子彈打中後,不管當前處於什麼狀態,都會倒地死亡。

Exit 退出狀態機。一般用於嵌套的狀態機的退出(後面動畫進階模塊會講)。

添加狀態

可以在空白處右鍵添加Empty State,也可以將Animation Clip文件拖到Animator窗口中添加一個State。

如果當前在Project窗口選中了一個Animation Clip,也可以通過上圖的From Selected Clip創建一個State,不過還是直接將Clip拖到Animator中創建State更簡單,如下圖所示。

拖拽添加State.gif

第一個創建的State默認是橘黃色的,代表是默認狀態。有一條黃色的箭頭從Entry指向橘黃色的State。Animator組件會在一開始播放New State,如果New State中有動畫,也會播放對應的動畫。

這時候如果你Play這個場景的話,設個物體就會播放默認State的動畫。

State設置

每個State可以包含一段Animation Clip,處於該State時Animator組件所在的物體會播放該動畫。選中一個State時,在Inspector中可以看到如下內容:

Motion 可以設置一個Animation Clip,如果是從Animation Clip創建的動畫,這裏應該已經有動畫了,你也可以從工程中選擇動畫。

Speed 動畫的播放速度

Multiplier 乘數,可以使用一個參數來控制動畫的播放速度,動畫最終的播放速度會是Speed * Multiplier。後面會講解Animator的參數以及如何在代碼中控制參數。

Normalized Time 單位化時間,範圍是0-1,需要使用參數控制。

Mirror 鏡像動畫。也可以使用一個參數控制。

Cycle Offset 循環偏移量。可以用來同步循環的動畫。偏移量使用的是單位化時間,範圍是0-1。也可以使用參數來控制。

Foot IK 只用於人形動畫。角色的腳是否使用反向動力學。

Write Defaults 是否初始化該State沒有用到的參數爲默認值。

Transitions 該狀態參與的狀態轉換。下面會細講。

Parameters 參數

上面我們提到了參數的概念,那麼參數是什麼呢?

Animator Controller中的參數可以作爲控制transition切換的條件,也可以控制上面可以參數化的屬性比如State中的幾個屬性。

State中可以用參數做屬性值的來源

Animator Controller的參數可以通過代碼進行控制,進而控制整個Animator狀態機的運轉。

參數共有4種類型:

  • Int 整數類型
  • Float 浮點數(小數)類型
  • Bool true或false(真或者假,用於邏輯判斷),界面上顯示爲複選框
  • Trigger 觸發器,與Bool有點類似,但是transition在使用這個參數後會被自動設置爲false狀態。界面上顯示爲一個圓形按鈕。

Transition

Transition代表狀態之間的切換條件,一般會有一個或多個條件,用於從一個狀態切換到另一個狀態。

添加Transition

在一個State上右鍵,在彈出菜單中選擇Make Transition,可以創建一個到其他State的Transition。

增加Transition

點擊代表Transition的箭頭,可以在Inspector上看到這條Transition的具體情況。選中Transition的源State(從哪個State出發),也可以在State的Inspector中看到這條Transition的具體信息。

Transitions 顯示當前選中的Transition。後面有兩個複選框包括Solo和Mute。

  • Solo 如果兩個State之間有多條Transition,勾選這個選項後,只有選中Solo的Transition生效。其他Transition會被禁用。

比如Transition1設置爲Solo,則從源State到目的State的3個Transition中只有1會生效

  • Mute 勾選這個選項後,該條Transition會被禁用。如果同時選中了Solo和Mute,Mute會優先生效。

Name Field 名稱框。如上圖所示,可以給Transition命名,用於區分兩個State之間的多個Transition時非常有用。

Has Exit Time 是否有退出時間條件。退出時間是一種特殊的transition條件,它沒有依賴參數(下面會講),而是根據設置的退出時間點作爲條件進行狀態轉換。

Settings transition的一些參數設置。

  • Exit Time 如果勾選了Has Exit Time,該參數是可以設置的,設置動畫退出的單位化時間。例如設置爲0.75,代表動畫播放到75%時爲true,如果沒有其他條件,會直接切換到下一個State。

    如果exit time小於1,那麼state每次循環到對應位置的時候(不管動畫是否設置爲循環,state總是循環的),該條件都會爲true。比如第一次播放到75%,第二次播放到75%……時退出條件都會爲true。

    如果exit time大於1,該條件只會檢測一次。比如exit time爲3.5,state的動畫會在循環3次後,在播放到第4次的50%時爲true。

  • Fixed Duration 勾選時,下方Transition Duration參數的單位是秒,不勾選時,參數會作爲一個百分比。

  • Transition Duration transition的過渡時間。兩個狀態在轉換時,一般不會瞬間從一個狀態轉換到另一個狀態,而是會經過平滑混合,這個屬性就是設置了平滑混合的時間。可以從下圖的兩個藍色箭頭看出轉換的時間。

  • Transition Offset 目標狀態開始播放的時間偏移。比如設置爲0.5,則轉換到下一個State時,會從50%的位置開始播放。

如圖設置爲0.5時,下一個State會從50%開始轉換

  • Interruption SourceOrdered Interruption 這兩個參數可以用來控制transition的打斷。下面會進行詳解。

Transition圖

上面的參數不僅可以手動修改數值,也可以通過Transition圖預覽、修改。

Conditions 條件

一個Transition可以有一個條件,也可以有多個條件,甚至沒有條件。

如果Conditions中沒有條件,但是勾選了Has exit time,那麼exit time會被作爲state退出的條件,到達exit time時,會切換到下一個state。

如果有一個或多個條件,需要同時滿足這些條件才能切換下一個state。

一個條件可以是:

  • 相等/不相等判斷,一個參數等於/不等於一個常量時爲true(int,float,bool類型參數)
  • 比較判斷,一個參數與一個常量的比較結果(int,float類型參數)
  • 觸發器,觸發器激活時爲true

如果Has Exit Time勾選了,並且transition還有一個或多個條件,那麼transition需要同時滿足到達exit time同時條件全爲true,纔會切換到下一個state。

一個transition至少要有一個條件(Has Exit Time可以作爲一個條件),否則transition會被忽略。

【選讀】Transition Interruption

之前我們提到了Interruption SourceOrdered Interruption 這兩個參數可以用來控制transition的打斷。那麼究竟什麼是transition打斷呢?

一般情況下,動畫系統的transition是不能打斷的:一旦transition開始從一個state切換到另一個state,沒有打斷的方法。就像乘坐跨大西洋航班的乘客一樣,你舒適地坐在座位上,直到到達目的地,無法改變主意。對於大多數用戶來說,這很好。

但是如果你需要對transition進行更多控制,可以通過多種方式配置動畫系統來滿足需求。如果你對目前的目的地不滿意,你可以跳進飛行員的座位,在飛行途中改變計劃。這能帶來更靈活的動畫控制,但也很有可能迷失在複雜的打斷中。

我們通過幾個例子來深入探索一下打斷。從一個相當簡單的狀態機開始,這個狀態機具有四個狀態,標記爲A到D,並且使用trigger作爲每個transition的條件。

默認情況下,當A到B的切換觸發後,狀態機開始切換到B,在切換到B之前無法被改變。但是,如果將A->B的transition的interruption source屬性從None切換到Current State,A到B的切換就可以被A上的一些觸發器中斷。

爲什麼只有一些呢?因爲Ordered Interruption屬性默認也會被勾選。這意味着只有優先級大於當前的transition才能打斷。選中State A,在Inspector中查看,我們看到A -> C的優先級高於 A -> B,那也意味着只有A -> C能打斷A -> B的轉換。

如果我們激活A->B的trigger,然後立馬激活A->D的trigger,A到B的transition不會被打斷。但是,如果我們激活A->B的trigger,然後立馬激活A->C的trigger,A到B的transition會被打斷,轉而切換到C。

在動畫系統內部,會記錄下被打斷時的動畫的狀態,然後從打斷的狀態混合到新的目標動畫。

如果不勾選Ordered Interruption屬性,會發生什麼情況呢?A->C 和 A->D 都能打斷 A -> B 的transition了。但是,如果在同一幀激活了A->C和A->D的trigger,A->C仍然會優先激活因爲A->C的優先級更高。

如果將A -> B的interruption source屬性改爲Next State,也就是下一個狀態。A->C 和 A->D就不能打斷A -> B了。如果我們激活A->B的trigger,然後立馬激活B->D的trigger,A到B的transition會被打斷,轉而切換到D。

B上的Transition的順序也有影響。但是這時候Ordered Interruption屬性就無法勾選了(因爲A -> B是在State A上不在State B上,不參與B的排序)。B上transition的順序會決定同時觸發時,會使用哪一個transition。例如下圖的排序,如果B->D 和B->C在同一幀被觸發,B->D的transition會被執行。

如果想完整控制,我們可以設置interruption source屬性爲Current State Then Next State或Next State Then Current State。設置爲這兩個值時,State A和State B上的transition都會被考慮在內。例如設置如下,選中了Current State Then Next State:

如果A到B切換時,同時激活的A->C, A->D, B->C和B->D,會發生什麼情況?

如果選中了Ordered Interruption,那麼首先可以忽略A->D(因爲比A->B)的優先級低。然後先考慮Current State A,那麼A->C會勝出,甚至不用考慮Next State B了。

如果同樣的配置,只激活了B->C 和 B->D,那麼B->D會勝出,因爲B->D的優先級比B->C更高。

小結

上面我們只使用了A->B一種情況作爲例子進行了講解,其他的中斷都是類似的,只需要根據他們自身的規則即可。

有一點很重要需要記住的是:不管打斷髮生了幾次,只要transition沒有完成,source state會一直不會變。比如A->B被B->C打斷,又被C->D打斷,transition未完成前source state會一直是A。Animator.GetCurrentAnimatorStateInfo()也會返回State A。

簡而言之,transition中斷功能很強大,並提供了很大的靈活性,但會變得非常混亂。因此,合理地使用transition中斷,而且一定要在編輯器中多進行測試。

總結

今天講了Animator組件,希望你能記住一下幾點:

  • 如果把Animation Clip比作是一段視頻的話,那麼Animator就是一個視頻播放器,用來控制多段視頻的播放、切換等等。
  • Animator Controller就是一個劇本,用來指導視頻播放器如何播放多段視頻。

今日思考題

大智:“導入Standard Assets中的Character包,看看裏面的Animator Controller是如何設置的。”
小新:“好嘞~”
大智:“收穫別忘了分享出來!別忘了點擊右下角請好友看免費分享給你的朋友,也許能夠幫到他。”

擴展閱讀

【擴展學習】洪流學堂公衆號回覆動畫可以閱讀本系列所有文章,更有視頻教程等着你!


呼~ 今天小新絮絮叨叨的真是夠夠的了。沒講清楚的地方歡迎評論,咱們一起探索。

我是大智(微信:zhz11235),你的技術探路者,下次見!

別走!點贊收藏哦!

好,你可以走了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章