[開發日誌 #1] 狀態機奮鬥記
時光荏苒,參與新專案到現在也超過半年了。因為是第一次做動作遊戲,面對沒開發過的機制,看了許多資料,也踩了不少的坑,就覺得應該來寫個開發日誌,多少記錄一下開發過程的酸甜苦辣鹹。開張第一篇先來分享開發狀態機時的碰壁。
成功的經驗很棒,但失敗的經驗也值得參考啊
在新專案之前,沒想到都沒有開發過狀態機,就算有需要狀態的地方,也因為是線性流程,所以不需要用狀態機。但在動作遊戲中,狀態機是遊戲的核心,角色要狀態機,關卡流程也要狀態機,然後狀態機裡面也可能要有自己的狀態機。
狀態(轉換)機
雖然知道通常會在狀態機中執行角色的行為,但是一開始功能單純,就設計成讓狀態機專責處理狀態轉換的判斷,而狀態的執行還是在角色中:
角色會提供角色狀態(status)給狀態機判斷,狀態機中對每個狀態(state)提供不同的判斷函式,在角色中則是提供不同的執行函式。當狀態機判斷要切換狀態後,會通知角色也切換執行函式,角色執行函式就會更新角色狀態。
但當狀態開始變多與功能變複雜時,這樣的設計出現了兩個問題。第一個問題是因為狀態(state)要用到的狀態(status)都是由角色提供與更新,所以就算那個變數只是為了給某個狀態使用(像是控制一個狀態執行多久的計時器),也要宣告在角色上,造成那個變數有機會被其它狀態更新到:
另外這些類變數一多起來,管理上也不方便。
第二個問題是如果狀態中要額外做其它事會變得相當麻煩。由於判斷都是交由狀態機執行,所以狀態機判斷要做額外的事情時(像是在攻擊狀態中被打時,不轉換成硬直狀態,而是只改變一點位移),得要另外傳資料出來,因為原本狀態機回傳的資料是告知狀態轉換的資訊:
再者,用來傳遞額外資訊的物件,可能會因為每個狀態需要做不同的額外事情,而讓變數越來越多,出現與第一個問題同樣的情況。
繞了遠路
為了解決這個有問題的狀態機,就開始想:
- 為什麼不讓狀態判斷函式變成類別,讓它自己管理需要的變數就好?
- 為什麼不讓狀態執行函式自己判斷需要額外做的事情就好?
然後就想到:為什麼不直接把狀態自己的判斷跟執行函式都放在同一個類別就好?
唉呀,繞了一圈,結果還是做最典型的狀態機就好了啊: