はかせのラボ

私の頭の中を書いていく雑記ブログです

DirectX シーン切り替えが自動化出来た

あいさつ

最近気温が低くなり冬眠しそうになっているはかせです。
私の部屋には暖房の類がなく、凍えながら作業をしています。

シーン切り替え

まずは動画です。
youtu.be

タイトル→プレイ→リザルト→タイトル・・・
といったループでシーンが切り替わっています。

タイトルとリザルトはエンターキーを押したら、
プレイは自機もしくは敵がしんだら切り替わっています。

実装概要

①各シーンクラスを生成
②シーン管理配列に格納
③条件を満たしたら次にシーンに切り替え

①に関しては今までで既にやってきたことなので詳細は割愛します。
ただまともにコードを上げたことはなかったので
そこだけやります。

class DXGameObject;

class Scene
{
public:
	Scene() {};
	virtual ~Scene() {};
	void SetDXResourceManager(DXResourceManager* manager) { mDXRescourceManager = manager; }
	//シーンに最初から存在するゲームオブジェクトを渡す
	std::vector<DXGameObject*> GetGameObjects() const
	{ 
		std::vector<DXGameObject*> games;
		for(auto& game:mGameObjectsList)
		{
			games.push_back(game.get());
		}
		return games;
	}
	//ゲームオブジェクトをシーンに登録し参照を渡す
	virtual DXGameObject* Instantiate();
	//シーンの初期設定 シーン上のオブジェクトの生成などを行う
	virtual void Init() {};
	//シーンが始まった時に呼ばれる
	virtual void SceneStart() {};
	//Update前に呼ばれる ゲームオブジェクトに依存しないUpdate
	virtual void SceneUpdate() {};
	//LateUpdate前に呼ばれる ゲームオブジェクトに依存しないLateUpdate
	virtual void SceneLateUpdate() {};
	//描画処理が終わった後に呼ばれる 1フレームの最後に行う処理
	virtual void SceneEndFrame() {};
	//シーンの終わりに呼ばれる
	virtual void SceneEnd() {};
	//シーンの終了条件
	virtual bool IsSceneEnd() { return false; }
protected:
	//このシーンに最初から存在するゲームオブジェクトのリスト
	std::vector<std::unique_ptr<DXGameObject>> mGameObjectsList;
	//全体リソース管理クラスへの参照
	DXResourceManager* mDXRescourceManager;
};

シーンクラスはこんな感じになっていて
各シーンクラスはこのクラスを継承し
必要なところを書き換えて実装しています。

作り直しに次ぐ作り直しをしているので
いろいろごちゃっていますw
最後のほうでコードの整理をしなければいけませんね。

②は書いてあるまんまです。
シーンクラスの配列を用意し、
そこに生成したシーンクラスを格納しています。

③は IsSceneEndがtrueを返したら終了条件を満たしたとし、
シーンを切り替えます。

シーン切り替え方法

これも過去上げてきましたが、詳細がなかった(気がする)
やつなのでちょっと書きます。

手順は
①登録シーンを切り替える
②旧登録シーンのSceneEndを呼ぶ
③新登録シーンのSceneStartを呼ぶ

です。
(なんか私のプログラムって3つの手順で構成されてることが多い気がする・・・)

①はシーン管理配列を頭から順に切り替えていっています。

//シーン番号をループ
mSceneIndex = (++mSceneIndex) % mSceneCount;
//登録シーンを切り替える
mDXExcuter->SetScene(mSceneList[mSceneIndex].get());

実装はこんな感じです。

ちなみに小ネタなのですが、
値を0~一定値の範囲でループさせたいときって
皆さんどんな書き方をしていますか?
多分愚直に書くならば

if(count < 0) count = max;
if(count > max) count = 0;

こんな感じでif文で確認してやると思います。
やりたいことが直感的にわかるのでいいと思います。

ただループさせたいだけで2行書かなければいけないのはどうでしょうか?
私はめんどくさいと思います。
コードを多く書くということは
バグの混入率の上昇やヒューマンエラーを誘発します。

値をループさせるだけならば余りを使えば1行で行けます。

//シーン番号をループ
mSceneIndex = (++mSceneIndex) % mSceneCount;

今回の私の例でいくならシーン数は3つです。
なので0~2の間でループさせたいです。
上記のコードでそれが出来ます。
実際に数値を入れてみればわかると思います。

//mSceneCount = 3

//mSceneIndex = 0
mSceneIndex = 1 % mSceneCount;// 1
//mSceneIndex = 1
mSceneIndex = 2 % mSceneCount;// 2
//mSceneIndex = 2
mSceneIndex = 3 % mSceneCount;// 0

どうでしょうか。
余りを使えばif文2行でやっていた処理が
計算式1行で済みました。

逆ループをしたければ(++mSceneIndex)を
(mSceneIndex + mSceneCount - 1)に変更すればできます。
こちらも実際に値を入れればわかると思います。

値ループって意外と使うので(私は)
地味ですがコード量削減に役立ってくれています。
(あとif文も回数が増えると意外と処理食っていくのでその対策にも便利です)
パッと見分かりづらいかもですが何回か使うと慣れますw

②、③はメソッド呼んでるだけです。
準備と後始末をするだけなので特に書くことはありません。

あとがき

とりあえずこれで流れはできました。
いやーここまで来るの大変だったなぁ・・・
(まだ未実装多いけどw)

とりあえず敵増やしてスコア的なの付けたいですね。
今までの経験上すんなりいく気がしないのですが、
まぁ何とかなるでしょう。(なったからここまで来てるわけだしね)

では今回はこの辺でノシ

今回作ったものはgithubに上げました
github.com