状態遷移とゲームループ

次に、タイトル画面をクリックしたら⇒プレイ画面、プレイ画面をクリックしたら⇒クリア画面、クリア画面をクリックしたら⇒タイトル画面。。。とループできる仕組みを作っちゃおう
今状態は、TITLE, PLAY, CLEAR, GAMEOVERの4つあるので、それぞれのDraw〇〇を作ってしまいましょう。



この4つの画面をとりあえず作って表示する。
今、まだ状態の切り替え処理を書いていないので、無理やり状態をPLAY、CLEARに変更して表示させる。
TitleDraw();、PlayDraw();、ClearDraw(); GameOverDraw();の宣言と定義は書いたし、状態が遷移した際にそれを呼び出すswitch-case文はもう書いてあるので、状態さえ変われば呼び出される関数が変わるはずである。

"状態の無理やり切り替え"
//ゲーム状態の変数と、状態の初期化
GAME_STATE state = GAME_STATE::TITLE;
//GAME_STATE::は省略できるよ
//GAME_STATE state = TITLE; でもよい
//プレイ画面を呼び出す
//GAME_STATE state = GAME_STATE::PLAY;
//クリア画面を呼び出す
//GAME_STATE state = GAME_STATE::CLEAR;
//ゲームオーバー画面を呼び出す
//GAME_STATE state = GAME_STATE::GAMEOVER;

これを直接書き換えて、switch-case文に突入することでプレイ画面とクリア画面が正しく呼び出されるか確認できる。

次に、クリックしたら、次の状態に移動するって処理を書いてみます。
今ある関数は、

void TitleUpdate();
void PlayUpdate();
void ClearUpdate();
void TitleDraw();
void PlayDraw();
void ClearDraw();

だが、○○Drawは、現在の盤面や画面の描画処理のみを、入力や変数の変更は○○Updateのみで行うようにすることで、プログラムが作りやすくなる。
(決めたら、そのルールを破らないのは大事!)
現在描画処理はできているので、各Update関数でクリックしたときに、状態を移行する処理を書いていけば、今回の目的を達成できる。
とりあえず、タイトル⇒プレイ画面の移行を書いてみよう。
画面のクリックは、授業でやった通り MouseL.pressed()でtrue,falseで取得できる。
後は、押されたときに次の状態に移行してやればいい。
stateはグローバル変数にしといたから、どこからでもアクセスできるよ!

"クリックの検出"
void TitleUpdate()
{
	if (マウスの左ボタンが押された)
	{
		ステート(state)をプレイ(GAME_STATE::PLAY)に移行
	}
}

書いたら動作させてみて、タイトル画面からプレイ画面に移行できたか確認しよう!
同じようにプレイ画面⇒クリア画面、クリア画面⇒タイトル画面、の移行も書いてみよう

実際のゲーム内での状態移行

これができたら、ゲーム状態のループはほぼ完成。
実際のゲーム内ではクリックで移行ではなく、例えば、

  • スタートの文字を押したら、プレイ画面へ移行してゲーム開始
  • パズルが完成したら、クリア画面に移行
  • クリア画面で10秒おめでとうメッセージを表示したらタイトルに戻る

などの方法で状態を移行していくことになる。
早速スタートボタンを作ってみよう!
ゲームタイトル(THE SLIDE PUZZLE)の下の「Push~」を押したらゲーム開始するように書き換えていこう。
と思ったけど、DxLibで、文字の描画領域を取得してそこを押したら・・・って、結構面倒です。
今回は、画面クリックしたら次、でとりあえず作っていきましょう。

クリックの取得

クリックの取得は、

  • 毎フレームごとに
    • 左ボタンを押しているか判定
    • もし、前フレームで押していなくて、かつ、現在押している
      • YES:これはクリック
      • 現在のクリック状態を保存

を繰り返します。ソースコードにすると

void TitleUpdate(void)
{
    // 今のフレームでマウスの左ボタンが押されているか?
    bool cur = (GetMouseInput() & MOUSE_INPUT_LEFT) != 0;
 
    // 前は押していなかったけれど、今は押している → クリックした瞬間
    if (cur == true && prev == false)
    {
         state = PLAY;  // 状態を PLAY に切り替える
    }
 
    // 今の状態を次フレームの「前の状態」として覚えておく
    prev = cur;
}

こんな感じになります。(GetMouseInput() & MOUSE_INPUT_LEFT) != 0がtrueだと左ボタンが押されていることを表します。
あとはこれを、TitleUpdate、PlayUpdate。。。の必要なところすべてに書いてやればいいです。(現在の状態が何で、どこに遷移するかを正確に書くこと!)

また、

  • Drawは描画処理とその他軽い処理(ほんとは描画のみがいいんだけどね)
  • Updateは、状態や変数の更新処理

のように、処理を分けます。
さてやってみよう!

次はいよいよプレイ画面を作っていくよ!
プレイ画面でも同じように、UpdateとDrawの仕事をうまく分けて書いていくことを心がけよう!

Fig. 1: 完成イメージ(動画)
  • game-engineer/classes/2025/something-else/summertime-special-cource/slidepuzle-dxlib-2.txt
  • 最終更新: 5カ月前
  • by root