ページ 11

選択画面を応用したプログラム C++

Posted: 2011年8月28日(日) 16:51
by ののき
新・ゲームプログラミングの館のソースを利用してプログラムを作ったのですが、動作せず、皆目分からない状態です。
希望する動作としては、
選択画面に表示されたゲームスタートの項目へとスクロールし、ESCキーを押す。
キーが押されたら、選択画面が消え、キャラクターを表示される。
というものです。
エラーメッセージには次のようなものが出ました。
c:\users\rain\documents\gameprog\test.cpp(63): error C2065: 'i' : 定義されていない識別子です。
c:\users\rain\documents\gameprog\test.cpp(63): error C2228: '.x' の左側はクラス、構造体、共用体でなければなりません



ご指導お願い致します。


コード:

#include "DxLib.h"

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey(){
        char tmpKey[256]; // 現在のキーの入力状態を格納する
        GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
        for( int i=0; i<256; i++ ){ 
                if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
                        Key[i]++;     // 加算
                } else {              // 押されていなければ
                        Key[i] = 0;   // 0にする
                }
        }
        return 0;
}

// メニュー項目の表示に必要な構造体を用意する
typedef struct{
        int x, y;       // 座標格納用変数
        char name[128]; // 項目名格納用変数
} MenuElement_t ;

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

        // メニュー項目要素を5つ作る
        MenuElement_t MenuElement[5]={
                {  80, 100, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
                { 100, 150, "おまけ" },
                { 100, 200, "ヘルプ" },
                { 100, 250, "コンフィグ" },
                { 100, 300, "ゲーム終了" },
        };
        int SelectNum = 0; // 現在の選択番号

        // while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 ){

                // 計算フェーズ 

                if( Key[ KEY_INPUT_DOWN ] == 1 ){ // 下キーが押された瞬間だけ処理

                        SelectNum = ( SelectNum + 1 ) % 5; // 現在の選択項目を一つ下にずらす(ループする)

                        for( int i=0; i<5; i++ ){              // メニュー項目数である5個ループ処理
                                if( i == SelectNum ){          // 今処理しているのが、選択番号と同じ要素なら
                                        MenuElement[i].x = 80; // 座標を80にする
                                } else {                       // 今処理しているのが、選択番号以外なら
                                        MenuElement[i].x = 100;// 座標を100にする
                                }
                        }
                }

                // 描画フェーズ

                for( int i=0; i<5; i++ ){ // メニュー項目を描画
                        DrawFormatString( MenuElement[i].x, MenuElement[i].y, GetColor(255,255,255), MenuElement[i].name );
                }
				while( 1 ){
                ProcessMessage();
                if(( CheckHitKey(KEY_INPUT_ESCAPE) == 1 )&&(MenuElement[i].x= 100)){
					 LoadGraphScreen( 50, 100, "画像/キャラクタ00.png", TRUE ); // 画像を描画する

                        break;
                }
        }


        }

        DxLib_End(); // DXライブラリ終了処理
        return 0;
}

Re: 選択画面を応用したプログラム C++

Posted: 2011年8月28日(日) 17:04
by softya(ソフト屋)
インデントが分かりづらかったので修正してあります。人に見せる場合は、ちゃんとしたインデントに補正してくださいね(自分だけの場合もちゃんとしたほうがバグが減ります)。

コード:

#include "DxLib.h"

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey(){
	char tmpKey[256]; // 現在のキーの入力状態を格納する
	GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
	for( int i=0; i<256; i++ ){ 
		if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
			Key[i]++;     // 加算
		} else {              // 押されていなければ
			Key[i] = 0;   // 0にする
		}
	}
	return 0;
}

// メニュー項目の表示に必要な構造体を用意する
typedef struct{
	int x, y;       // 座標格納用変数
	char name[128]; // 項目名格納用変数
} MenuElement_t ;

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

	// メニュー項目要素を5つ作る
	MenuElement_t MenuElement[5]={
		{  80, 100, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
		{ 100, 150, "おまけ" },
		{ 100, 200, "ヘルプ" },
		{ 100, 250, "コンフィグ" },
		{ 100, 300, "ゲーム終了" },
	};
	int SelectNum = 0; // 現在の選択番号

	// while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 ){

		// 計算フェーズ 

		if( Key[ KEY_INPUT_DOWN ] == 1 ){ // 下キーが押された瞬間だけ処理

			SelectNum = ( SelectNum + 1 ) % 5; // 現在の選択項目を一つ下にずらす(ループする)

			for( int i=0; i<5; i++ ){              // メニュー項目数である5個ループ処理
				if( i == SelectNum ){          // 今処理しているのが、選択番号と同じ要素なら
					MenuElement[i].x = 80; // 座標を80にする
				} else {                       // 今処理しているのが、選択番号以外なら
					MenuElement[i].x = 100;// 座標を100にする
				}
			}
		}

		// 描画フェーズ

		for( int i=0; i<5; i++ ){ // メニュー項目を描画
			DrawFormatString( MenuElement[i].x, MenuElement[i].y, GetColor(255,255,255), MenuElement[i].name );
		}
		while( 1 ){ ← このwhileループにの役目は?
			ProcessMessage(); ←なぜここに?
			if(( CheckHitKey(KEY_INPUT_ESCAPE) == 1 )&&(MenuElement[i].x= 100)){ ← エラー原因のiは同じブロックまたは上部ブロックに未定義です。別ブロックには存在します。
				LoadGraphScreen( 50, 100, "画像/キャラクタ00.png", TRUE ); // 画像を描画する

				break;
			}
		}


	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}

Re: 選択画面を応用したプログラム C++

Posted: 2011年8月28日(日) 19:34
by Dixq (管理人)
まず気になるのが、メインループの中に更に処理の返ってこないループがあることです。

ProcessMessageが二か所にあるのは何故でしょうか。
また、二重ループから抜ける処理の中に比較ではなく代入が行われているので、期待の動作になっていないと思います。
更にMenuElement.xがこのループ内で変化することもないでしょう。

ScreenFlip()
ProcessMessage()
ClearDrawScreen()
gpUpdateKey()

の4処理が一ループで一度呼ばれなければならないことに注意して下さい。
ループの特定部分で処理を止める設計はよくありません。

特定の条件によって特定の動作をさせるには、
特定の部分で処理を止めるのではなく、フラグか何かを用意して、
そのフラグなどに応じた関数呼び出し等を行って制御するようにして下さい。

特定のキー操作に応じて異なる操作をする一例を書いてみました。

コード:

#include "DxLib.h"

enum STATUS{
	STATUS_SHOW_MENU,
	STATUS_SHOW_CHARA,
};

int Key[256]; // キーが押されているフレーム数を格納する
STATUS Status = STATUS_SHOW_MENU;

// キーの入力状態を更新する
int gpUpdateKey(){
	char tmpKey[256]; // 現在のキーの入力状態を格納する
	GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
	for( int i=0; i<256; i++ ){ 
		if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
			Key[i]++;     // 加算
		} else {              // 押されていなければ
			Key[i] = 0;   // 0にする
		}
	}
	return 0;
}

void ShowMenu(){
	if( Key[ KEY_INPUT_Z] == 1 ){
		Status = STATUS_SHOW_CHARA;
	}
	DrawString(0,0,"メニュー表示中",GetColor(255,255,255));
}

void ShowChara(){
	if( Key[ KEY_INPUT_X] == 1 ){
		Status = STATUS_SHOW_MENU;
	}
	DrawString(0,0,"キャラ表示中",GetColor(255,255,255));
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
	ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); 

	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 ){
		switch( Status ){
			case STATUS_SHOW_MENU:
				ShowMenu();
				break;
			case STATUS_SHOW_CHARA:
				ShowChara();
				break;
		}
	}

	DxLib_End();
	return 0;
}
ZキーとXキーを交互に押してみて下さい。
押したタイミングでコールされる関数が変わり、別の処理がされているのが分かります。

これはサンプルですので、設計される際はこのまま使われないようお気を付けください。

Re: 選択画面を応用したプログラム C++

Posted: 2011年8月29日(月) 02:15
by ののき
dixq様に申し訳ないのですが、ゲームプログラミングの館のソースと返信の内容のコードを組み合わせ、修正いたしました。
期待する動作としては、
選択画面の状態からxボタンを押すと、キャラ表示と書かれた画面へと移行することです。

しかし、実行したところ、
選択画面は表示されたのですが、xボタンを押してもキャラ表示と書かれた画面へと移行しません。

これは何が問題なのでしょうか。

コード:

#include "DxLib.h"
 
enum STATUS{ //列挙型(enum)は、一定の範囲の値を保持するためのデータ型です。

    STATUS_SHOW_MENU,
    STATUS_SHOW_CHARA,
};
 
int Key[256]; // キーが押されているフレーム数を格納する
STATUS Status = STATUS_SHOW_MENU;
 
// キーの入力状態を更新する
int gpUpdateKey(){
    char tmpKey[256]; // 現在のキーの入力状態を格納する
    GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
    for( int i=0; i<256; i++ ){ 
        if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
            Key[i]++;     // 加算
        } else {              // 押されていなければ
            Key[i] = 0;   // 0にする
        }
    }
    return 0;
}
 


void ShowMenu(){
if( Key[ KEY_INPUT_Z] == 1 ){
        Status = STATUS_SHOW_CHARA;
    }


// メニュー項目の表示に必要な構造体を用意する
typedef struct{
        int x, y;       // 座標格納用変数
        char name[128]; // 項目名格納用変数
} MenuElement_t ;

// メニュー項目要素を5つ作る
        MenuElement_t MenuElement[5]={
                {  80, 100, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
                { 100, 150, "おまけ" },
                { 100, 200, "ヘルプ" },
                { 100, 250, "コンフィグ" },
                { 100, 300, "ゲーム終了" },
        };
        int SelectNum = 0; // 現在の選択番号

        // while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)
        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 ){

		
                // 計算フェーズ 
			 

                if( Key[ KEY_INPUT_DOWN ] == 1 ){ // 下キーが押された瞬間だけ処理

                        SelectNum = ( SelectNum + 1 ) % 5; // 現在の選択項目を一つ下にずらす(ループする)

                        for( int i=0; i<5; i++ ){              // メニュー項目数である5個ループ処理
                                if( i == SelectNum ){          // 今処理しているのが、選択番号と同じ要素なら
                                        MenuElement[i].x = 80; // 座標を80にする
                                } else {                       // 今処理しているのが、選択番号以外なら
                                        MenuElement[i].x = 100;// 座標を100にする
                                }
                        }
                }

                // 描画フェーズ

                for( int i=0; i<5; i++ ){ // メニュー項目を描画
                        DrawFormatString( MenuElement[i].x, MenuElement[i].y, GetColor(255,255,255), MenuElement[i].name );
                }
				


        }
			
}

void ShowChara(){
    if( Key[ KEY_INPUT_X] == 1 ){
        Status = STATUS_SHOW_MENU;
    }
    DrawString(0,0,"キャラ表示中",GetColor(255,255,255));
}
 
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); 
 
    while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 ){
        switch( Status ){
            case STATUS_SHOW_MENU:
                ShowMenu();
                break;
            case STATUS_SHOW_CHARA:
                ShowChara();
                break;
        }
    }
 
    DxLib_End();
    return 0;
}

Re: 選択画面を応用したプログラム C++

Posted: 2011年8月29日(月) 02:28
by h2so5
ループが二つあるのがまずおかしいです。
ShowMenu()内のループから抜け出せないので、ShowChara()が呼び出せません。

ShowMenu内にループを入れないでください。

Re: 選択画面を応用したプログラム C++

Posted: 2011年8月29日(月) 19:15
by Dixq (管理人)
まず、回答で

・インデントをきちんと行うこと
・特定の箇所でループして処理を止めるような設計にしないこと
・ProcessMessageを2か所で書かないこと

が上がっていますが、コードに適用されていますか?

ScreenFlip()
ProcessMessage()
ClearDrawScreen()
gpUpdateKey()

の4大処理は1か所にしか書かないようにして下さい。
もし複数個所に出現した時はそれは設計が変です。

私が提示したサンプルはShowMenu();およびShowChara();がすぐ返ってくることを期待しています。
しかし、whileで処理を止めてはメインの処理に返って来ません。
特に今回の場合、ShowMenu関数内のループから出ることは、何らかのエラーを発生させる以外にありません。

もし処理が行われている順番が分からなければF10キーを押してステップ実行して1ステップずつ処理を確認して下さい。

Re: 選択画面を応用したプログラム C++

Posted: 2011年8月30日(火) 10:41
by ののき
show Menu()内の
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 )
を消したところ、正常に作動いたしました。

while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 )
をループ内に入れることで、処理が止まってしまうことは初めて知ったので、今回のご指導は大変参考になりました。

初心者なものですが丁寧に教えて頂き、どうもありがとうございます。