上回說到,遊戲項目中客觀會遇到邏輯狀態的複雜性和動畫狀態的單一性之間的矛盾,那麼Animation Tree是如何解決這個問題的呢?
這又需要引入一個定律:就是邏輯狀態無論有多麼複雜,但一套邏輯狀態組合一定唯一對應一個具體的動畫。
舉例來說:已知控制當前遊戲對象的邏輯狀態有是否技能中、是否受擊、是否中毒、是否眩暈。
那麼我們可以建立一個下面的關係:
技能中 | 否 | 是 | 否 | 否 | 否 | 否 | 是 |
受擊 | 否 | 否 | 是 | 否 | 否 | 否 | 是 |
中毒 | 否 | 否 | 否 | 是 | 否 | 是 | 是 |
眩暈 | 否 | 否 | 否 | 否 | 是 | 是 | 否 |
最終動作 | 默認站立待機動作 | 當前技能動作 | 當前受擊動作 | 中毒待機動作 | 眩暈動作 |
眩暈動作 (設眩暈動畫優先級高於中毒) |
技能動作 (設技能動作優先級高於受擊) |
給定每個邏輯的輸入,最終的動畫結果基本一定是唯一的。
這就是Animation Tree的原理。把整個角色動畫,依照不同的邏輯單元組合,最終在給定既定的邏輯取值的情況下,能得到唯一的動畫結果。無論是使用什麼具體的方案,萬變不離其宗。
這中間有幾個需要注意的問題:
1、優先級,這個優先級一般與邏輯無關,只是動畫本身的優先級,例如上表中的倒數第二列,中毒和眩暈全都觸發時,一般眩暈的優先級會高於中毒的優先級。再如最後一列,當中毒和技能同時觸發時,技能有限級一般會高於中毒優先級。這就意味着眩暈和技能條件的判斷要早於中毒的判斷,並享有對整個樹的優先處理權,眩暈條件一旦達成,其之後的中毒條件甚至根本就不用去判斷了。
2、融合,角色當前屬於眩暈動畫狀態,眩暈解除後,一般不會直接跳轉到接下來的狀態,而是需要走一個動作融合,這時需要注意接下來到底要轉到哪個狀態的問題。表面上看,人們不可能知道一個狀態解除後接下來會轉向什麼狀態,但實際上在既定的項目中,這一點是可以做到的。
3、邏輯狀態本身的互斥性,例如,上表中,不太可能出現眩暈和技能同時存在的情況,因爲眩暈的目的旨在剝奪玩家的行爲控制能力。在製作具體的Animation Tree時可以靈活根據這些條件進行一些優化和優先級的合理排布。
Animation Tree,目前接觸過UE3的Animation Tree思路和CE3的Animation Graph思路。這兩個思路是分別從兩個不同的出發點入手解決同一個問題。
UEAT的出發點是:邏輯狀態無論有多麼複雜,但一套邏輯狀態組合一定唯一對應一個具體的動畫,也就是說,無論AT有多麼複雜,最終的結果一定是單一的。這種具有單一結果的情況,一般人們應該都會選擇樹來做爲數據結構。所以,UEAT看起來像下面這個樣子(圖片來自UDK官網):
4中,被一堆綠色節點包圍的那個節點,就是UEAT的根,所有的條件依照這個根以樹狀排布。
AG不是特別熟悉,這裏只是根據筆者現在的經驗來寫,可能會有疏漏,望懂CE的大牛補充。
CEAG的出發點與UEAT不同:邏輯狀態無論有多麼複雜,但一套邏輯狀態組合一定唯一對應一個具體的動畫,所以CE把重點放在了這些狀態組合上,AG的編輯界面裏排布着大量的關聯節點,每個節點的進入條件就是狀態的各種組合,從一個節點跳轉到另一個節點,如果有路徑,就順路徑混合,否則直接按照節點混合直接跳到目標節點(圖片來自CE官網):
上圖是節點間的轉移路徑,下圖是某個單一節點的條件,一個是Action條件,一個是當前角色速度的條件。
個人推薦使用UEAT的方案,圖表一旦大起來的時候,樹狀邏輯組織的可讀性顯然高於圖狀邏輯組織,而CEAG更糟糕的是將節點間的不同性隱藏在了節點內部的屬性上,不把節點全部點開一次你是不可能明白這張圖到底想幹嘛的,而UE則直接從樹根追溯到葉子就知道這張圖是怎麼回事了。但是UEAT的缺點是任意兩個動畫葉子之間的Blend並不是特別好設置,因爲葉子間的切換,需要首先追溯到兩個葉子的共同樹枝,然後根據這個共同樹枝來進行混合,如果有下面這種情況,就很難對付了。
順便做個廣告,Surface Pro的1024級壓感電磁筆爽死了,誰用誰知道。
如圖所述,1到3、1到4的公共根是Blend節點,節點Blend時間0.1s,所以如果要這兩個路徑的Blend區分,這裏的處理就需要麻煩點。AG處理這個只需要走兩條不同的Blend路徑就可以。
但是筆者仍然推薦AT,道理很簡單,可讀性太重要了,而且Blend這種看起來對就是對的的坑爹玩意兒,一般不會有人揪着0.1和0.3不放的,真需要葉子間那麼精確到0.1和0.3的可能性不是很大,即便有了,也可以通過回調或者自定義等手段避免掉。但是,學AT的時候,半個小時就明白這玩意兒是怎麼回事了,學AG的時候,把整個例子的所有節點走一遍就是一上午,還沒來得及排布各個條件的優先關係。AG這種思路太過於直接地考慮程序的實現性了,而忽視了整個體系的方便性,感覺像給自己用的東西,不像給人用的東西。
邏輯狀態中最重要的關係就是優先級關係,各個不同體系的邏輯條件,其優先級基本直接決定了最後的結果,所以,像UEAT這樣的組織方式,最直接地表述了這樣的關係,必然產生的結果就是優良的可讀性和可控性。
關於AT的組織和概念就基本上差不多這樣了。
基於AT的基本原理,用戶可以定製各種輔助的條件和Blend模式來達成自己的目的:
例如速度。
可以把當前角色的相對朝向速度作爲條件導給AT,如果速度是正前方的,則角色播放正前方跑步動畫,如果是正後方的,則播放後退動畫,如果是左右的,則播放向左跑向右跑動畫(不是直接轉朝向)。如果有前有左呢?在當前節點混合吧!這樣就很容易地處理了方向移動的混合問題。與此相同,游泳、飛行這種可能帶方向的需求都可以這麼做。還可以根據速度的大小,進行走和跑的切換。
例如頭部一直向着某目標(Look IK)。
可以把角色的Look IK做成專門的節點,並製作一個專門的處理頭部與身體混合的節點,這樣,下半身該什麼操作還什麼操作,跟頭部合理融合就行了。
上下半身融合可以採取同樣的機制來處理。
在AG裏,這麼做可就痛苦了,因爲AG是既定輸入得到既定的唯一結果,而得到兩個結果,並使這兩個結果之間能夠混合……稍微會有點麻煩。
諸如此類的橋段還可以想出很多,再舉一個特殊的:
技能動作成百上千,難道全都要放在AT裏面去連嗎?
不可能,那樣的話整個圖會變成什麼樣子呢?設想一下幾千個節點,各種連線,這已經超越蜘蛛網,甚至超越亂麻,達到神經網絡的層次了。
技能動作再多,其優先級相對卻是很簡單的,大部分技能優先級一般都高於走跑跳,小於擊倒、擊飛、眩暈什麼的。擴展一個節點,這個節點的動畫並不是直接填寫在節點裏的,而是可以從技能系統中取得當前的技能動畫就可以了。上下半身分離技能什麼的,可以採用類似的機制來做。
總而言之,AT是個非常強大的概念,使用這套系統基本上就可以做到把程序從繁重而且毫無意義的動作狀態機編制過程中解放出來了。而且,您難道不覺得“這玩意兒本來就該這樣”嗎?邏輯和表現分離,就正如M和V分離一樣天經地義,有時候反而搞不明白爲什麼動作狀態表這樣的奇葩思路在中國居然還這麼流行。
儘早集成,儘早使用,您一定會體會到它彪悍之處的。
希望下個項目的時候,筆者不會再遇到長1000行寬1000行的動作狀態表這樣的坑爹玩意兒了……
(完)