學習後的一點小紀錄,希望留下些東西在腦子。
未來回來也能當作複習。
另外這篇範例是以 Godot 為主。
Finite State Machine 是什麼?
這裡首先就要從我們遇到的問題開始。
想像我們在製作一款平台跳躍遊戲,例如《瑪利歐》。
玩家操控的角色基本上的動作有移動( Run )和跳躍( Jump ),還有可能會被忽略的待機( Idle )。
示意圖
因為很簡單,我們就把程式碼都塞在 _physics_process( ) 裡面。
現在這樣看起來還不算太複雜。
接著團隊討論後,為了內容豐富一點想要加入在空中滑翔的動作。
在空中掉落速度會比較慢,而且不能馬上轉向。
滑翔途中按跳躍可以取消。
那再來看一下程式碼會變成怎麼樣。
可以看到內容變得更複雜了。
未來或許還想要增加衝刺、攀爬等動作的時候,
這樣正面硬上除了有閱讀上的困難,也容易漏掉東西造成 BUG。
設狀態 ( State ) 變數,裡面裝了 { ON_GROUND, IN_AIR, GLIDING }
方便我們追蹤角色的狀態,閱讀上會比較輕鬆。
State Pattern
目的是要把每個狀態分成單獨的物件。然後利用 state machine 追蹤角色現在的狀態,以及決定轉移到哪個狀態。
就像控制中心一樣。
因為每個狀態都變獨立物件了,
- 所以只讀取自己需要的變數,減少不小心動到其他狀態變數的機率。
- debug 的時候比較方便。
現在又回到上面的例子,這時候我們最主要需要兩樣東西。
- StateMachine :處理切換狀態的控制中心。
- State :狀態的範本
例子
在我們開始設計 State 前,可以先把可能的情況做分類。
例如:
Idle -> Run:從停止狀態開始移動
Run -> Air:從移動狀態離開地板到空中,例如跳躍或是落下
Air -> Run:落地時在移動
Air -> Idle:落地後什麼動作都沒有
接著就是實際運用的範例了。
State
可以看到 function 裡面都是空白沒內容,之後讓每個 State 覆蓋利用的。
像是填空題一樣,這個題目你希望現在的 State 怎麼動作。
StateMachine
簡單紀錄我可能忘的地方
yield( owner, "ready" ) 等到 StateMachine 底下的 child 都執行完 _ready( ) 後再繼續跑下去。 |
func _process( ) 和 _physics_process( ) 執行現在 State 的內容 |
state.exit( ) 離開現在的 State state = get_node(target_state_name) 設定新的 State state.enter(msg) 進入新的 State |
原文章裡有
Idle、
Run、
Air State的範例。
這裡簡單放了 Idle 的。
可以看到在 update( ) 裡面寫了判斷什麼時候用 transition_to( )。
- 角色不在地板上就轉到 Air State。
- 有按左右鍵移動就轉到 Run State。
因為拆成單個單個的 Script,
程式碼長度相較原版都放一起就能比較短,閱讀上可以比較輕鬆。
需要用 Godot 執行。