2016年7月24日 星期日

等等!我改變主意了! 如何在狀態機轉換過程時中斷

作者:CATHERINE PROULX 原文

最近解決了一個開發者回報的棘手Bug,這個Bug牽扯到空狀態(empty states)、覆蓋層(override layers)和轉換中斷(transition interruptions)。當我
進一步深入研究這個Bug的時候,我發現動畫系統文件中關於轉換中斷的描述太抽象了。經過內部討論後,我們決定發文說明一下。

下面我們來深入研究一下狀態機的轉換和中斷的細節。

預設情況下動畫系統裡的轉換是不能被中斷的,一旦開始由一個狀態轉換為另一個狀態,這個過程沒有出口。就像一個乘坐飛越大西洋航班的乘客,只能舒適的靠在座位上直到抵達目的地。一般來說對開發者是好事。

但是如果要對轉換過程有更多控制,Mecanim系統有幾種不同配置方式來滿足需求。如果對當下目的地不滿意,可以跳到駕駛員的角度在中途改變飛行計畫。這代表可以更靈敏的控制動畫,但同時也可能讓配置變得太複雜。

透過下面幾個例子來說明一下。首先是一個包含4個狀態
簡單的狀態機,名字為A到D,並且都指定轉換狀態連上狀態機。


預設情況下,當觸發了A->B的轉換後,狀態機將會從A轉換為B,中間無法阻止它變為狀態B。但是如果打開A->B轉換的檢視屬性,並將Interruption Source(中斷來源)從“None”變為“Current State”後,從A到B的這個過程就可以被狀態A的某些觸發器(triggers)中斷了。


為什麼是“某些”觸發器呢?因為“Ordered Interruption(順序中斷)”預設是勾選的。這代表在狀態A的轉換過程中,只有比當下轉換優先順序更高的轉換能夠被執行。查看狀態A的檢視介面可以看到只有 A->C這個轉換的優先順序比A->B高。


因此如果觸發了A->B,馬上又觸發了A->D,那麼轉換過程不會被中斷。但如果是A->C,A->B的轉換會被馬上中斷並且狀態機轉換至狀態C。

在系統內部,動畫系統記錄了中斷發生時的動畫狀態,並且將播到一半的靜態姿勢(X)和新的目標動畫進行漸變融合。


為什麼是靜態姿勢,而不是從A到C進行流暢的融合?簡單來說是為了效能。當遊戲必須要快速判斷中斷條件或是同時追蹤幾個不同的動態轉換時,將使得動畫系統不好擴展,因為每增加一個新狀態都會消耗更多的系統資源。

現在,如果取消勾選“Ordered Interruption(順序中斷)”,那麼A->C和A->D都可以中斷A->B的轉換。但如果它們在同一幀觸發,那麼A->C仍然會優先執行,因為A->C的優先順序更高。

如果將Interruption Source改為“Next State”,A->C和A->D將不再中斷轉換,不論它們的順序如何。但是如果觸發了B->D,則會馬上開始A到D的轉換,並不會完成到B的轉換。

轉換順序對於狀態B來說也很重要。“Ordered Interruption”的勾選已經不能用了,任何從狀態B觸發的轉換都可以中斷A->B的轉換,因為它們都沒有相對於A->B的優先順序排序,但狀態B的轉換順序會決定在同一幀都被觸發的情況下最終將轉換到哪個狀態。在這個例子中,如果B->D 和 B->C在同一幀觸發了, 則B->D會被選中。


最後,想要完全控制,可以將中斷來源設為“Current State Then Next State(先當下狀態再下一狀態)”或者“Next State Then Current State(先下一狀態再當下狀態)”。在這種情況下,轉換會先在一個狀態下獨立分析,然後再到另一個狀態。

所以,如果使用如下配置:


在狀態A到B的轉換過程中,有個玩家在同一幀觸發了4次轉換:A->C,A->D,B->C,B->D。結果如何呢?

首先,勾選了“Ordered Interruption”,所以可以直接忽視A->D,因為它的優先順序不如A->B高。當下狀態會最先處理,所以不用看A->B了,這裡進行的是A->C的轉換。




但是,相同配置條件下,如果只觸發了B->C和B->D,那就會進行B->D的轉換(它比B->C的優先順序高)。

現在還只是一個轉換,所有其他的轉換也是可能以其特定的規則被中斷的。所以如果讓A->C的轉換從下一個狀態中斷,那可能A->B的轉換會被A->C中斷,而反過來A->C的轉換也可能會被C->D中斷。

有一點很重要,不管中斷在何處發生,原狀態會保持不變直至轉換結束,而Animator.GetCurrentAnimatorStateInfo()將始終返回起始狀態。

簡而言之,狀態轉換的中斷設置非常強大,也提供了極高的靈活性,但也會讓人非常迷惑。所以要明智的使用狀態轉換中斷,有問題一定要先在編輯器中測試。

沒有留言:

張貼留言

著作人