シーンの管理方法で悩んでいます

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
PK

シーンの管理方法で悩んでいます

#1

投稿記事 by PK » 9年前

いつもこちらのサイトでお世話になっております。PKと申します。

現在ゲームを作成しようとしています。
以下のようにして、シーンごとに CSceneMgr を作成してシーン管理を行おうとしていますが、
ISceneChanger.h 内の virtual enum EScene = 0 や
CSceneMgr.h 内の void ChangeScene(enum EScene NextScene) override でエラーになります。
virtual は関数にしか使えないのは分かりますが、このようにシーケンス(シーンの上の区別)ごとに、その中のシーンは違うので、それをシーンごとに namespace 等でスコープを分けて、enum 定数で管理し、ChangeScene 関数にそれを渡せるようにするべきだと思うのですが、このような方法以外に何か良い方法はありますか。
または、同様の方法でこのエラーを回避できる方法があれば教えてください。

質問内容が分かりにくければ、返信します。よろしくお願いします。

CBaseScene.h

コード:

#ifndef _INCLUDE_GUARD_CBASESCENE_
#define _INCLUDE_GUARD_CBASESCENE_

#include "CSceneTask.h"
#include "ISceneChanger.h"

//シーンの基底クラス。
class CBaseScene : public CSceneTask {
protected:
	ISceneChanger* mSceneChanger;	//クラス所有元にシーン切り替えを伝えるインターフェイス
public:
	CBaseScene(ISceneChanger* changer);
	virtual ~CBaseScene() {}
	virtual void Load()	override {};	//ロード処理をオーバーライド。
	virtual void Unload() override {};	//アンロード処理をオーバーライド。
	virtual void Calc()	override {};	//更新処理をオーバーライド。
	virtual void Draw()	override {};	//描画処理をオーバーライド。
};

#endif
CSceneTask.h

コード:

#ifndef _INCLUDE_GUARD_CSCENETASK_
#define _INCLUDE_GUARD_CSCENETASK_

//共通処理のクラス
class CSceneTask {
public:
	virtual ~CSceneTask() {}
	virtual void Load() = 0;	//ロード処理は必ず継承先で実装する
	virtual void Unload() = 0;	//アンロード処理は必ず継承先で実装する
	virtual void Calc() = 0;	//更新処理は必ず継承先で実装する
	virtual void Draw() = 0;	//描画処理は必ず継承先で実装する
};

#endif
ISceneChanger.h

コード:

#ifndef _INCLUDE_GUARD_ISCENECHANGER_
#define _INCLUDE_GUARD_ISCENECHANGER_

//シーンを変更するためのインターフェイスクラス
class ISceneChanger {
public:
	virtual ~ISceneChanger() = 0;
	//指定シーンに変更する。
	virtual void ChangeScene(enum EScene NextScene) = 0;
protected:
	virtual enum EScene = 0;
};

#endif
CSceneMgr.h

コード:

#ifndef _INCLUDE_GUARD_CSCENEMGR_
#define _INCLUDE_GUARD_CSCENEMGR_

#include "ISceneChanger.h"
#include "CBaseScene.h"

class CSceneMgr : public ISceneChanger, CSceneTask {
private:
	CBaseScene* mScene;	//シーン管理変数
	EScene mNextScene;	//次のシーン管理変数
	enum EScene {
		Scene_Load,
		Scene_XXX,    //このシーケンス(シーンの一つ上の区別です)特有のシーン
		Scene_Unload
	} override;
public:
	CSceneMgr();
	void Load() override;	//ロード
	void Unload() override;	//アンロード
	void Calc() override;	//更新
	void Draw() override;	//描画

	// 引数 NextScene にシーンを変更する
	void ChangeScene(enum EScene NextScene) override;
};

#endif

hide

Re: シーンの管理方法で悩んでいます

#2

投稿記事 by hide » 9年前

構文エラーをそのまま訪ねられちゃうとそらそうよとしか言えないので
具体的にどういう動きをさせたいのかを書いてもらえると助かります。

シーンを管理する側と、シーンそのものの区別がついていないように見えました。
シーンの管理者は、現在のシーンに対して次のシーンをよこせ という指示を出すくらいで充分で、
シーンの実態が勝手に内部でロード、アンロードをやっていれば充分だと思います。
せっかく管理する側される側にきっちり分けることのできる処理なので、管理する側は管理される側の情報を極力知らないべきです。

PK

Re: シーンの管理方法で悩んでいます

#3

投稿記事 by PK » 9年前

返信ありがとうございます。
構文エラーをそのまま訪ねられちゃうとそらそうよとしか言えないので
具体的にどういう動きをさせたいのかを書いてもらえると助かります。
 自分のやりたいことは次の通りです。
 まず、ゲーム自体をいくつかのシーケンスという区切りで分けて管理しています。また、各シーケンスをシーンという区切りで分けて管理しようとしています。
 このとき、各シーケンスごとに、「シーンの基底クラス(CBaseScene.h)」「シーンを変更するためのインターフェイスクラス(ISceneChanger.h)」「シーン管理者(CSceneMgr.h)」を作っていては大変なので、シーケンスごとに CSceneMgr.h のみを作ることにして、ISceneChanger.h と CBaseScene.h は使いまわしたいと考えています。

 以下のことに躓いています。
 シーケンスごとに違いがあるのは、“どのようなシーンがあるのか” ということのみで、他に違いがありません。しかし、ISceneChanger.h は “どのようなシーンがあるのか” という情報(これが enum EScene です)が必要なため、与える必要がありますが、enum EScene は純粋仮想関数のように後から実装することができないので、CSceneMgr.h のみを作るだけでは上手くできません。
シーンを管理する側と、シーンそのものの区別がついていないように見えました。
シーンの管理者は、現在のシーンに対して次のシーンをよこせ という指示を出すくらいで充分で、
シーンの実態が勝手に内部でロード、アンロードをやっていれば充分だと思います。
せっかく管理する側される側にきっちり分けることのできる処理なので、管理する側は管理される側の情報を極力知らないべきです。
管理者は、シーンの変更と、シーンの実行のみ可能にしてみましたが、例えばこのような感じでしょうか。

CBaseScene.h

コード:

#ifndef _INCLUDE_GUARD_CBASESCENE_
#define _INCLUDE_GUARD_CBASESCENE_

#include "ISceneChanger.h"

//シーンの基底クラス。
class CBaseScene {
protected:
	ISceneChanger* mSceneChanger;	//クラス所有元にシーン切り替えを伝えるインターフェイス
public:
	CBaseScene(ISceneChanger* changer);
	virtual ~CBaseScene() {}
	virtual void RunScene() = 0;	//シーンを動かす
};

#endif
ISceneChanger.h

コード:

#ifndef _INCLUDE_GUARD_ISCENECHANGER_
#define _INCLUDE_GUARD_ISCENECHANGER_
 
//シーンを変更するためのインターフェイスクラス
class ISceneChanger {
public:
	virtual ~ISceneChanger() = 0;
	virtual void ChangeScene(EScene NextScene) = 0;	//指定シーンに変更する。
};
 
#endif
CSceneMgr.h

コード:

#ifndef _INCLUDE_GUARD_CSCENEMGR_
#define _INCLUDE_GUARD_CSCENEMGR_

#include "ISceneChanger.h"
#include "CBaseScene.h"

class CSceneMgr : public ISceneChanger {
private:
	CBaseScene* mScene; //シーン管理変数
	EScene mNextScene;  //次のシーン管理変数
public:
	CSceneMgr();

	// 引数 NextScene にシーンを変更する
	void ChangeScene(EScene NextScene) override;
};

#endif

hide

Re: シーンの管理方法で悩んでいます

#4

投稿記事 by hide » 9年前

まず、シーケンスというものが重要そうに聞こえるのですが、コード上にあわられないので
申し訳ないんですが、コードの細かい指摘はできないです。

シーケンスが主でシーンが従なのでしょうか?具体的にそれぞれ何をしているんでしょう。
シーケンスが、タイトル画面とかの括りで シーンがタイトル画面のロード処理とかの括り ですか?
だとすると、ESceneというのがシーンと言われているものの実態を示すもの?

上記の解釈であっているならば、外部にESceneを公開する必要性に疑問を感じます。
継承を利用するならば、外から見て等しい操作ができなければいけません。
オフトピック
憶測が多いので、間違ってたらごめんなさいね。
シーン管理が結構抽象的な話なので、説明文より"具体"例が欲しいです。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: シーンの管理方法で悩んでいます

#5

投稿記事 by usao » 9年前

オフトピック
>enum 定数で管理し、ChangeScene 関数にそれを渡せるようにする

ChangeScene(CBaseScene* pNextScene); //遷移先シーンを直接渡す

みたいな直接的な形ではなく
(遷移先シーンを表すための?)enumを一旦間に挟む形としている理由があると思いますので,
そこら辺を説明した方が良いのではないかと.

PK

Re: シーンの管理方法で悩んでいます

#6

投稿記事 by PK » 9年前

 返信いただき、ありがとうございます。
 説明文だけでは不足していたようですので、コード全体を載せます。
 シーケンス管理につきましては、http://dixq.net/g/sp_06.html こちらを参考にして作成しました。

//main.cpp

コード:

//デバッグ用
#define DEBUG_MODE
#define _CRT_SECURE_NO_WARNINGS

#include "DxLib.h"
#include "CSequenceMgr.h"
#include "key.h"

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
#ifdef DEBUG_MODE
	AllocConsole();
	freopen("CONOUT$", "w", stdout);
#endif

	//ウィンドウ or 全画面
	if (ChangeWindowMode(TRUE) == -1) {
		return -1;
	}

	//DXライブラリ初期化
	if (DxLib_Init() == -1) {
		return -1;
	}

	//裏画面へ書き込み
	if (SetDrawScreen(DX_SCREEN_BACK) == -1) {
		return -1;
	}

	CSequenceMgr SequenceMgr;
	SequenceMgr.Init();
	//メインループ。画面更新、他アプリケーションとの連携処理、画面消去
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		UpdateKey();		//キー情報の更新
		SequenceMgr.Calc();	//計算
		SequenceMgr.Draw();	//描画
	}
	SequenceMgr.End();

	//DXライブラリ終了
	DxLib_End();

#ifdef DEBUG_MODE
	FreeConsole();
#endif
	return 0;
}
//CSequenceMgr.h

コード:

#ifndef _INCLUDE_GUARD_CSEQUENCEMGR_
#define _INCLUDE_GUARD_CSEQUENCEMGR_

#include "ISequenceChanger.h"
#include "CBaseSequence.h"

class CSequenceMgr : public ISequenceChanger, CSequenceTask {
private:
	CBaseSequence* mSequence;	//シーケンス管理変数
	ESequence mNextSequence;	//次のシーケンス管理変数
public:
	CSequenceMgr();
	void Init() override;	//初期化
	void End() override;	//終了処理
	void Calc() override;	//更新
	void Draw() override;	//描画

	// 引数 NextSequence にシーケンスを変更する
	void ChangeSequence(ESequence NextSequence) override;
};

#endif
//ISequenceChanger.h

コード:

#ifndef _INCLUDE_GUARD_ISEQUENCECHANGER_
#define _INCLUDE_GUARD_ISEQUENCECHANGER_

typedef enum {
	Sequence_Menu,    //メニュー画面
	Sequence_Game,    //ゲーム画面
	Sequence_Config,  //設定画面

	Sequence_None    //無し
} ESequence ;

//シーケンスを変更するためのインターフェイスクラス
class ISequenceChanger {
public:
	virtual ~ISequenceChanger() = 0;
	//指定シーケンスに変更する。
	virtual void ChangeSequence(ESequence NextSequence) = 0;
};

#endif
//CBaseSequence.h

コード:

#ifndef _INCLUDE_GUARD_CBASESEQUENCE_
#define _INCLUDE_GUARD_CBASESEQUENCE_

#include "CSequenceTask.h"
#include "ISequenceChanger.h"

//シーケンスの基底クラス。
class CBaseSequence : public CSequenceTask {
protected:
	int mImageHandle;					//画像ハンドル格納用変数
	ISequenceChanger* mSequenceChanger;	//クラス所有元にシーケンス切り替えを伝えるインターフェイス
public:
	CBaseSequence(ISequenceChanger* changer);
	virtual ~CBaseSequence(){}
	virtual void Init()	override {};	//初期化処理をオーバーライド。
	virtual void End()	override;		//終了処理をオーバーライド。
	virtual void Calc()	override {};	//更新処理をオーバーライド。
	virtual void Draw()	override;		//描画処理をオーバーライド。
};

#endif
//CSequenceTask.h

コード:

#ifndef _INCLUDE_GUARD_CTASK_
#define _INCLUDE_GUARD_CTASK_

//共通処理のクラス
class CSequenceTask {
public:
	virtual ~CSequenceTask(){}
	virtual void Init(){}		//初期化処理は実装してもしなくてもいい
	virtual void End(){}		//終了処理は実装してもしなくてもいい
	virtual void Calc()	= 0;	//更新処理は必ず継承先で実装する
	virtual void Draw()	= 0;	//描画処理は必ず継承先で実装する
};

#endif
//CBaseSequence.cpp

コード:

#include "CBaseSequence.h"
#include "DxLib.h"

CBaseSequence::CBaseSequence(ISequenceChanger* changer) : mImageHandle(0) {
	mSequenceChanger = changer;
}

void CBaseSequence::End() {
	//共通処理
}

void CBaseSequence::Draw() {
	//共通処理
}
//ISequenceChanger.cpp

コード:

#include "ISequenceChanger.h"

ISequenceChanger::~ISequenceChanger(){
}
//CSequenceMgr.cpp

コード:

#include "DxLib.h"
#include "Config.h"
#include "Game.h"
#include "Menu.h"
#include "CSequenceMgr.h"

CSequenceMgr::CSequenceMgr() : mNextSequence(Sequence_None) {
	mSequence = (CBaseSequence*) new Menu(this);
}

//初期化
void CSequenceMgr::Init() {
	mSequence->Init();
}

//終了処理
void CSequenceMgr::End() {
	mSequence->End();
}

//更新
void CSequenceMgr::Calc() {
	//次のシーケンスがセットされていたら
	if (mNextSequence != Sequence_None) {
		//現在のシーケンスの終了処理を実行
		mSequence->End();
		delete mSequence;

		//シーケンスによって処理を分岐
		switch(mNextSequence){
		case Sequence_Menu:
			mSequence = (CBaseSequence*) new Menu(this);
			break;
		case Sequence_Game:
			mSequence = (CBaseSequence*) new Game(this);
			break;
		case Sequence_Config:
			mSequence = (CBaseSequence*) new Config(this);
			break;
		}
		//次のシーケンス情報をクリア
		mNextSequence = Sequence_None;
		//シーケンスを初期化
		mSequence->Init();
	}

	//シーケンスの更新
	mSequence->Calc();
}

//描画
void CSequenceMgr::Draw(){
	//シーケンスの描画
    mSequence->Draw();
}

// 引数 NextSequence にシーケンスを変更する
void CSequenceMgr::ChangeSequence(ESequence NextSequence){
	//次のシーケンスにセットする
    mNextSequence = NextSequence;
}
//Menu.h

コード:

#ifndef _INCLUDE_GUARD_MENU_
#define _INCLUDE_GUARD_MENU_

#include "CBaseSequence.h"

//メニュー画面クラス
class Menu : public CBaseSequence {
public :
    Menu(ISequenceChanger* changer);
    void Init()	override;
    //void End() override;
    void Calc() override;
    void Draw() override;
};

#endif
//Menu.cpp

コード:

#include "Menu.h"
#include "DxLib.h"

//CBaseSequence(changer) の意味は、mSequenceChanger = changer
Menu::Menu(ISequenceChanger* changer) : CBaseSequence(changer) {
}

//初期化
void Menu::Init() {
	//画像のロード
    mImageHandle = LoadGraph("images/Sequence_Menu.png");
}

//更新
void Menu::Calc() {
    if(CheckHitKey(KEY_INPUT_G)!=0){//Gキーが押されていたら
        mSequenceChanger->ChangeSequence(Sequence_Game);//シーケンスをゲーム画面に変更
    }
    if(CheckHitKey(KEY_INPUT_C)!=0){//Cキーが押されていたら
        mSequenceChanger->ChangeSequence(Sequence_Config);//シーケンスを設定画面に変更
    }
}

//描画
void Menu::Draw() {
	//親クラスの描画メソッドを呼ぶ
	CBaseSequence::Draw();
	DrawGraph(0, 0, mImageHandle, TRUE);
	DrawString(0, 0, "メニュー画面です。", GetColor(255,255,255));
	DrawString(0, 20, "Gキーを押すとゲーム画面に進みます。", GetColor(255,255,255));
	DrawString(0, 40, "Cキーを押すと 設定画面に進みます。", GetColor(255,255,255));
}
// Config, Game, key は不要かな?と思いますので、省略します。

usao さんが書きました: >enum 定数で管理し、ChangeScene 関数にそれを渡せるようにする

ChangeScene(CBaseScene* pNextScene); //遷移先シーンを直接渡す

みたいな直接的な形ではなく
(遷移先シーンを表すための?)enumを一旦間に挟む形としている理由があると思いますので,
そこら辺を説明した方が良いのではないかと.
特に理由は考えておらず、冒頭のURLのページに書かれているソースコードを参考にさせていただいたのみです。

hide さんが書きました: シーケンスが主でシーンが従なのでしょうか?具体的にそれぞれ何をしているんでしょう。
シーケンスが、タイトル画面とかの括りで シーンがタイトル画面のロード処理とかの括り ですか?
だとすると、ESceneというのがシーンと言われているものの実態を示すもの?
シーケンスが主、シーンが従になります。
シーケンスだけでは括りが大きいので、もう少し小さい括りをシーンとしています。
シーケンスは、タイトル画面、ゲーム画面、設定画面などの大きな括りで、
タイトル画面には、「オープニングムービー再生」のシーンのみ
ゲーム画面には(とりあえず、スーファミのスーパーマリオワールドを例にとります。ご存知でしょうか)、「ステージ選択画面」、「ステージ1」、「ステージ2」…のシーン
設定画面には、「設定画面の表示」「設定1の詳細」「設定2の詳細」…のシーン
という感じです。

hide さんが書きました: 上記の解釈であっているならば、外部にESceneを公開する必要性に疑問を感じます。
継承を利用するならば、外から見て等しい操作ができなければいけません。
すみません、うまく伝わらなかったかも知れません。
外部には EScene を公開しません。
シーケンスごとに内部で(シーケンスのスコープ内で or シーケンスはシーケンスごとに class を作っているので、その中で)シーンの名前のリスト EScene (ゲーム画面の例では、Scene_SelectStage, Scene_Stage1, Scene_Stage2 など)を用意します。

これでうまく具体例になっていて、伝わると良いのですが…

hide

Re: シーンの管理方法で悩んでいます

#7

投稿記事 by hide » 9年前

あぁ、確かにこの形でやるとenumで困っちゃうという気持ちは理解できました。
特別な理由がないのであれば 私からもusaoさんが言っている、遷移先シーンを直接渡すやりかたを推しておきます。

遷移先シーンを遷移元が生成する形にすると
上位の管理者側が管理される側オブジェクトを細かく知る必要がなくなるので、以下のようなメリットがあります。

1.
例えば、数十数百のシーンができた場合に今のやり方だと同じ数の列挙子及びシーンのインクルードが必要になりますが、
遷移先を遷移元が作るようにすれば、いくらシーンが増えようと管理者のコードに手を加える必要がありません。
管理者がやることは次のシーンが来たら切り替える ということだけです。

2.
遷移元が自身の情報から遷移先を生成するので情報の受け渡しもスムーズになるかとおもいます。
たとえばステージ1から2へマリオを引き継ぐとして、管理者が 生成する方法だと
var stage2 = new Stage2(stage1->getMario());
というようにするコードを管理者がわコードに書く必要がありますし、getMarioなどというIFが必要になります。
遷移元で生成すると
var stage2 = new Stage2(this->mario);
のような感じでIFが減りますし、管理者側にコードを追加する必要もありません。

3.
管理される側オブジェクトの情報を知らなくていいことになると、管理する側がかなり簡略化して書くことができるはずです。
今回でいうと、SequenceMgrとSceneMgrを同じクラスにすることができる可能性があります。

PK

Re: シーンの管理方法で悩んでいます

#8

投稿記事 by PK » 9年前

色々なアドバイスをありがとうございました!
おっしゃる通りに作ると、今後の管理がすごく楽に感じられるようになりました。
以下がそのソースコードです。

main.cpp

コード:

//デバッグ用
#define DEBUG_MODE
#define _CRT_SECURE_NO_WARNINGS

#include "DxLib.h"
#include "CSceneMgr.h"
#include "Opening.h"
#include "key.h"

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
#ifdef DEBUG_MODE
	AllocConsole();
	freopen("CONOUT$", "w", stdout);
#endif

	//ウィンドウ or 全画面
	if (ChangeWindowMode(TRUE) == -1) {
		return -1;
	}

	//DXライブラリ初期化
	if (DxLib_Init() == -1) {
		return -1;
	}

	//裏画面へ書き込み
	if (SetDrawScreen(DX_SCREEN_BACK) == -1) {
		return -1;
	}

	CSceneMgr* SceneMgr = new CSceneMgr;
	SceneMgr->ChangeScene(new COpening(SceneMgr));
	//メインループ。画面更新、他アプリケーションとの連携処理、画面消去
	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
		UpdateKey();			//キー情報の更新
		SceneMgr->RunScene();	//シーンの実行
	}
	delete SceneMgr;

	//DXライブラリ終了
	DxLib_End();

#ifdef DEBUG_MODE
	FreeConsole();
#endif
	return 0;
}
CSceneTask.h

コード:

#ifndef _INCLUDE_GUARD_CTASK_
#define _INCLUDE_GUARD_CTASK_

//共通処理のクラス
class CSceneTask {
public:
	virtual ~CSceneTask() {}
	virtual void RunScene()	= 0;
};

#endif
CSceneMgr.h

コード:

#ifndef _INCLUDE_GUARD_CSCENEMGR_
#define _INCLUDE_GUARD_CSCENEMGR_

#include "ISceneChanger.h"
#include "CBaseScene.h"

class CSceneMgr : public ISceneChanger, CSceneTask {
private:
	CBaseScene* mScene;	//シーン管理変数
public:
	void RunScene() override;
	// 引数 pNextScene にシーンを変更する
	void ChangeScene(CBaseScene* pNextScene) override;
};

#endif
ISceneChanger.h

コード:

#ifndef _INCLUDE_GUARD_ISCENECHANGER_
#define _INCLUDE_GUARD_ISCENECHANGER_

//シーンを変更するためのインターフェイスクラス
class CBaseScene;
class ISceneChanger {
public:
	virtual ~ISceneChanger() = 0;
	//指定シーケンスに変更する。
	virtual void ChangeScene(CBaseScene* pNextScene) = 0;
};

#endif
ISceneChanger.cpp

コード:

#include "ISceneChanger.h"

ISceneChanger::~ISceneChanger(){
}
CBaseScene.h

コード:

#ifndef _INCLUDE_GUARD_CBASESCENE_
#define _INCLUDE_GUARD_CBASESCENE_

#include "CSceneTask.h"

//シーンの基底クラス。
class ISceneChanger;
class CBaseScene : public CSceneTask {
protected:
	ISceneChanger* mSceneChanger;	// クラス所有元にシーン切り替えを伝えるインターフェイス
public:
	CBaseScene(ISceneChanger* changer);
	virtual ~CBaseScene(){}
	virtual void RunScene() = 0;	//シーンを実行。
};

#endif
CBaseScene.cpp

コード:

#include "CBaseScene.h"

CBaseScene::CBaseScene(ISceneChanger* changer) {
	mSceneChanger = changer;
}
CSceneMgr.cpp

コード:

#include "CSceneMgr.h"
#include "Opening.h"

void CSceneMgr::RunScene() {
	mScene->RunScene();
}

// 引数 pNextScene にシーンを変更する
void CSceneMgr::ChangeScene(CBaseScene* pNextScene){
	//次のシーンにセットする
    mScene = pNextScene;
}
---Opening---
Opening.h

コード:

#ifndef _INCLUDE_GUARD_OPENING_
#define _INCLUDE_GUARD_OPENING_

#include "CSceneMgr.h"

//オープニング画面クラス
class COpening : public CBaseScene {
private:
	CSceneMgr* mSceneMgr;
public:
	void RunScene() override;
	COpening(ISceneChanger* changer);
	~COpening();
};

#endif
Opening.cpp

コード:

#include "Opening.h"
#include "Opening/PlayLogo.h"

COpening::COpening(ISceneChanger* changer) : CBaseScene(changer) {
	mSceneMgr = new CSceneMgr;
	mSceneMgr->ChangeScene(new Opening::PlayLogo(mSceneChanger));
}

COpening::~COpening() {
	delete mSceneMgr;
}

void COpening::RunScene() {
	mSceneMgr->RunScene();
}
Opening/PlayLogo.h

コード:

#ifndef _INCLUDE_GUARD_OPENING_PLAYLOGO_
#define _INCLUDE_GUARD_OPENING_PLAYLOGO_

#include "CLoad.h"
#include "../CBaseScene.h"
// オープニング/ロゴ画面
namespace Opening {
	class PlayLogo : public CBaseScene, CLoad {
	public:
		void RunScene() override;
		PlayLogo(ISceneChanger* changer);
	};
}

#endif
Opening/CLoad.h

コード:

#ifndef _INCLUDE_GUARD_OPENING_CLOAD_
#define _INCLUDE_GUARD_OPENING_CLOAD_

namespace Opening {
	enum class EGrName {	//グラフィックハンドル名(GrPathと対応)
		Logo,
		Length
	};
	class CLoad {
	private:
		int* mGrHandle;
	public:
		int GetGrHandle(EGrName GrIndex);
		void Load(EGrName GrIndex);
		void Unload(EGrName GrIndex);
		CLoad();	//全てロード
		~CLoad();	//全てアンロード
	};
}

#endif
Opening/CLoad.cpp

コード:

#include "CLoad.h"
#include "DxLib.h"

namespace Opening {
	static const char* GrPath[] = {	//グラフィックハンドル名と対応するように
		"img/Opening/logo.png"
	};
	CLoad::CLoad() {
		int i = 0;
		mGrHandle = (int*)malloc(sizeof(int) * (int)EGrName::Length);
		for (i = 0; i < sizeof(GrPath) / sizeof(GrPath[0]); i++) {
			mGrHandle[i] = LoadGraph(GrPath[i]);
		}
	}
	CLoad::~CLoad() {
		int i = 0;
		for (i = 0; i < sizeof(mGrHandle); i++) {
			mGrHandle[i] != NULL && DeleteGraph(mGrHandle[i]);
		}
		free(mGrHandle);
	}
	int CLoad::GetGrHandle(EGrName GrIndex) {
		return mGrHandle[(int)GrIndex];
	}
	void CLoad::Load(EGrName GrIndex) {
		mGrHandle[(int)GrIndex] = LoadGraph(GrPath[(int)GrIndex]);
	}
	void CLoad::Unload(EGrName GrIndex) {
		DeleteGraph(mGrHandle[(int)GrIndex]);
		mGrHandle[(int)GrIndex] = NULL;
	}
}
Opening/PlayLogo.cpp

コード:

#include "PlayLogo.h"
#include "DxLib.h"

namespace Opening {
	PlayLogo::PlayLogo(ISceneChanger* changer) : CBaseScene(changer) {
	}

	void PlayLogo::RunScene() {
		DrawGraph(0, 0, GetGrHandle(EGrName::Logo), FALSE);
	}
}

ロード部分はイマイチな感じはありますが、シーンの管理に関しては、うまくいっているかなと思っています。
もう特に問題なければこのまま設計を進めていこうと思いますが、何かあれば返信をお願いします。
なさそうであれば、解決としたいと思います。
本当に、ここまで丁寧に返信をいただき、ありがとうございました。

hide

Re: シーンの管理方法で悩んでいます

#9

投稿記事 by hide » 9年前

switch caseが消えて綺麗になりましたね。
複数階層の状態遷移も問題なさそうですし、いいと思います。

PK

Re: シーンの管理方法で悩んでいます

#10

投稿記事 by PK » 9年前

ありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る