feature image

2017年11月14日 | ブログ記事

Stateパターンを用いた状態の管理

こんにちは.traPAdventCalendar2017の11月14日担当のOsa_Pyonです.

はじめに

ゲームを制作する際にプレイヤーの状態をどうやって記述,管理するかという課題は常に発生します.この記事では状態の記述,管理の方法として状態ごとにクラスを定義するStateパターンという手法を紹介していきます.

ゲームにおけるプレイヤーの状態

例としてマリオを考えてみます.マリオが持つ状態を列挙してみると

こんな感じになりますね.それぞれの状態から状態への遷移図はこの様になります.
state-1

switchで書いてみた

前述の状態遷移をswitch文を使って実装しました.言語はc#です.

Mario.cspublic class Mario {

    //状態
    enum State{Idle,Run,InAir,HipDrop};
    State state = State.Idle;
    
    //毎フレーム実行される
    void Update() {
        switch (state) {
            case State.Idle:
                if(/*ジャンプ入力*/) {
                    state = State.InAir;
                    //ジャンプ処理
                    Jump();
                    break;
                }else if(/*移動入力*/) {
                    state = state.Run;
                    break;
                }
                break;
            
            case State.Run:
                if(/*ジャンプ入力*/) {
                    state = State.InAir;
                    //ジャンプ動作
                    Jump();
                    break;
                }else if(/*移動入力*/) {
                    //走るという処理
                    Run();
                    break;
                }else{
                    state = State.Idle;
                    break;
                }
                break;
                
            case State.InAir:
                if(/*ヒップドロップ入力*/) {
                    state = State.HipDrop;
                    break;
                }else if(/*地上にいる*/) {
                    state = State.Idle;
                    break;
                }
                break;
                
            case State.HipDrop:
                if(/*地上にいる*/) {
                    state = State.Idle;
                }else{
                    //ヒップドロップの処理
                    HipDrop();
                    break;
                }
                break;
            }
        }
    }
}

このコードでは実感し難いですが状態数が10や20とかになって状態による分岐がUpdate以外の場所でも出現した上で,振る舞いを変更したり状態を増やしたりする時,全ての分岐をチェックし書き直さなくてはなりません.いやです.

Stateパターンを用いて書き直す

Stateパターンで上のコードを書き直すと次のようになります.

State.csinterface State {
    State Execute();
}
StateProcessor.cspublic class StateProcessor {
    State state;
    
    public StateProcessor() {
        state = new Idle();
    }
    
    //毎フレーム呼び出される
    void Update() {
        state = state.Execute();
    }
}
Idle.cspublic class Idle : State {
    public State Execute() {
        if(/*ジャンプ入力*/) {
            //ジャンプ処理
            Jump();
            return new InAir();
        }else if(/*移動入力*/){
            return new Run();
        }else{
            return this;
        }
    }
}
Run.cspublic class Run : State {
    public State Execute() {
        if(/*ジャンプ入力*/) {
            //ジャンプ動作
            Jump();
            return new InAir();
        }else if(/*移動入力*/) {
            //走るという処理
            Run();
            return this;
        }else{
            return new Idle();
        }
    }
}
InAir.cspublic class InAir : State {
    public State Execute() {
        if(/*ヒップドロップ入力*/) {
            return new HipDrop();
        }else if(/*地上にいる*/) {
            return new Idle();
        }else{
            return this;
        }
    }
}
HipDrop.cspublic class HipDrop : State {
    public State Execute() {
        if(/*地上にいる*/) {
            return new Idle();
        }else{
            //ヒップドロップの処理
            HipDrop();
            return this;
        }
    }
}

この様にすることで,例えばHipDropからの遷移を追加する時やHipDropの挙動を変更する時にHipDropクラスのみをいじれば良くなりました(書き換え前だとコード全体をチェックしなくてはいけません).うれしい.ちなみに状態遷移の仕方は色々な派閥があるらしいです.

まとめ

この手法は僕が現在制作に関わっているゲームで管理が爆発した時に出会ったデザインパターンです.今回解説した手法以外にも状況に応じた様々な先人の知恵が存在するのでそれらをゴリゴリ使っていきましょう.
明日はPolyさんの記事です.

参考

Stateパターン TECHSCORE

Osa_Pyon icon
この記事を書いた人
Osa_Pyon

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2017年11月14日
IBIS2017参加報告
Keijan icon Keijan
2017年11月17日
そばやのワク☆ワク流体シミュレーション~MPS編~
sobaya007 icon sobaya007
2017年12月26日
RustでMCMC(Metropolis-Hasting)
David icon David
2017年12月13日
チズケ破壊論
whiteonion icon whiteonion
2017年12月1日
WaltZ
Double_oxygeN icon Double_oxygeN
2017年11月4日
文章をよしなに分散表現しよう
David icon David
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記