げぇむぷろぐらみんぐ

日々の生活で得た知識、経験を書きます

【Unity】ゲーム開発におけるStateMachineの有用性

はじめに

最近ゲーム開発での状態管理にStateMachineを用いているのですが、何をしているかがわかりやすくなり変更にも強くて良いと感じているので紹介します。

FiniteStateMachine

FiniteStateMachineは日本語でいうと有限オートマトンです。情報系の大学で学んでいた人なら一度は聞いたことがあるかと思います。 Wikipediaから説明を引用すると、

有限オートマトンまたは有限状態機械とは、有限個の状態と遷移と動作の組み合わせからなる数学的に抽象化された「ふるまいのモデル」である。

となります。

しっかりとした定義は僕もまだ理解できていませんが、状態と遷移を記述するためのものと理解すれば良いと思います。

FiniteStateMachineでは、状態と遷移を以下のような状態遷移図で表します。

f:id:siguma_sig:20180716175425p:plain

四角で表されるものが起こりうる状態で、矢印が遷移の条件となります。 図で言えば、状態がIdle、Jump、SecondJumpの3つあり、遷移の条件がFlickUp、Groundとなります。

利点

バグが出にくくなる

各状態において取りうる遷移のみを受け付けることになるので、意図しない動作が起こりづらくなります。

先程の遷移図で具体的に説明します。 図のとおり、初期状態としてIdle状態から始まり、1回目の上フリックによってジャンプをします。 そのとき、地面に着地をする前にもう一度上フリックをすることにより2段ジャンプのStateへと遷移します。

通常の実装ではジャンプ中にジャンプを許可するなどとしてしまうと意図せずに3段ジャンプができてしまったりする可能性がありますが、StateMachineを用いた実装ではSecondJump中にFlickUpを受け付けないようになっているので、3段ジャンプができないことが保証されます。 このように、StateMachineにない意図しない動作が起こらなくなるので必然とバグの発生を防ぐことができます。

また、StateMachineを用いた実装をするにあたって遷移図を書くことになるのですが、こうすることで仕様の抜けや考慮漏れが発生しづらくなります。

仕様の変更に強い

仕様変更の際には、StateMachineを変更するようにすれば良いので変更箇所がわかりやすくなり、仕様変更に強くなります。

こちらも先程の状態遷移図で説明します。 例えば、2段ジャンプの仕様がなくなったとき通常の実装だとコード全体から2段ジャンプに関わる実装を削っていく必要がありますが、StateMachineを用いた実装の場合は2段ジャンプのStateそのものを消し去るだけで完結します。 また、2段ジャンプ中にのみ行えるアクションなどが発生したときも、新たに2段ジャンプから遷移するStateを作って実装をするだけで良く、他の実装に手を加える必要はありません。

実装が理解しやすい

通常の実装では、コード全体を読んで流れを理解する必要がありますが、StateMachineを用いた実装の場合は状態遷移図を理解すれば良いだけです。

欠点

状態遷移図を用いた実装になれるのが大変

今までのフラグなどを用いて状態を管理していた実装とは異なり、状態遷移図を記述し各状態と遷移を考えながら実装するのは最初はとても大変です。 どんな状態があるかというのを切り出すのもなかなか難しく、各状態からの遷移を漏れなく考えるのも慣れが必要になります。

まとめ

欠点にも書いたとおり、はじめのうちはStateMachineに沿った実装を行うことは今までの考え方とは大きく異なるため大変かもしれません。 しかし、その分かなり大きな利点を得ることができるので、積極的に採用していったほうが良いものだと思います。

今回は、具体的な実装方法に関しては触れませんでしたが、今後時間があるときに具体的な実装を交えた記事に関しても書きたいと思います。