« コマンド解析ロジック | メイン | 勘九郎ステージ制作中 »

コマンド解析ロジック その2

キューを使わずに格闘ゲームのコマンド入力を解析する方法について。
その1はこちら

すごいテクニックを思いついた!というわけではないんですが、普通に探してもみつからないんで簡単に解説してみることにします。


用意するものは、ひとつのコマンドに対して存在する条件の数と同じ数の、boolean変数とタイマー変数です。
構造体を作っておくといいですね。

typedef struct {
bool enable;
unsigned long count;
} STCMD;

コマンドが成立するには複数の条件を順番に満たしていく必要があります。
波動拳(下・前下・前・ボタン)を例にしてみましょう。

1.下が押されている
2.下が離されてた
3.下が離されてから nフレーム以内に前下が押された
4.前下が押されてから nフレーム以内に前が押された
5.前が押されてから nフレーム以内にボタンが押された

こんな感じになります。「押された・離された」が混在しているのは間違いではありません。こうしないとしゃがみ状態からコマンドを入力したときに困るので。

そして、これらの条件のそれぞれにさっき用意した構造体変数を割り当てます。

ロジックの肝は「一つ前の条件が満たされているなら、現在の条件の判定を行う」ということです。二つ前の条件は満たされていなくてもいいのです。
具体的にどう判定していくかを書いていきます。

1 前に条件が無いので、下が押されていたら無条件で STCMD[0].enable = true にします。
2 STCMD[0].enable == true かつ STCMD[1].enable == false の時だけ、下方向が入力されているかチェックします。
 入力が無かったら STCMD[1].enable = true とします。
3 STCMD[1].enable == true かつ STCMD[2].enable == false の時だけ、前下方向が入力されているかチェック。
 入力があったら STCMD[2].enable = true とします。
制限時間(nフレーム)を過ぎていたら STCMD[1].enable = false とします。
4 以降、ボタン入力の判定まで同様の操作を行います。
5 入力が成立したら boolean変数を全て false にします。

入力制限時間が過ぎたら boolean 変数を寝かせてあげないと、フラグが立ったままになってしまい「歩き千烈脚」なんていうバグが生まれるので注意です。

こんな説明でわかってもらえたでしょうか?
具体的なソースコードを下に付記しておくので、そちらも参考にしてみてください。

typedef struct {
  bool enable;
  unsigned count;
} STCMD;

STCMD cmd[4];

bool Cmd236(KEYINP stick, KEYINP trigger, unsigned long now) {
if (stick == STICK_2) {
cmd[0].enable = true;
}
if (cmd[0].enable && ! cmd[1].enable && stick != STICK_2) {
cmd[0].enable = false;
cmd[1].enable = true;
cmd[1].count = now;
}
if (cmd[1].enable && ! cmd[2].enable) {
if (stick == STICK_3) {
cmd[1].enable = false;
cmd[2].enable = true;
cmd[2].count = now;
} else if (now - cmd[1].count > 12) {
cmd[1].enable = false;
}
}
if (cmd[2].enable && ! cmd[3].enable) {
if (stick == STICK_6) {
cmd[2].enable = false;
cmd[3].enable = true;
cmd[3].count = now;
} else if (now - cmd[2].count > 12) {
cmd[2].enable = false;
}
}
if (cmd[3].enable && ! cmd[4].enable) {
if (trigger == TRIGGER_A) {
return true;
} else if (now - cmd[3].count > 12) {
cmd[3].enable = false;
}
}
return false;
}