GDScriptで状態機械を書く

状態機械(ステートマシン)は、自機が普通の状態と空中にいるときで受け付ける入力を変化させる、普通の状態とゴール時の演出でアニメーションを変化させる、といったゲーム内の要素の状態を記述する際に便利なプログラミングのパターンである。

if文を使った実装

GDScriptで状態機械を書く場合、シーンに割り当てたスクリプト内で状態を表す列挙型 (enum) を利用するとよい。

extends CharacterBody2D

enum PlayerState { Normal, Jumping, Goal, Died }
var player_state: int


func _ready():
    # 初期状態の設定
    player_state = PlayerState.Normal


func _physics_process(_delta):
    if player_state == PlayerState.Normal:
        # なんかする(例:立ってるだけのアニメーションを再生)
        pass
    elif player_state == PlayerState.Jumping:
        # なんかする(例:飛んでるときのアニメーションを再生)
        pass

    move_and_slide()

enum型に関する注意

注意点として、enum型は内部的にint型として扱われているようで、変数定義時に

var player_state: PlayerState  # これはできない

と書くとPlayerStateなんてないぞというエラーが発生する。

enum型のOR条件

複数種類の状態のいずれかを満たす場合、のような OR条件を記述する際には以下のように書くと大きな条件式でも見通しの良い記述にすることができる:

if player_state in [PlayerState.Normal, PlayerState.Jumping]:
    # なんかする
    pass

match文を使った実装

GDScriptではif文の代わりにmatch文を用いて分岐を記述することができる。 CやJavaにあるswitch文にも似ているが、どちらかというとRustのmatch式に近く、ある程度高度なパターンマッチングも可能らしい。

extends CharacterBody2D

enum PlayerState { Normal, Jumping, Goal, Died }
var player_state: int


func _ready():
    # 初期状態の設定
    player_state = PlayerState.Normal


func _physics_process(_delta):
    match player_state:
        PlayerState.Normal:
            # なんかする(例:立ってるだけのアニメーションを再生)
            pass
        PlayerState.Jumping:
            # なんかする(例:飛んでるときのアニメーションを再生)
            pass
        _:
            pass

    move_and_slide()

match文の最後にある_は上のいずれの条件にもマッチしなかった場合にマッチする条件で、CやJava等のswitch文におけるdefaultに相当するものと考えてよい。

OR条件を記述する際には以下のようにカンマ区切りにする:

match player_state:
    PlayerState.Normal, PlayerState.Jumping:
        # なんかする
        pass