スタート画面を作っているのですが・・・

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

スタート画面を作っているのですが・・・

#1

投稿記事 by 名無し » 17年前

スタート画面を作っているのですが、スタート画面でcontinueを選んで、
enterを押すとロード画面に行くようにしているのですが、enterを二回押さないと
ロード画面に行きません。なぜなのでしょうか?お願いします。以下ソースです。

-----start.cpp--------
#include"DxLib.h"

void choice(int y,int str1,int str2)
{
	LoadGraphScreen(215,y,"hagure.bmp",TRUE);
        DrawFormatStringToHandle(220,120,GetColor(255,255,255),str1,"UNTITLED");
	DrawFormatStringToHandle(250,260,GetColor(255,255,255),str2,"START");
	DrawFormatStringToHandle(250,280,GetColor(255,255,255),str2,"CONTINUE");
}

void ContinueScreen(int str1)
{
	ClearDrawScreen();
	DrawFormatStringToHandle(220,120,GetColor(255,255,255),str1,"ロード画面");
	WaitKey();
}
	

	
void start(void)
{ 
	int str1,str2,y=260;
	int DownOshita=0,NewDown=0,OldDown=0,DownPusingCounter=0;
	int UpOshita=0,NewUp=0,OldUp=0,UpPushingCounter=0;
	char keybuf[256];
	
	str1=CreateFontToHandle("MS 明朝",40,5,DX_FONTTYPE_NORMAL);
	str2=CreateFontToHandle("MS 明朝",20,3,DX_FONTTYPE_NORMAL);
	
	SetDrawScreen( DX_SCREEN_BACK ) ;                        // 描画先を裏画面に設定
	
	while(1){
		ClearDrawScreen();                               // 裏画面のデータを全て削除
		GetHitKeyStateAll( keybuf ) ;                    // すべてのキーの状態を得る
		if( keybuf[ KEY_INPUT_ESCAPE ] == 1 ) exit(1);    // Escapeが押されたら終了
		
		choice(y,str1,str2);
		
		/*下キー判定*/
		if( keybuf[ KEY_INPUT_DOWN ] == 1 )              // 下キーが押されたら
                        NewDown=1;                                  // 今押されている状態に
                else                                             // 押されていなかったら
                        NewDown=0;                                  // 今押されていない状態に
                                
                if( OldDown==0 && NewDown==1 )                   // 前回押されてなく、今回押されていたら
                        DownOshita=1;                               // たった今押された状態に
                else                                             // それ以外なら
                        DownOshita=0;                               // たったいま押されていない状態に
                                
                if( OldDown==1 && NewDown==1 )                   // 前回も押され、今回も押されていたら
                        DownPusingCounter++;                        // 押しっぱなしカウンターを増加
                else
                        DownPusingCounter=0;

                if( DownOshita==1 || DownPusingCounter>30){      // たった今押したか、30カウンター以上押しっぱなしなら
                        if(DownPusingCounter>30)                 // 30カウンター以上押しっぱなしならカウンターを27へ
                                DownPusingCounter=27;            // オートの場合4回に1回下に下がる。
                        if(y==260)y=280;                                           
                        else                                     // y座標が280なら(選択が一番下なら)
                                y=260;                           // 選択座標を一番上に
                }
                OldDown=NewDown;
		
		/*上キー判定*/
		if(keybuf[KEY_INPUT_UP]==1) NewUp=1;
		else NewUp=0;
		
		if(OldUp==0 && NewUp==1) UpOshita=1;
		else UpOshita=0;
		
		if(OldUp==1 && NewUp==1) UpPushingCounter++;
		else UpPushingCounter=0;
		
		if(UpOshita==1 || UpPushingCounter>30){
			if(UpPushingCounter>30) UpPushingCounter=27;
			
			if(y==280) y=260;
			else y=280;
		}
		OldUp=NewUp;
		
		if(keybuf[KEY_INPUT_RETURN]==1 && y==280)
			ContinueScreen(str1);
			
		
		if( ProcessMessage() == -1 ) break ;             //エラーが起きたら終了
		ScreenFlip() ;                                   // 裏画面データを表画面へ反映
        }
 
}

管理人

Re:スタート画面を作っているのですが・・・

#2

投稿記事 by 管理人 » 17年前

このままだと汎用性が無いですし、とても見にくいコードになっていますので、
キーの入力状態を格納する関数key_checkを作ってみました。
十字キーの「下キー」を押したり、押しっぱなしにしたりしてみてください。



GetHitKeyStateAll( now_key );//キー入力状態をnow_keyに格納

だけでは、0か1しかはいりませんから、今入力されたのか、どれ位押しっぱなしだったのかわかりません。
そこで、int keybuf[256]を用意し押されたカウントだけカウント数を格納する関数を作ってみます。

以下実装してみましたので、よければお使い下さい。
これを使って作り直したほうがずっと見やすくなると思います。
重複しますが、keybufに入っている数字は押しっぱなしにしたカウント数です。
0だと押されていません。60Hzのモニタなら、keybuf[KEY_INPUT_DOWN]==60ならば1秒間押しっぱなしにしたことになります。
#include "DxLib.h"

void key_check(int key[/url]){
	int i;
	char now_key[256];

	GetHitKeyStateAll( now_key );//キー入力状態をnow_keyに格納

	for(i=0;i<256;i++){
		if(now_key==1)//押されていたら
			key++;//カウントアップ
		else//押されていなければ
			key=0;//0に
	}
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
	int keybuf[256]={},y=100;
    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
    SetDrawScreen( DX_SCREEN_BACK );        //裏画面に設定

    while(!ProcessMessage() && !ClearDrawScreen() && !keybuf[KEY_INPUT_ESCAPE]){

		key_check(keybuf);//キーの入力状態チェック
		
		if(keybuf[KEY_INPUT_DOWN]==1)//たった今入力されたら
			y+=20;
		if(keybuf[KEY_INPUT_DOWN]>40)//40カウント以上押し続けたら
			y+=20;
		if(y>380)
			y=100;

		DrawCircle(100,y,5,GetColor(255,255,255),TRUE);//円を描画
		
		ScreenFlip();//裏画面反映
    }

    DxLib_End();
    return 0;
}

名無し

Re:スタート画面を作っているのですが・・・

#3

投稿記事 by 名無し » 17年前

管理人さんのを使わせてもらったらうまく行きました!
ありがとうございました。

一応ソースを
#include"DxLib.h"

void choice(int y,int str1,int str2)
{
	LoadGraphScreen(215,y,"hagure.bmp",TRUE);
        DrawFormatStringToHandle(220,120,GetColor(255,255,255),str1,"UNTITLED");
	DrawFormatStringToHandle(250,260,GetColor(255,255,255),str2,"START");
	DrawFormatStringToHandle(250,280,GetColor(255,255,255),str2,"CONTINUE");
}

void key_check(int key[/url]){
	int i;
	char now_key[256];

	GetHitKeyStateAll( now_key );//キー入力状態をnow_keyに格納

	for(i=0;i<256;i++){
		if(now_key==1)//押されていたら
			key++;//カウントアップ
		else//押されていなければ
			key=0;//0に
	}
}


void ContinueScreen(int str1)
{
	while(!ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE) && !CheckHitKey(KEY_INPUT_BACK)){
		DrawFormatStringToHandle(220,120,GetColor(255,255,255),str1,"ロード画面");
		ScreenFlip();
	}
}
	

	
void start(void)
{ 
	int str1,str2,y=260;
	int keybuf[256];
	
	str1=CreateFontToHandle("MS 明朝",40,5,DX_FONTTYPE_NORMAL);
	str2=CreateFontToHandle("MS 明朝",20,3,DX_FONTTYPE_NORMAL);
	
	SetDrawScreen( DX_SCREEN_BACK ) ;                        // 描画先を裏画面に設定
	
	while(!ProcessMessage() && !ClearDrawScreen() && !keybuf[KEY_INPUT_ESCAPE]){
		key_check(keybuf);
		
		/*下キー判定*/
		if(keybuf[KEY_INPUT_DOWN]==1)		//たった今入力されたら
			y+=20;
		if(keybuf[KEY_INPUT_DOWN]>40)		//40カウント以上押し続けたら
                	y+=20;
		if(y>280) y=260;
		
		/*上キー判定*/
		if(keybuf[KEY_INPUT_UP]==1)
			y-=20;
		if(keybuf[KEY_INPUT_UP]>40)
			y-=20;
		if(y<260) y=280;
		
		choice(y,str1,str2);
		
		if(keybuf[KEY_INPUT_RETURN]==1 || keybuf[KEY_INPUT_RETURN]>40){
			if(y==280)
			ContinueScreen(str1);
		}
			
		ScreenFlip() ;                                   // 裏画面データを表画面へ反映
        }
 
}

管理人

Re:スタート画面を作っているのですが・・・

#4

投稿記事 by 管理人 » 17年前

while(!ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE) && !CheckHitKey(KEY_INPUT_BACK)){

このループはあちこちに書くものではないです。
WinMainなり、どこでもいいので、必ず一度返って来る関数を作ったほうがよりキレイになると思います。

ProcessMessage()やClearDrawScreen()はプログラムコードのどこか1箇所にだけかけばよく、
ずっと処理の返ってこないループがあちこちにあるとデバッグもやりにくくなりますし、
あちこちに同じ処理を書かないといけなくなるので非効率です。

ゲームプログラミングの館に「メイン関数の書き方」を紹介していますので、よければ参考にして下さい。

また

if(keybuf[KEY_INPUT_RETURN]==1 || keybuf[KEY_INPUT_RETURN]>40){

この>40の方の判定分は必要ですか?
40カウント以上エンターが押しっぱなしである必要は無いのではないでしょうか?

名無し

Re:スタート画面を作っているのですが・・・

#5

投稿記事 by 名無し » 17年前

すみません、こういう大きいプログラムを組むのは初めてなもので・・・
えっと、理解の仕方としては、WinMain関数にループを作り、グローバル変数で
いろいろな関数に行くように管理して、WinMain関数以外の他の関数のループから
他の関数のループはあまりよくないということなのでしょうか?

管理人

Re:スタート画面を作っているのですが・・・

#6

投稿記事 by 管理人 » 17年前

WinMainじゃなくてもいいと思いますが、あちこちに

while(!ProcessMessage() && !ClearDrawScreen() && !CheckHitKey(KEY_INPUT_ESCAPE) ・・・

のループを書くのはちょっと効率悪いですよね。
最初のうちは、メイン関数にだけ画面クリアや反映関数を書いておき、絶対ここに1周に一度返って来るようにプログラムを組んだほうがいいと思います。
自分なりの方法はそれを理解したうえで行った方がいいと思います。

誤解しないで貰いたいのが、for文やループ文を他の関数で使うなと言うことではありません。
色んなところに同じような機能を持ったプログラムを書くことが非効率的なので、
そのような重複は省きましょうということです。
とりあえず

ProcessMessage()
ClearDrawScreen()
ScreenFlip()

は、メイン関数で一度だけ書くようにしてプログラムを書いてみて下さい。


プログラムを書いていけば解るのですが、グローバル変数は多用しない方が関数が汎用的になります。
例えば先ほどのようなキーチェック関数など、自作した関数はいちいちコピペしなくても、自作ヘッダファイルを作ることで、その関数が利用できるようにすれば効率的ですよね。

先ほどの関数をkey.hみたいなファイルに保存しておき、#include "key.h"としてその関数をよんでやったりすれば、どんなプログラムからでも同じように使えるわけです。

しかし、そのプログラムによって変数名がかわり、その変数名ではないと機能しないような関数では、他で利用も出来ませんし、保守的な意味でもよくないです。なのでグローバル変数は必要最小限にした方がいいと思います。

名無し

Re:スタート画面を作っているのですが・・・

#7

投稿記事 by 名無し » 17年前

管理人さんのを参考にして改善しました。
すごくすっきりしてデバッグもしやすいです。
ありがとうございます。
---main.cpp---
#include "DxLib.h"
#include"global_define.h"
#include"Extern_etc.h"
#include"function.h"
#include"start.cpp"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{
	ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
        if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了
	SetDrawScreen( DX_SCREEN_BACK ) ;
	
	white=GetColor(255,255,255);
	str1=CreateFontToHandle("MS 明朝",40,5,DX_FONTTYPE_NORMAL);
	str2=CreateFontToHandle("MS 明朝",20,3,DX_FONTTYPE_NORMAL);
	
	while(!ProcessMessage() && !ClearDrawScreen() && !keybuf[KEY_INPUT_ESCAPE]){
		key_check(keybuf);
		switch(scene){
			case 0:
        			start();
				break;
			case 1:
				ContinueScreen();
				break;
			default:
                                DxLib_End() ;                                // DXライブラリ使用の終了処理
                                return 0;
                                break;
		}

			ScreenFlip() ;
	}
	WaitKey();
	DxLib_End();
	return 0;
}

---start.cpp---

#include"DxLib.h"
#include"Extern_etc.h"

void ContinueScreen()
{
	DrawFormatStringToHandle(220,120,white,str1,"ロード画面");
	if(keybuf[KEY_INPUT_BACK]==1) scene=0;
}
	

	
void start(void)
{ 
	
	LoadGraphScreen(215,y,"hagure.bmp",TRUE);
         DrawFormatStringToHandle(220,120,white,str1,"UNTITLED");
	DrawFormatStringToHandle(250,260,white,str2,"START");
	DrawFormatStringToHandle(250,280,white,str2,"CONTINUE");
		
		/*下キー判定*/
	if(keybuf[KEY_INPUT_DOWN]==1)		//たった今入力されたら
		y+=20;
	if(keybuf[KEY_INPUT_DOWN]>40)		//40カウント以上押し続けたら
               	y+=20;
	if(y>280) y=260;
	
		/*上キー判定*/
	if(keybuf[KEY_INPUT_UP]==1)
		y-=20;
	if(keybuf[KEY_INPUT_UP]>40)
		y-=20;
	if(y<260) y=280;
		
		
	if(keybuf[KEY_INPUT_RETURN]==1 ){
		if(y==280)
			scene=1;
	}
			      
 
}

閉鎖

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