2011-06-16 68 views
10

基本上我有一個控制遊戲角色攻擊的狀態機,其時間基於動畫長度。實現大型狀態機的最佳方式?

因此,例如:

我開始在默認狀態下,如果玩家擊中的攻擊按鈕,它開始攻擊,切換狀態並設置基於攻擊長度的計時器。然而,當我考慮可以取消的電荷攻擊時,狀態機會變得更加複雜,而攻擊可以根據它們的命中而移動到不同的狀態,並且每個狀態都有獨特的方式來處理被攻擊的角色。 目前我有大量的switch語句。我想過多態,但這需要爲每一個有很多狀態的國家開設一個新的課程(開始攻擊,攻擊和終結攻擊都需要單獨的狀態)。

switch語句有效,但它非常大,也不像基於繼承的系統那樣容易修改。

關於外觀美觀的任何建議?編輯: 這是使用java。

回答

8

對於較大的狀態機,您必須注意「過渡爆炸」現象。事實證明,傳統的有限狀態機不提供重用許多狀態的常用轉換的機制,因此最終會重複太多,並且狀態機會「爆炸」(這也違背了「不要重複自己」(Do-not-Repeat-Yourself, DRY)原則)。

因此,我建議使用分層狀態機和實現技術,以便將這些狀態機輕鬆映射到代碼中。有關分層狀態機的更多信息,請參閱維基百科文章http://en.wikipedia.org/wiki/UML_state_machine

2

考慮建立一個表驅動的狀態機。如果考慮狀態機的定義,基本上有一組具有區別的初始狀態,轉換函數和(在這種情況下)輸入和輸出字母表。

您可以構造一個由當前狀態和輸入索引的表,並使用指向函數的指針或函子類來表示發生了什麼。該函數應該返回下一個狀態。然後你就可以建立狀態機(僞):

state := initial state 
while(state != STOP) 
    state := (lookupTransition(inputs))() 

其中lookupTransition(inputs)簡單地找到下一個狀態。我在這裏假設轉換函數是沒有參數返回狀態的函數,所以lookupTransition(inputs)必須是你有很多輸入的函數,返回一個指向void arguments返回狀態函數的指針。

設置正確,你可以把所有的狀態機和行爲放到一個表中,這個表很容易被修改和重新編譯。

(對於額外的信用,找出如何,你可以從文件加載該表,所以你並不需要在所有重新編譯。)

更新

在Java中,使用類似一個函數類代替函數指針。

另一個更新

當然,另一種選擇是使用一個狀態機之類的編譯Ragel

+0

這是真正的問題不是它。只要你需要每個狀態/事件組合的新類,代碼就會變得非常冗長。我們必須等待關閉才能最終做到簡潔。目前,可以使用反射或代碼生成來減少代碼混亂,並有其自身的缺點。 – irreputable 2011-06-16 21:25:19

+0

你知道,說實話,我懷疑這裏有一個本質複雜的命令。關閉只能幫助一個或兩個過渡線;使用仿函數使得這種代碼類似於cookie-cutter,但複雜性並非完全不同。使用動態語言(如Ruby,Python或Groovy)可能會有所幫助,但主要是因爲它會使表格加載部分更加簡單。但最終,如果你有一個複雜的狀態機,你將不得不編寫代碼。 – 2011-06-17 02:16:45