ページ 11

DXライブラリのプログラム設計について

Posted: 2014年9月21日(日) 03:20
by V30
初めまして。この度登録させて頂いた者です。

VS2013 ExpressのC++とDXライブラリを使ってゲームを作り始めて1年程になります。
熟れてきて、クラスを作るようになってきた時からの疑問です。

ゲーム本体のクラスを作り、それとは別に用意したスタートアップ用cppファイル中のWinMain()のDXLibの初期化と終了処理間で、インスタンス化したそのゲーム本体クラス自身が持つメインループ関数「While(){ClsDrawScreen()~ScreenFlip()}」を呼び出すという、いつの間にか教科書と違った組み方をしています。教科書(一般書籍)通りだと、クラスは使わずグローバル変数を使う指示があります。

クラスや構造体を使えば、ExternやStaticを使用せずにスッキリまとまって見やすいプログラムになると個人的に思いますが、自分の場合、そのゲーム本体クラスのメインループ関数から更に別のインスタンス化した違うゲームクラスのメイン関数(もちろんClsDrawScreen()~ScreenFlip()を使用せず、1フレームにするべき処理+終了フラグを返すだけ)を呼び出しています。

WinMain()が親だとすると、常に子供クラスの子供クラス(孫クラス?)を呼んでいる状態ですが、プログラムの設計上に何か問題はありますか?
関数から関数を呼び出すのは計算の途中ではない限りネストが深いとは言わないのかも知れませんが、今時のパソコンだとこれくらいの深さではビクともしないと思いますけれど、どうなんでしょうか…。パソコン経験は長いのですが、本職ではないので、無知な私にご教授お願いします。

使用環境
Windows 7 Home
Core i7 920 2.67GHz
6.00GB RAM
Visual Studio 2013 Express(C++)

Re: DXライブラリのプログラム設計について

Posted: 2014年9月24日(水) 22:04
by softya(ソフト屋)
すいません。
ゆっくり答える隙がないのですが、質問がわかりづらいので回答が付かないのではないかと思います。
簡単な参考擬似コードを提示されてはどうでしょうか?

Re: DXライブラリのプログラム設計について

Posted: 2014年9月25日(木) 05:56
by V30
softya(ソフト屋) 様、ご助言ありがとうございます。

サンプルプログラムで、質問の説明をさせて頂きます。

"Class_Game.h"

コード:

#include <DXLib.h>

//ゲーム本体クラス
class Game()
{
	int exitflag;			//終了フラグ

	//計算処理
	void Calc(){}

	//描画処理
	void Draw(){}

	//入力処理
	void Input(){}

	//メインプログラム
	int Main()
	{
		Input();			//入力処理
		Calc();				//計算処理
		Draw();				//描画処理
		return exitflag;	//終了フラグ返還
	}
};
"Class_Menu.h"

コード:

#include <DXLib.h>
#include "Class_Game.h"

//メニュークラス
class Menu()
{
	//ゲーム状態列挙体
	enum GameState
	{
		GAME_EXIT,		//ゲーム終了
		GAME_MAIN,		//ゲーム中
		GAME_SELECT		//ゲーム選択
	}
	gs = GAME_SELECT;	//初期値 = ゲーム選択

	Game g;				//ゲーム本体インスタンス

	//ゲーム中処理
	void GameMain()
	{
		if (g.Main() == TRUE) gs = GAME_EXIT;		//ゲームプログラム呼び出し&終了判定
	}

	//ゲーム選択
	void GameSelect()
	{
		gs = GAME_MAIN;		//ゲーム状態設定
	}

	//メインループ
	void MainLoop()
	{
		while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0)
		{
			ClsDrawScreen();						//画面消去
			if (gs == GAME_SELECT) GameSelect();	//ゲーム選択画面
			if (gs == GAME_MAIN)   GameMain();		//ゲーム中処理
			if (gs == GAME_EXIT)   break;			//ゲーム終了処理
			ScreenFlip();							//画面反転
		}
	}
};
"Main.cpp"

コード:

#include <DXLib.h>
#include "Class_Menu.h"


#define WIDTH	 800		//ウインドウ幅
#define HEIGHT	 600		//ウインドウ高さ
#define DEPTH	  32		//ビット深度
#define TITLE	"Game"		//ウインドウタイトル

Menu m;						//メニュークラスインスタンス



//***アプリケーション本体***//

int WINAPI WinMain(HINSTANCE h1, HINSTANCE hP, LPSTR lpC, int nC)
{
	ChangeWindowMode(TRUE);					//ウインドウモード変更[FALSE・全文省略(デフォルト)は、全画面モード]
	SetGraphMode(WIDTH, HEIGHT, DEPTH);		//ウインドウサイズ設定
	SetWindowSizeChangeEnableFlag(TRUE);	//ウインドウサイズ変更可能フラグ設定
	SetWindowTextA(TITLE);					//ウインドウタイトル設定
	if (DxLib_Init() == -1) return -1;		//DxLibを初期化→DxLibが異常なら、アプリを異常終了
	SetDrawScreen(DX_SCREEN_BACK);			//描画画面を裏画面に切り替え

	m.MainLoop();							//メニュープログラム実行

	DxLib_End();							//DxLib終了処理
	return 0;								//アプリケーション正常終了
}
解り易くする為にかなり端折りましたが、イメージとしてはこんな感じです。While文の居場所にご注目下さい。

While文の中でProcessMessage()を呼んでいるので、While文を置く場所は上記"Class_Menu.h" "Main.cpp"のどちらでも良い気がしますが、やはり呼び出し元のOSに一番近い"Main.cpp"に記述するのが安心安全なのか?、それとも極端な話、上記"Class_Menu.h"内でのゲーム選択処理を無くして"Class_Game.h"のMain()内にWhile文を置いたりしても全然OKなのか?と言う質問です。

While文の所は何れかのファイルには必ず書かないといけないので、どのファイルに記述してもシンプルさの追求はできそうにはありませんが、クラス不使用の状態から"Main.cpp"をよりシンプルにと進化させていった結果、成り行きでこうなりました。

My PCだと問題なく動作しているので上記の法則で記述しているプログラムが多々ございますが、一般的(本職的?)にはどうなのか、皆様のお考えを聞かせて頂きたいです。

Re: DXライブラリのプログラム設計について

Posted: 2014年9月25日(木) 13:42
by softya(ソフト屋)
ゲームプログラミングの館は読まれましたか?
こちららが参考になると思います。
http://dixq.net/g/sp_06.html
こちらにも有るように唯一無二のProcessMessageのWhileループがWinMainにあるべきかと思います。

【補足】
シンプルであるべきという追求の根本的な目的はバグを無くしメンテンナス性を上げることですので、それを捻じ曲げるとひどい目に会います。
つまり、目的と手段が逆転している可能性を常に忘れてはいけません。
WinMainから別の場所に移すとなにかデメリット上回るメリットは有るのでしょうか?

【補足の補足】
この場合、シンプルにする → バグを無くしメンテンナス性を上げるのが目的で、シンプルにするのは手段です。
シンプルにするのが本来の目的ではありません。

Re: DXライブラリのプログラム設計について

Posted: 2014年9月25日(木) 18:36
by V30
再びのご回答、ありがとうございます。非常に参考になる文献です。早速、コピペして使わさせてもらいます。

取り敢えず力任せでコーディングして、後から訂正・改良してダメな所を減らす手段を取っていますが、コードが大量になって来るとまとめ方も混乱してきて、最近は動けばいいやの放置状態で勉強不足でした。

externを使いたくないのが理由で代わりにクラスのインスタンスを利用する事により始まった迷宮から、ようやっと抜け出せそうな気がします。

ポインタの基本は理解しているので結構利用していますが、同時にクラスの抽象・継承も使いこなして自分なりの改良を試みます。とは言っても、参考文献に関しては改良の余地はないですね。

今後も愚問・珍問等繰り返すかも知れませんが、よろしくお願いします。