見出し画像

コナミコマンドを認識する仕組みを作ってみよう

状態遷移は色々作ってみるとだんだん感触が掴めてきます。これまで色々紹介してきた状態遷移の武器を使い、コナミコマンド(上上下下左右左右BA)を認識する仕組みを作ってみましょう。

ハッシュテーブルが楽かも

過去記事で紹介してきた状態遷移をざっと列挙してみます:

・if文
・switch~case
・関数ポインタ
・状態遷移表+ハッシュテーブル
・クラス内メソッド
・入れ子クラス
・状態遷移専用クラス
・std::function +ラムダ式

武器増えましたねぇ(^-^)。もちろんどれを使ってもコナミコマンド判定機を作れます。ただ連続するキー入力の正誤判定をするだけではありますので、あまり仰々しい物(下段にある武器)は必要無いかなと思います。

取り敢えずif文で超愚直に書いてみましょうか:

int cur = 0;

bool konamiCommnad() {
    KEY key = getInput();
    if ( cur == 0 && key == KEY_UP )
        cur++;
    else ()
        cur = 0;   // コマンドミス
    }

    if ( cur == 1 && key == KEY_UP )
        cur++;
    else ()
        cur = 0;   // コマンドミス
 
    ...
 
    if ( cur == 9 && key == KEY_A ) {
        cur = 0;     // 成功なので元に戻す
        return true;  // 成立
    }
    return false;   // まだ成立せず
}

わーやっちゃってるなぁって感じですよね。これはちょっといただけない。そこで入力するキーの順番をハッシュ化してみると、ずっと綺麗になります:

int cur = 0;
KEY keys[] = {
    KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN,
    KEY_LEFT, KEY_RIGHT, KEY_LEFT, KEY_RIGHT, KEY_B, KEY_A
};

bool konamiCommand() {
    Key key = getInput();
    cur = ( key == keys[ cur ] ? cur + 1 : 0 );
    if ( cur == 10 ) {
        cur = 0;
        return true;
    }
    return false;
}

これは状態遷移表+ハッシュテーブルの概念に近い実装です。

上の記事では一つの状態が複数の遷移先を持つためハッシュテーブルが2次元配列になっていますが、コナミコマンドの場合は各状態で遷移先が一つだけなのでハッシュテーブルを1次元配列にできるんですね。またすべての遷移先でする事が「キーを待つ」と同じなので、関数ポインタ配列もいりません。

汎用的なコマンド認識クラスを作ろう

ハッシュテーブルによる状態遷移はデータ駆動的にできるため、入力すべきキーを外から与える事が容易に出来ます。これを利用すれば汎用的なコマンド認識クラスを作れます。こんな感じです:

#include <initializer_list>   // 配列初期化用
#include <vector>

class KeyCommand {
public:
    KeyCommand( initializer_list<KEY> keyList ) : cur() {
        for ( auto it = keyList.begin(); it != keyList.end(); it++ )
             keys.push_back( *it );
    }

    // コマンドチェック
    bool check() {
        Key key = getInput();
        cur = ( key == keys[ cur ] ? cur + 1 : 0 );
        if ( cur == keys.size() ) {
            cur = 0;
            return true;   // 成立!
        }
        return false;   // まだ
    }

private:
    int cur;
    std::vector< KEY > keys;
};

コンストラクタで認識させたいコマンドリストを渡して、checkメソッドを毎フレーム回してコマンド入力をチェックします。

KeyCommand konamiCommand(
    { KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN,
      KEY_LEFT, KEY_RIGHT, KEY_LEFT, KEY_RIGHT, KEY_B, KEY_A }
);

// ゲームループ
while( ture ) {
    if ( konamiCommand.check() ) {
        allWeaponOn();   // ウェポン最強に!
    }
}

checkメソッドを親クラス(KeyCommandBase)に持たせて、具体的な各コマンドを表すクラスをそこから派生しても良いと思います。

キーコマンドをクラス化すれば、複数の独立したコマンド判定オブジェクトを作れるので、例えば格闘ゲームのキャラに仕様に見合うコマンドを登録すれば、技のコマンド判定なども出来ますよね(実際はもっと色々考える事がありますが(^-^;)。

こういう小さい状態遷移を色々作っていくと、的確な武器もだんだん選択出来るようになってきます。今後も機を見て色々サンプルを作ってみますね(^-^)

いいなと思ったら応援しよう!