ゲームが作れるようになるまでがんばる日記

ゲーム制作のことを中心にゲームに関することを書いています

State

状態をクラスとして表現するもの。
これはゲームプログラムでは定番の処理。タイトル、ゲーム中、ゲームオーバーなどの状態をクラスで表現し、それらを切り替えて使用する。

// 状態を表すインタフェース
public interface State {
    public abstract void proc(Context context);
    public abstract void draw(Context context);
}
// タイトルを表すクラス
public class Title implements State {
    private static Title singleton = new Title();
    private Title() { }
    public static State getInstance() {
        return singleton;
    }
    public void proc(Context context) {
        // タイトルの処理
           ...
        // STARTボタンが押されたらゲームの状態へ
        if ( STARTボタン押されたか ) {
            context.changeState( GameMain.getInstance() );
        }
    }
    public void draw(Context context) {
        // タイトル画面の描画
    }
}
// ゲーム中を表すクラス
public class GameMain implements State {
    private static GameMain singleton = new GameMain();
    private GameMain() { }
    public static State getInstance() {
        return singleton;
    }
    public void proc(Context context) {
        // ゲーム中の処理
           ...
        // 自機が全部やられたらゲームオーバーへ。
        if ( 自機が全部やられた? ) {
            context.changeState( GameOver.getInstance() );
        }
    }
    public void draw(Context context) {
        // ゲーム中画面の描画
    }
}
// ゲームオーバーを表すクラス
public class GameOver implements State {
    private static GameOver singleton = new GameOver();
    private GameOver() { }
    public static State getInstance() {
        return singleton;
    }
    public void proc(Context context) {
        // ゲームオーバーの処理
           ...
        // ボタンが押されたらタイトルへ
        if ( ボタンが押された? ) {
            context.changeState( Title.getInstance() );
        }
    }
    public void draw(Context context) {
        // ゲームオーバー中画面の描画
    }
}
// コンテキスト、状態を管理するインタフェース
public interface Context {
    public abstract void changeState(State state);
}
// ゲーム全体のクラス
public class Game implements Context {
    private State state = Title.getInstance();  // 現在の状態
    public void proc() {
        state.proc();
    }
    public void draw() {
        state.draw();
    }
    public void changeState(State state) {
        this.state = state;
    }
}

※ソースはイメージを表したもので、実際にはこのまま入力しても動作しない。
これは非常に単純化した例。タイトル、ゲーム中、ゲームオーバーをStateを継承したクラスで表し、proc()でそれぞれに応じた処理を行い、draw()で描画を行う。
ゲーム全体のクラスではStateがなんであろうとproc()とdraw()を呼べばよい。
ただし、ここに挙げた例だとchangeStateをしたフレームでproc()とdraw()のStateが異なるという問題がある。対処としてはStateをすぐ変更するのではなく、予約しておいて次のフレームで変更するとか。


参考文献:(旧版)Java言語で学ぶデザインパターン入門
参考:ギコ猫とStateパターン
(2007-9-14 ソースで各状態がインタフェースになっていたのをクラスに修正)