あさちゅんのゲームブログ

UnityやSiv3Dに関するゲーム開発メモを残していきます

Siv3Dでポーズ画面を簡単に実装する with HamFramework

Siv3Dでポーズ画面を簡単に実装する方法を紹介します。

と言っても、既存のゲームに実装するというより、こういう風に作れば簡単に実装できるって感じの紹介です。
せっかくSiv3Dを使っているのでJanuary 2015 v2から実装されたHamFrameworkを使いましょう!

HamFrameworkとは?

Siv3Dで簡単にゲームを作るのを支援するフレームワークです。
一応、Siv3Dとは別物ですがついてくるのでインクルードするだけで使えます。

今回はそれのシーン管理機能を使います。(シーン遷移は行いませんが、、、)
公式リファレンスはこちら

実はこれにゲームを落としこんでしまえば、1分くらいでポーズ機能が実装できるんです。
それでは、HamFrameworkの使い方から見て行きましょう。

HamFrameworkの使い方

簡単なシーンを一つ作ってみました。

struct GameData {};	//今回は使わないので空でいい

struct Game : SceneManager<String, GameData>::Scene
{
	Circle player;
	Array<Circle> bullets;

	void init() override
	{
		player = Circle(320, 400, 50);
	}

	void update() override
	{
		if (Input::KeyLeft.pressed)
		{
			player.moveBy(Vec2::Left);
		}

		if (Input::KeyRight.pressed)
		{
			player.moveBy(Vec2::Right);
		}

		if (Input::KeyZ.clicked)
		{
			bullets.emplace_back(player.center, 10);
		}

		for (auto& bullet : bullets)
		{
			bullet.moveBy(5.0 * Vec2::Up);
		}

		player.draw(Palette::Red);
	}

	void draw() const override
	{
		for (auto& bullet : bullets)
		{
			bullet.draw(Palette::Blue);
		}

		player.draw(Palette::Red);
	}
};

矢印キーで左右に動き、Zキーで弾を発射する簡単なシーンですね。
それでは、軽く解説していきます。

まず、init関数でSceneクラスのメンバの初期化を行います。
update関数にはシーンの更新処理をdraw関数にはシーンの描画処理を記述します。

ここで重要なのがdraw関数がconstメンバ関数であるということです。

メンバ関数constキーワードをつけることによって定義される。
これらの関数は読み取り専用であり、メンバ変数を変更する処理ができない。
Siv3Dではdraw関数や、movedBy、rotatedなどの過去分詞のつく関数に多い。

Sceneのdraw関数はconstメンバ関数なので中で非constメンバ関数を呼べません。今回は使っていませんが、独自クラスの描画処理を行う関数もconstメンバにしておかなければ使うことができないので注意です。

今回はポーズ機能をシーンの更新を意図的に行わないことによって実装します。
ただし、すべての更新を止めてしまうと画面が真っ暗になってしまうので、描画の更新だけを行うように設定します。

ポーズ機能の実装

まずはシーンにポーズ中かどうかを表す変数を追加しましょう。
init関数で初期化するのを忘れないように!

struct Game : SceneManager<String, GameData>::Scene
{
	Circle player;
	Array<Circle> bullets;
	bool pause;	//ポーズ中かどうかを表す変数

	void init() override
	{
		player = Circle(320, 400, 50);
		pause = false;
	}

ここで早期リターンを使用します。

早期リターン
関数の処理の途中でreturnを呼ぶとそれ以降の処理は行われません。
void関数の場合「return;」のように単体で使用します。

早期リターンを用いてupdate関数を無効にすることにより描画更新のみを行います。
ついでにPキーでポーズのON/OFFを切り替えられるようにしましょう。

	void update() override
	{
		if (Input::KeyP.clicked)
		{
			pause = !pause;
		}

		if (pause)
		{
			return;	//早期リターン
		}

		if (Input::KeyLeft.pressed)

これでpause変数がtrueの時は早期リターンによってシーンの更新処理を呼ばずに描画の更新だけを行うようにすることができました。
このままもいいですが、ただ止まってもバグに見えるのでdraw関数でポーズ中と出るようにしましょう。

Font font;

void draw() const override
{
	for (auto& bullet : bullets)
	{
		bullet.draw(Palette::Blue);
	}

	player.draw(Palette::Red);

	if (pause)
	{
		font(L"ポーズ中").drawCenter(240, Palette::Yellow);
	}
}

こんな感じになります。



このようにHamFrameworkを使えば簡単にポーズ機能が実装できます。
(今回の場合はupdateとdrawが分かれていれば何でもいいんですが、、、)
今回はポーズ機能を実装しましたが、このように機能ごとに関数を分けておけば敵の動きを止める魔法や、画面が一瞬止まるエフェクトを作ったりできるので、独自クラスを作るときはこのようなことも念頭に入れるようにしましょう。

おまけ

失敗したかもという人用に完成版を用意しました。

gist.github.com
使用したソフト
Microsoft Visual Studio Express 2013 for Windows Desktop
Siv3D(January 2015 v3)