グラフィック版スライドパズルを作っていくよ

コンソール版による試作品製作の意義

ここまでたどり着いた人は、多分だけどコンソール版ではスライドパズルが完成しているはず。
昔からゲーム作ってる人は良くやるんだけど、とりあえずコンソールで配列とかを駆使してプロトタイプ(試作品)を作って、それをグラフィック表示にしていくという開発手順である。
これをやってみることで、とりあえず

が確認できる。
後は、できたゲームにグラフィックを割り当てていったり、座標系とか描画とかグラフィック特有の処理を解決すればゲーム完成!
って流れである。(簡単だね)
後は、画面を作って、現在の盤面を表示できるようにDraw関数を作る。

Fig. 1: ゲーム画面

画面のクリックした位置のパネル番号を取得して、コンソール版の移動可能か調べる関数に渡して、
動かせそうなら、コンソール版のパネルをスペースと入れ替える関数に渡す。
なんかできそうじゃない?

準備1 ゲーム全体の流れを作る

後からやるととってもめんどくさいことになるので、まずゲームの流れをまるっと作ってゆく。
今回のゲームは、パズルゲームなのでとても簡単流れを考えると以下のようになると思う。。

  1. タイトル画面(⇒プレイ画面へ移行)
  2. プレイ画面(⇒クリアしたらクリア画面へ移行、⇒ゲームオーバーならゲームオーバー画面へ)
  3. クリア画面(⇒タイトルへ移行)
  4. ゲームオーバー画面(⇒タイトル画面へ移行)

スライドパズルのレベルデザイン的な部分は、難易度、手数制限、時間制限等で考えられるが、今回はクリアはあるけどゲームオーバー(手数とか時間制限はなし)で考える(ここは後付けでも簡単だし!)
授業でやったように、ゲームのステート(状態)を移行していくことでその場面に必要な関数を呼び分けるという作戦をとる。
すなわち、こんな感じのデザインになるかなと思う

"状態遷移"
enum GAME_STATE
{
	TITLE,
	PLAY,
	CLEAR,
	GAMEOVER,
};
 
GAME_STATE state = GAME_STATE::TITLE; //状態の初期化
 
 
	while (System::Update())
	{
		switch (state)
		{
		case TITLE:
			TitleUpdate(board);
			TitleDraw();
			break;
		case PLAY:
			PlayUpdate(board);
			PlayDraw(board);
			break;
		case CLEAR:
			ClearUpdate(board);
			ClearDraw();
			break;
		case GAMEOVER:
			break;
		default:
			break;
		}
	}

タイトル画面を表示するまで

とりあえずタイトル画面を出したいね。

各状態で呼び出す関数を以下のように作っていこうと思う。

とりあえずSiv3Dのプロジェクトを作って、こいつらを追加しちゃいます。
ほんとは、ソースコードとヘッダファイル分けたほうがいいけど、今回は全部メインに書いていきます。

ここでちょっとプロトタイプ宣言の話

宣言と定義は別だよねって話は授業の時にしたと思います。
プロトタイプ宣言は、関数の戻り値の型と、関数名、引数のリストを書いたものです。
(関数定義から、関数ブロック(処理内容)とってかわりにセミコロンつければいいよ。)
プロトタイプ宣言と、関数定義を書くと2度手間な気がするが、役割が違う。

初めのひな型

"全体像"
enum GAME_STATE
{
	TITLE,
	PLAY,
	CLEAR,
	GAMEOVER,
};
 
//ゲーム状態の変数と、状態の初期化
GAME_STATE state = GAME_STATE::TITLE; 
 
void TitleUpdate();
void TitleDraw();
 
void PlayUpdate();
void PlayDraw();
 
void ClearUpdate();
void ClearDraw();
 
void Main()
{
	// 背景の色を設定する | Set the background color
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
 
	while (System::Update())
	{
		switch (state)
		{
		case TITLE:
			TitleUpdate();
			TitleDraw();
			break;
		case PLAY:
			PlayUpdate();
			PlayDraw();
			break;
		case CLEAR:
			ClearUpdate();
			ClearDraw();
			break;
		case GAMEOVER:
			break;
		default:
			break;
		}
	}
}

ここでやったのは、

関数の準備

プロトタイプ宣言まで完了したが、関数本体=定義、がないため呼び出せない。
関数宣言の中身を空にしてると、呼び出してもスルーするだけなのでエラーにはならない。
なので、とりあえず処理部を空にして定義をすべて作っておく。
プロトタイプ宣言をまるっとドラッグで選択して、右クリックして、「クイックアクションとリファクタリング」⇒「宣言/定義の作成」をえらぶと、空の定義が自動でできるので便利!
そうするとこの状態になる。

"関数定義まで"
//上のほう省略
//プロトタイプ宣言たち
void TitleUpdate();
void TitleDraw();
 
void PlayUpdate();
void PlayDraw();
 
void ClearUpdate();
void ClearDraw();
 
void Main()
{
	// 背景の色を設定する | Set the background color
	Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
	//タイトル画面とスタートボタンのフォント(ンでそのままほかのシーンに使いまわし)
	FontAsset::Register(U"TITLE_FONT", FontMethod::SDF, 40, Typeface::Bold);
	FontAsset::Register(U"BUTTON_FONT", FontMethod::SDF, 20, Typeface::Mplus_Heavy);
 
	while (System::Update())
	{
       //省略
	}
}
//この関数定義が自動で生成されるよ!
void TitleUpdate()
{
}
 
void TitleDraw()
{
}
 
void PlayUpdate()
{
}
 
void PlayDraw()
{
}
 
void ClearUpdate()
{
}
 
void ClearDraw()
{
}

タイトル画面の作成

Mainの中で、タイトル画面用のFontAssetを2つほど用意して、タイトル画面を作ってみよう。
(みんな好きなように作っていいよ。この説明のタイトル画面は、とりあえずの説明用なので文字だけにします)
上の関数定義のソースコードにシラーっとFontAsset2個登録してるので参考にしてください。
(これは授業でやったことあるから大丈夫だよね? Mainの中でFontAssetを登録するとプログラムのどこからでも使えるFontが生成されるんだったね)

Fig. 2: タイトル画面の作成

とにかくこんな感じでタイトルを作る!
実際の処理は、TitleDrawの中に描画処理を書いてやります。
画像読んだり、アニメーションしたりいろいろやってみて!

"タイトル画面の描画"
void TitleUpdate()
{
	//特になし
}
 
void TitleDraw()
{
	String TitleStr = U"THE SLIDE PUZZLE";
	String StartStr = U"Push Here to Start GAME ";
 
	Point margin{ 3,3 };
	Point ajustSpace{ 0, -50 };
	Point startPoint = { Scene::Center().x, Scene::Center().y + 50 };
	FontAsset(U"TITLE_FONT")(TitleStr).drawAt(Scene::Center() + ajustSpace + margin, Palette::Lightslategray);
	FontAsset(U"TITLE_FONT")(TitleStr).drawAt(Scene::Center() + ajustSpace, Palette::Blueviolet);
	FontAsset(U"BUTTON_FONT")(StartStr).drawAt(TextStyle::Outline(0.2, Palette::Black),
		                                     startPoint + ajustSpace, Palette::White);
}

これでタイトル画面が表示されるか確認する!

グラフィック編 その2へ