メニュー選択画面について

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

メニュー選択画面について

#1

投稿記事 by poboro » 12年前

初めて質問させていただきます、C言語初心者です。
環境はwindowsでC++とDXライブラリを使用しています。

多人数で作成しているゲームに参加し、タイトル及びメニュー選択画面を担当しました。
ゲームプログラミングの館の説明を参考に作成したところ、最初に提出したものがループ内で画像のロードを大量に行っておりかなり重い物になってしまったため訂正を行いました。ですが、この訂正方法が正しいのかがよくわかりません。
細かく言うと、画像のロードをループから出して描画ループの最初に置いたのですが(下記コードの384~389行目です)、これを提出した場合他の人のプログラムと合わせることができるのかが不安なのです。描画ループは1つのゲームで共有するわけですよね。
これ全体を1つの関数として提出後にメインループに入れてもらおうとも思ったのですが、その場合のスイッチの設置の仕方がよくわからず、結局この状態で止まってしまいました。
このまま再提出してしまっても大丈夫なのでしょうか?ご指摘よろしくお願いします。

以下コードです。長いですがどこを切ったら大丈夫なのかがわからず不安なため全て載せます。申し訳ありません。
コンフィグやステージ等自分が作っていない部分は文字表示のみにしてあります。

コード:

#include "DxLib.h"

enum {
	STATE_TITLE,
	STATE_MENU,
	STATE_CONFIG,
	STATE_EXIT,
	STATE_SELECTL,
	STATE_SELECTS,
	STATE_STAGE1,
	STATE_STAGE2,
	STATE_STAGE3,
	STATE_STAGE4,
	STATE_FINALSTAGE,
	STATE_NORMAL,
	STATE_HARD,
};

int function_status=STATE_TITLE,White;
int Key[256];
char KeyBuf[256];
int Count;

/*項目移動用設定*/

int i,j;
int SelectNum;
int iy;

/*画像用設定*/

int SBACK;
int	MBACK;
int Icon;
int LiImage[6];
int LeImage[5];
int StImage[6];

/*キー入力状態確認*/

int gpUpdateKey(){
	char tmpKey[256];
	GetHitKeyStateAll( tmpKey );
	for(i=0; i<256; i++ ){ 
		if( tmpKey[i] != 0 ){ 
			Key[i]++; 
		} else {         
			Key[i] = 0;
		}
	}
	return 0;
}

/*メニュー項目用*/

typedef struct{ 
	int x, y;    
	int PICTURE; 
} MenuElement_t ;

/*タイトル画面*/

int title(){
	while( CheckHitKeyAll() == 0 ){           
		if( ProcessMessage() != 0 ) break ;

		DrawGraph( 0, 0, SBACK,FALSE ) ;

		return STATE_TITLE;

	}

	return STATE_MENU;
}

/*メニュー画面*/

int menu(){

	SelectNum = 0;
	iy = 230;

	MenuElement_t MenuElement[4]={
		{ 270, 220, LiImage[0] },
		{ 290, 270, LiImage[1] },
		{ 290, 320, LiImage[4] },
		{ 290, 370, LiImage[5] },
	};

	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && 

		gpUpdateKey()==0 && Count >= 3 ){

			if( Key[ KEY_INPUT_DOWN ] == 1 ){ 
				SelectNum = ( SelectNum + 1 ) % 4; 
			}

			if( Key[ KEY_INPUT_UP ] == 1 ){ 
				SelectNum = ( SelectNum + 3 ) % 4; 
			}

			if( Key[ KEY_INPUT_DOWN ] == 1 || Key[ KEY_INPUT_UP ] == 1 ){ 
				for( i=0; i<4; i++ ){         
					if( i == SelectNum ){       
						MenuElement[i].x = 270;
					} else {         
						MenuElement[i].x = 290;
					}
				}
			}

			if( Key[ KEY_INPUT_Z ] == 1){
				if( SelectNum == 0){
					return STATE_SELECTL;
				}
				else if( SelectNum == 1){
					return STATE_SELECTS;
				}
				else if( SelectNum == 2){
					return STATE_CONFIG;
				}
				else if( SelectNum == 3){
					return STATE_EXIT;
				}

			}

			DrawGraph( 0, 0, MBACK,FALSE ) ;
			DrawGraph( 240, iy, Icon,TRUE);

			if(Key[KEY_INPUT_DOWN] == 1 && iy == 380){
				iy = 230;
			}
			else if(Key[KEY_INPUT_DOWN] == 1){
				iy += 50;
			}


			if(Key[KEY_INPUT_UP] == 1 && iy == 230){
				iy = 380;
			}
			else if(Key[KEY_INPUT_UP] == 1){
				iy -= 50;
			}

			for( j=0; j<4; j++ ){ 
				DrawGraph( MenuElement[j].x, 

					MenuElement[j].y, MenuElement[j].PICTURE,TRUE ) ;

			}

	}

	Count ++;
	return STATE_MENU;
}

/*コンフィグ画面*/

int config(){
	DrawString(100,100,"coufig",White);
	return STATE_CONFIG;
}

/*ゲーム終了・エンディング画面*/

int exit(){
	DrawString(100,100,"exit",White);
	return STATE_EXIT;
}

/*レベル選択画面*/

int selectl(){

	SelectNum = 0;
	iy = 260;

	MenuElement_t MenuElement[5]={
		{ 270, 250, LeImage[1] },
		{ 290, 300, LeImage[2] },
		{ 290, 350, LeImage[4] },
	}; 

	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && 

		gpUpdateKey()==0 ){

			if( Key[ KEY_INPUT_DOWN ] == 1 ){ 
				SelectNum = ( SelectNum + 1 ) % 3; 
			}

			if( Key[ KEY_INPUT_UP ] == 1 ){ 
				SelectNum = ( SelectNum + 2 ) % 3; 
			}

			if( Key[ KEY_INPUT_DOWN ] == 1 || Key[ KEY_INPUT_UP ] == 1 ){ 
				for( i=0; i<3; i++ ){         
					if( i == SelectNum ){       
						MenuElement[i].x = 270; 
					} else {         
						MenuElement[i].x = 290;
					}
				}
			}

			if( Key[ KEY_INPUT_Z ] == 1){
				if( SelectNum == 0){
					return STATE_NORMAL;
				}
				else if( SelectNum == 1){
					return STATE_HARD;
				}
				else if( SelectNum == 2){
					return STATE_MENU;
				}

			}

			DrawGraph( 0, 0, MBACK,FALSE ) ;
			DrawGraph( 240, iy, Icon,TRUE);

			if(Key[KEY_INPUT_DOWN] == 1 && iy == 360){
				iy = 260;
			}
			else if(Key[KEY_INPUT_DOWN] == 1){
				iy += 50;
			}


			if(Key[KEY_INPUT_UP] == 1 && iy == 260){
				iy = 360;
			}
			else if(Key[KEY_INPUT_UP] == 1){
				iy -= 50;
			}


			for( j=0; j<3; j++ ){ 
				DrawGraph( MenuElement[j].x, 

					MenuElement[j].y, MenuElement[j].PICTURE,TRUE ) ;

			}


	}
	return STATE_SELECTL;
}

/*ステージ選択画面*/

int selects(){

	SelectNum = 0;
	iy = 175;

	MenuElement_t MenuElement[6]={
		{ 270, 160, StImage[0] },
		{ 290, 210, StImage[1] },
		{ 290, 260, StImage[2] },
		{ 290, 310, StImage[3] },
		{ 290, 360, StImage[4] },
		{ 290, 410, StImage[5] },
	};

	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && 

		gpUpdateKey()==0 ){

			if( Key[ KEY_INPUT_DOWN ] == 1 ){ 
				SelectNum = ( SelectNum + 1 ) % 6; 
			}

			if( Key[ KEY_INPUT_UP ] == 1 ){ 
				SelectNum = ( SelectNum + 5 ) % 6; 
			}

			if( Key[ KEY_INPUT_DOWN ] == 1 || Key[ KEY_INPUT_UP ] == 1 ){ 
				for(i=0; i<6; i++ ){         
					if( i == SelectNum ){       
						MenuElement[i].x = 270; 
					} else {         
						MenuElement[i].x = 290;
					}
				}
			}

			if( Key[ KEY_INPUT_Z ] == 1){
				if( SelectNum == 0){
					return STATE_STAGE1;
				}
				else if( SelectNum == 1){
					return STATE_STAGE2;
				}
				else if( SelectNum == 2){
					return STATE_STAGE3;
				}
				else if( SelectNum == 3){
					return STATE_STAGE4;
				}
				else if( SelectNum == 4){
					return STATE_FINALSTAGE;
				}
				else if( SelectNum == 5){
					return STATE_MENU;
				}
			}

			DrawGraph( 0, 0, MBACK,FALSE ) ;
			DrawGraph( 240, iy, Icon,TRUE);

			if(Key[KEY_INPUT_DOWN] == 1 && iy == 425){
				iy = 175;
			}
			else if(Key[KEY_INPUT_DOWN] == 1){
				iy += 50;
			}


			if(Key[KEY_INPUT_UP] == 1 && iy == 175){
				iy = 425;
			}
			else if(Key[KEY_INPUT_UP] == 1){
				iy -= 50;
			}

			for( j=0; j<7; j++ ){ 
				DrawGraph( MenuElement[j].x,
					MenuElement[j].y, MenuElement[j].PICTURE,TRUE ) ;

			}


	}
	return STATE_SELECTS;
}

/*各ステージ*/

int stage1(){
	DrawString(100,100,"stage1",White);
	return STATE_STAGE1;
}
int stage2(){
	DrawString(100,100,"stage2",White);
	return STATE_STAGE2;
}
int stage3(){
	DrawString(100,100,"stage3",White);
	return STATE_STAGE3;
}
int stage4(){
	DrawString(100,100,"stage4",White);
	return STATE_STAGE4;
}
int finalstage(){
	DrawString(100,100,"finalstage",White);
	return STATE_FINALSTAGE;
}

/*各レベル*/

int normal(){
	DrawString(100,100,"normal",White);
	return STATE_NORMAL;
}
int hard(){
	DrawString(100,100,"hard",White);
	return STATE_HARD;
}

/*描写ループ*/

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int 
	nCmdShow ){
		ChangeWindowMode( TRUE ) ;                      
		DxLib_Init();        

		SetDrawScreen( DX_SCREEN_BACK ) ;                   

		White = GetColor( 255 , 255 , 255 ) ; 
		SBACK = LoadGraph( "startback.png" );
		MBACK = LoadGraph( "menuback.png" );
		Icon = LoadGraph("icon.png");
		LoadDivGraph( "ListParts.png", 6, 1, 6, 330, 58, LiImage) ;
		LoadDivGraph( "LevelParts.png",5, 1, 5, 312, 60, LeImage) ;
		LoadDivGraph( "StageParts.png",6, 1, 6, 312, 60, StImage) ;

		while( 1 ){
			ClearDrawScreen();                                                  
			GetHitKeyStateAll( KeyBuf ) ;               

			switch(function_status){
			case STATE_TITLE:
				function_status = title();
				break;
			case STATE_MENU:
				function_status = menu();
				break;
			case STATE_CONFIG:
				function_status = config();
				break;
			case STATE_EXIT:
				function_status = exit();
				break;
			case STATE_SELECTL:
				function_status = selectl();
				break;
			case STATE_SELECTS:
				function_status = selects();
				break;
			case STATE_STAGE1:
				function_status = stage1();
				break;
			case STATE_STAGE2:
				function_status = stage2();
				break;
			case STATE_STAGE3:
				function_status = stage3();
				break;
			case STATE_STAGE4:
				function_status = stage4();
				break;
			case STATE_FINALSTAGE:
				function_status = finalstage();
				break;
			case STATE_NORMAL:
				function_status = normal();
				break;
			case STATE_HARD:
				function_status = hard();
				break;
			default:
				DxLib_End() ;                      
				return 0;
				break;
			}

			if( ProcessMessage() == -1 ) break ;   

			ScreenFlip() ;   
		}

		DxLib_End() ;                         
		return 0 ;                                      
}

アバター
馬場自由
記事: 15
登録日時: 12年前

Re: メニュー選択画面について

#2

投稿記事 by 馬場自由 » 12年前

ざっくりとした感想です。
ループ外にロード処理を出してしまうのもひとつの手段ですが、これだとゲーム開始から終了まで
余分なデータを持って回ることになり、メモリを圧迫するので、ステージを切り替えるゲームではオススメできません。
ループ文中で必要なときだけロード処理と開放処理を呼ぶように、設計を直したほうが良いです。

また、見た感じ同じようなループを別々の関数で複数通っているようなので、そこも設計を
練り直すべきだと思います。

コード:

// この処理を別関数に作り直して呼び出し順を整理する
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 &&
 ...
 
この処理とか。


>全体を1つの関数として提出後にメインループに入れてもらう

意味を持つ一纏まりごとに関数を分けたほうが、修正しやすくなると思います。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: メニュー選択画面について

#3

投稿記事 by softya(ソフト屋) » 12年前

まず、この作りかたは良くないです。
本当はプログラマーのリーダーが決めて通達すべき部分ですが、
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 &&
が多数あるプログラムを組むと切り替えタイミングや終了処理でバグが凄く出やすくなります。

なので、次のことを守ったほうが良いでしょう。
「補足資料.11章 書いてはいけない4つの処理」
http://dixq.net/g/h_11.html

こちらのゲームプログラミング設計を参考にされると良いと思います。
http://dixq.net/g/
d.1 メイン関数の作り方
d.2 複数のファイルにわけてコンパイルする
d.3 ゲームの設計と分割コンパイル(1)
d.4 ゲームの設計と分割コンパイル(2)
d.5 ゲームの設計と分割コンパイル(3)
d.6 管理部の作り方 (似た要素のまとめ方)

ただ、チームの都合があると思うので必ずチームで相談して下さい。それが一番重要です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

poboro

ありがとうございました

#4

投稿記事 by poboro » 12年前

馬場自由さん、softyaさん、ご指摘ありがとうございました。
指摘内容を参考にしつつ、まずはメイン関数の作り方からじっくり学んで、もう一度取り組んでみようと思います。

閉鎖

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