ページ 11

別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月26日(火) 19:29
by フィア
IDとパスの入力欄をGetKeyInputString等を使って2つ作ってIDのほうで入力していた時に入力完了させるにはエンターキーを最後に押すことで入力完了になるとは思いますが、

エンターキーを押さなくても入力欄とは別の場所をクリックすることで入力完了にしたいのですがどうすればいいかがわかりません

どのようにすれば別の場所をクリックされたら入力途中から入力完了になりますか?

コード:

int login_pont(void){

	int MouX,MouY;

	while(ProcessMessage() == 0 ){
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) {
			GetMousePoint( &MouX, &MouY );

			if( ( ( SCREEN_X / 2 - 90 ) < MouX && MouX < ( SCREEN_X / 2 + 90 ) )&&
				( ( SCREEN_Y / 2 + 25 ) < MouY && MouY < ( SCREEN_Y / 2 + 45 ) ) ){
				return 0;	//ゲーム終了
			}

			else if( ( ( SCREEN_X / 2 - 87 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 - 22 ) < MouY && MouY < ( SCREEN_Y / 2 -  2 ) ) ){
				return 1;	//ログインボックス
			}

			else if( ( ( SCREEN_X / 2 - 87 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 +  2 ) < MouY && MouY < ( SCREEN_Y / 2 + 22 ) ) ){
				return 2;	//パスボックス
			}

			else if( ( ( SCREEN_X / 2 + 41 ) < MouX && MouX < ( SCREEN_X / 2 + 89 ) )&&
					 ( ( SCREEN_Y / 2 - 24 ) < MouY && MouY < ( SCREEN_Y / 2 + 24 ) ) ){
				return 3;	//入力完了
			}

			else{
				return 4;
			}
		}
	}
	return 0;
}

int login(void){

	int black = GetColor(0,0,0);
	int white = GetColor(255,255,255);
	int white_s = GetColor(254,254,254);
	int blue = GetColor(0,0,255);
	int blue_s = GetColor(96,96,255);
	int red = GetColor(255,0,0);

	char id_buf[26]="";
	char pass_buf[26]="";
	int	itihan = NULL;

	int kaku;

	SetTransColor(80,80,40);

	int read = LoadGraph( "itt.bmp" );
	int log= LoadGraph( "log_k.bmp" );

	SetDrawScreen( DX_SCREEN_BACK );
	SetMouseDispFlag( TRUE );

	int id_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );
	int pass_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );

	char *id_m ="IDを入力してください";
	char *pa_m ="PASSを入力してください";
	char *ip_m ="IDもしくはPASSが違います";

	int id_n = GetDrawStringWidth( id_m , strlen( id_m ) ) ;
	int pa_n = GetDrawStringWidth( pa_m , strlen( pa_m ) ) ;
	int ip_n = GetDrawStringWidth( ip_m , strlen( ip_m ) ) ;

	SetKeyInputStringColor(
		black, //文字色
		black, //変換しない場合の右の線の色
		white_s, //変換中の変換候補の背景色
		black, //変換中の右の線の色
		white, //変換中のアンダーライン
		blue_s,   //変換中の文字の色
		white,  //???
		white,  //???
		white,  //???
		white,  //???
		blue, //変換中の枠の色
		white_s //変換中の背景色
	);
	
	DrawGraph( 0  , 0 , read , FALSE ) ;
	DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , log , TRUE ) ;

	ScreenFlip();

	while(ProcessMessage() == 0 ){
		itihan =login_pont();

		if( itihan == 0){ //ゲーム終了ボタンが押される
			return 999; //ゲーム終了
		}

		if( itihan == 1){ //IDボックスの位置が押される
			SetActiveKeyInput( id_s );

			while(ProcessMessage() == 0 ){
				if( CheckKeyInput( id_s ) !=0 ){
					if(itihan != 1 ){
						//別の場所をクリックされたら入力途中から入力完了にしたい

						GetKeyInputString( id_buf , id_s );
						break;
					}

					GetKeyInputString( id_buf , id_s );
					break;
				}

				DrawGraph( 0  , 0 , read , FALSE );
				DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , log , TRUE );

				if( strcmp(pass_buf,"") !=0){
					DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , pass_buf, black );				
				}

				DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 - 20 , id_s ) ;

				ScreenFlip() ;
			}
		}

		if( itihan == 2){ //パスボックスの位置が押される
			
			SetActiveKeyInput( pass_s );

			while(ProcessMessage() == 0 ){
				if( CheckKeyInput( pass_s ) != 0 ){
					if( itihan != 2 ){
						//別の場所をクリックされたら入力途中から入力完了にしたい

						GetKeyInputString( pass_buf , pass_s );
						break;
					}
	

					GetKeyInputString( pass_buf , pass_s );
					break;
				}

				DrawGraph( 0  , 0 , read , FALSE ) ;
				DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , log , TRUE ) ;
				
				if( strcmp(id_buf,"") !=0){
					DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 -20 , id_buf, black );				
				}

				// 入力途中の文字列を描画
				DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +  4 , pass_s ) ;

				ScreenFlip();
			}
		}

		if( itihan == 3 ){	//ログインボタンが押される
			GetKeyInputString( id_buf ,	id_s );
			GetKeyInputString( pass_buf , pass_s );

			if( ( strcmp( id_buf , "test" ) == 0 ) && ( strcmp( pass_buf , "test" ) == 0 ) ){
				InitKeyInput();

				return 1; //キャラクタ選択画面
			}

			else if( strcmp( id_buf , "" ) == 0 ){
				DrawString( SCREEN_X / 2 - id_n / 2 , SCREEN_Y / 2 -64 , id_m, red );
				ScreenFlip();
			}

			else if( strcmp( pass_buf , "" ) == 0 ){
				DrawString( SCREEN_X / 2 - pa_n / 2 , SCREEN_Y / 2 -64 , pa_m, red );
				ScreenFlip();
			}

			else {
				DrawString( SCREEN_X / 2 - ip_n / 2 , SCREEN_Y / 2 -64 , ip_m, red );
				ScreenFlip();
			}

		}
	}
	return 0;
}

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月27日(水) 10:51
by softya(ソフト屋)
すいません。出来るだけそのままコンパイルして動かせるものを貼ってもらえませんか。

それと下記の問題に該当しております。
「補足資料.11章 書いてはいけない4つの処理」
http://dixq.net/g/h_11.html
IDとパスの入力欄をGetKeyInputString等を使って2つ作ってIDのほうで入力していた時に入力完了させるにはエンターキーを最後に押すことで入力完了になるとは思いますが、エンターキーを押さなくても入力欄とは別の場所をクリックすることで入力完了にしたいのですがどうすればいいかがわかりません
動かせないので勘での回答です。
GetKeyInputString()では入力途中でもキー入力の値は得ることはできます。
なので、別の場所をクリックした時にGetKeyInputString()で入力値を得れば良いのでは無いでしょうか?
不要なハンドル自体はDeleteKeyInput()で閉じてしまえば良いと思います。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月27日(水) 18:03
by ISLe
ゲームプログラムでは、すべての事象が同時に並行して進行するように作成しなければいけません。
その上で、分岐命令を使い、現在進行して欲しい処理だけが進行するように振り分けます。
それが基本中の基本です。

softyaさんが指摘している問題とは、それを実装するために守るべきルールです。

提示されたコードでは、文字列入力中に、画面のクリック場所を判定する処理が回りません。
このコードにさらにコードを追加して対応することは無駄を増やすことになります。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月28日(木) 05:45
by フィア
あれから画面のサイズを変更したのとプログラムの処理の手直し部分があったため使用部分の修正したのを書きますね。

コード:

#include "DxLib.h"

#define MOJI_SIZE 24 // 文字のサイズ
#define SCREEN_X 960 // 画面の横幅
#define SCREEN_Y 720 // 画面の縦幅
char script[10000]={0};//文字データ全体
char LoadFname[100];
int LoadFsize;

int DrawPointX , DrawPointY;	// 文字列描画の位置
int CP;	// 参照する文字列中の文字ポインタ

int MouX,MouY;

int white = GetColor(255,255,255);
int olcl = GetColor(128,128,255);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){

	int i = 0;

	int DrawPointX = 0;
	int	DrawPointY = 0;	// 文字列描画の位置
	int white = GetColor( 255 , 255 , 255 );

	int sin = 1; //ゲームの進行度
	bool end_sw = false;

	char fn[100] = "op.s";
	int z;
	
	SetMainWindowText("神さまの箱庭");
	SetOutApplicationLogValidFlag( FALSE ); //ログを出力しない
	SetBackgroundColor( 255, 255, 255 );
	SetGraphMode( SCREEN_X , SCREEN_Y , 16 );

	ChangeWindowMode( true );
	if( DxLib_Init() == -1 ){	// DXライブラリ初期化処理
		 return -1;				// エラーが起きたら直ちに終了
	}

	while(ProcessMessage() == 0){
		switch(sin){
			case 0: //ゲーム終了
				end_sw = true;
				break;
			
			//最初のシステム関係
			//OPデモ入れるべきだろうか? そんな技術ないくせに 入れるなら人員募集せねば
			case 1:	//ログイン画面
				sin = login();
				break;

			}

		if(end_sw == true){
			break;
		}
	}

	DxLib_End() ;				// DXライブラリ使用の終了処理

	return 0 ;					// ソフトの終了

}

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月28日(木) 05:47
by フィア

コード:

 
int login_pont(void){

	while(ProcessMessage() == 0 ){
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) {
			GetMousePoint( &MouX, &MouY );

			if( ( ( SCREEN_X / 2 - 90 ) < MouX && MouX < ( SCREEN_X / 2 + 90 ) )&&
				( ( SCREEN_Y / 2 + 25 ) < MouY && MouY < ( SCREEN_Y / 2 + 45 ) ) ){
				return 0;	//ゲーム終了
			}

			else if( ( ( SCREEN_X / 2 - 49 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 - 22 ) < MouY && MouY < ( SCREEN_Y / 2 -  2 ) ) ){
				return 1;	//IDボックス
			}

			else if( ( ( SCREEN_X / 2 - 49 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 +  2 ) < MouY && MouY < ( SCREEN_Y / 2 + 22 ) ) ){
				return 2;	//PASSボックス
			}

			else if( ( ( SCREEN_X / 2 + 41 ) < MouX && MouX < ( SCREEN_X / 2 + 89 ) )&&
					 ( ( SCREEN_Y / 2 - 24 ) < MouY && MouY < ( SCREEN_Y / 2 + 24 ) ) ){
				return 3;	//ログインボタン
			}

			else{
				return 4;
			}
		}
	}
	return 0;
}

int login(void){

	int black = GetColor(0,0,0);
	int white = GetColor(255,255,255);
	int white_s = GetColor(254,254,254);
	int blue = GetColor(0,0,255);
	int blue_s = GetColor(96,96,255);
	int red = GetColor(255,0,0);

	char id_buf[26] = "";
	char pass_buf[26] = "";
	int	itihan = NULL;

	SetTransColor(80,80,40);

	int read = LoadGraph( "itt.bmp" );
	int log= LoadGraph( "log_k.bmp" );

	SetDrawScreen( DX_SCREEN_BACK );
	SetMouseDispFlag( TRUE );

	int id_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );
	int pass_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );

	char *id_m ="IDを入力してください";
	char *pa_m ="PASSを入力してください";
	char *ip_m ="IDもしくはPASSが違います";

	int id_n = GetDrawStringWidth( id_m , strlen( id_m ) ) ;
	int pa_n = GetDrawStringWidth( pa_m , strlen( pa_m ) ) ;
	int ip_n = GetDrawStringWidth( ip_m , strlen( ip_m ) ) ;

	SetKeyInputStringColor(
		black, //文字色
		black, //変換しない場合の右の線の色
		white_s, //変換中の変換候補の背景色
		black, //変換中の右の線の色
		white, //変換中のアンダーライン
		blue_s,   //変換中の文字の色
		white,  //???
		white,  //???
		white,  //???
		white,  //???
		blue, //変換中の枠の色
		white_s //変換中の背景色
	);
	
	DrawGraph( 0  , 0 , read , FALSE ) ;
	DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , log , TRUE ) ;

	ScreenFlip();

	while(ProcessMessage() == 0 ){
		itihan =login_pont();

		if( itihan == 0){ //ゲーム終了ボタンが押される
			return 0; //ゲーム終了
		}

		if( itihan == 1){ //IDボックスの位置が押される
			SetActiveKeyInput( id_s );

			while(ProcessMessage() == 0 ){
				if( CheckKeyInput( id_s ) !=0 ){
					if(itihan != 1 ){
						//別の場所をクリックされたら入力途中から入力完了にしたい

						GetKeyInputString( id_buf , id_s );
						break;
					}

					GetKeyInputString( id_buf , id_s );
					break;
				}

				DrawGraph( 0  , 0 , read , FALSE );
				DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , log , TRUE );

				if( strcmp(pass_buf,"") !=0){
					DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , pass_buf, black );				
				}

				DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 - 20 , id_s ) ;

				ScreenFlip() ;
			}
		}

		if( itihan == 2){ //PASSボックスの位置が押される
			
			SetActiveKeyInput( pass_s );

			while(ProcessMessage() == 0 ){
				if( CheckKeyInput( pass_s ) != 0 ){
					if( itihan != 2 ){
						//別の場所をクリックされたら入力途中から入力完了にしたい

						GetKeyInputString( pass_buf , pass_s );
						break;
					}
	

					GetKeyInputString( pass_buf , pass_s );
					break;
				}

				DrawGraph( 0  , 0 , read , FALSE ) ;
				DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , log , TRUE ) ;
				
				if( strcmp(id_buf,"") !=0){
					DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 -20 , id_buf, black );				
				}

				// 入力途中の文字列を描画
				DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +  4 , pass_s ) ;

				ScreenFlip();
			}
		}

		if( itihan == 3 ){	//ログインボタンが押される
			GetKeyInputString( id_buf ,id_s );
			GetKeyInputString( pass_buf , pass_s );

			if( ( strcmp( id_buf , "test" ) == 0 ) && ( strcmp( pass_buf , "test" ) == 0 ) ){
				InitKeyInput();

				return 0; //キャラクタ選択画面に行く予定だけどゲーム終了
			}

			else if( strcmp( id_buf , "" ) == 0 ){
				DrawString( SCREEN_X / 2 - id_n / 2 , SCREEN_Y / 2 -64 , id_m, red );
				ScreenFlip();
			}

			else if( strcmp( pass_buf , "" ) == 0 ){
				DrawString( SCREEN_X / 2 - pa_n / 2 , SCREEN_Y / 2 -64 , pa_m, red );
				ScreenFlip();
			}

			else {
				DrawString( SCREEN_X / 2 - ip_n / 2 , SCREEN_Y / 2 -64 , ip_m, red );
				ScreenFlip();
			}

		}
	}
	return 0;
}

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月28日(木) 05:59
by フィア
softya(ソフト屋) さんが書きました:それと下記の問題に該当しております。
「補足資料.11章 書いてはいけない4つの処理」
http://dixq.net/g/h_11.html
そういえばいつの間にかClearDrawScreenが書いているうちになくなってましたね。
指摘ありがとうございます。
softya(ソフト屋) さんが書きました:GetKeyInputString()では入力途中でもキー入力の値は得ることはできます。
なので、別の場所をクリックした時にGetKeyInputString()で入力値を得れば良いのでは無いでしょうか?
不要なハンドル自体はDeleteKeyInput()で閉じてしまえば良いと思います。
あああ、すみません。
そうですね。
値のほうを書き換えればいいんですね。

ただの判定用関数だと捕らえてて値を与えれば調節できることを思いつきませんでした。
これは盲点でしたうっかりしてましたね。

教えていただきありがとうございました。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月28日(木) 06:16
by フィア
ISLe さんが書きました:ゲームプログラムでは、すべての事象が同時に並行して進行するように作成しなければいけません。
その上で、分岐命令を使い、現在進行して欲しい処理だけが進行するように振り分けます。
それが基本中の基本です。

softyaさんが指摘している問題とは、それを実装するために守るべきルールです。
そこら辺は私も思いますよ
ですのでWaitTimerはつかうべきではない事も最近感じまくってます。

そして並列処理は今は理想的、これから習得しなければいけない課題ですね。
現在の感覚としては一本道を曲がりくねたり、ジャンプさせたりして道自体は作れるけれど基本的には同時に進行ってどうやるんだろう?っと思っています。

勉強が進むにつれてそこら辺はいつか解消できるでしょうね。
そのいつかは並列処理が必要なプログラムを書く時に直面するでしょうね。

ISLe さんが書きました:提示されたコードでは、文字列入力中に、画面のクリック場所を判定する処理が回りません。
このコードにさらにコードを追加して対応することは無駄を増やすことになります。
確かにそこら辺も変更しなければいけないですね。
指摘ありがとうございます。

ただ、経験は無駄にはならないと思います。

ところで、私の感覚としては並列処理的なものではないと思うのですが、このコードも分類として並列になるんですか?

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年2月28日(木) 12:04
by softya(ソフト屋)
フィア さんが書きました:
softya(ソフト屋) さんが書きました:それと下記の問題に該当しております。
「補足資料.11章 書いてはいけない4つの処理」
http://dixq.net/g/h_11.html
そういえばいつの間にかClearDrawScreenが書いているうちになくなってましたね。
指摘ありがとうございます。
ProcessMessage()やScreenFlip()がアチコチにあるのが一番問題なんですけどね。
Xボタンを押された時などの終了処理の流れが不明確になっていませんか?
あと、何処でループを回っているか非常に追っかけ辛いです。 
 → バグりやすい とか 謎のバグが残る遠因になります。
フィア さんが書きました:
softya(ソフト屋) さんが書きました:GetKeyInputString()では入力途中でもキー入力の値は得ることはできます。
なので、別の場所をクリックした時にGetKeyInputString()で入力値を得れば良いのでは無いでしょうか?
不要なハンドル自体はDeleteKeyInput()で閉じてしまえば良いと思います。
あああ、すみません。
そうですね。
値のほうを書き換えればいいんですね。

ただの判定用関数だと捕らえてて値を与えれば調節できることを思いつきませんでした。
これは盲点でしたうっかりしてましたね。

教えていただきありがとうございました。
動作が分かり辛い原因は、ProcessMessage()やScreenFlip()がアチコチにある事だと思います。
そのため、入力完了の状態に遷移する事が難しくなっているプログラムコードだと思います。
状態変数で状態を管理する状態遷移の考え方を全面的に取り入れるべきだとおもいますので検討してみて下さい。
メインにある
switch( sin ) {
の考え方をID/PASSにも取り入れるのです。

下記に有る「メニュー画面の作り方」などを参考にされたほうが良いでしょう。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月01日(金) 01:06
by ISLe
フィア さんが書きました:ところで、私の感覚としては並列処理的なものではないと思うのですが、このコードも分類として並列になるんですか?
フィアさんとわたしとでは並列処理という言葉の意味が違うようなので回答できません。
少なくともわたしが並列処理と書いていないことだけは確かです。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月04日(月) 23:33
by ISLe
質問者さんがお戻りにならないようですが、せっかくなのでこちらで改造したコードを投稿します。
できるだけ元のコードを残そうと思いましたがほとんど別のものになりました。

入力項目周りのコードはさらにまとめることができます。
今回はどこがまとめられるかの判断材料とするためあえてまとめませんでした。
これ以上まとめると跡形も残らなくなりますし。

main.cpp

コード:

#include "DxLib.h"

#define MOJI_SIZE 24 // 文字のサイズ
#define SCREEN_X 960 // 画面の横幅
#define SCREEN_Y 720 // 画面の縦幅
char script[10000]= {0}; //文字データ全体
char LoadFname[100];
int LoadFsize;

int DrawPointX , DrawPointY;    // 文字列描画の位置
int CP; // 参照する文字列中の文字ポインタ

int white;// = GetColor(255,255,255);
int olcl;// = GetColor(128,128,255);

int login(void);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {

	int i = 0;

	int DrawPointX = 0;
	int DrawPointY = 0; // 文字列描画の位置

	int sin = 1; //ゲームの進行度
	bool end_sw = false;

	char fn[100] = "op.s";
	int z;

	SetMainWindowText("神さまの箱庭");
	SetOutApplicationLogValidFlag( FALSE ); //ログを出力しない
	SetBackgroundColor( 255, 255, 255 );
	SetGraphMode( SCREEN_X , SCREEN_Y , 16 );

	ChangeWindowMode( true );
	if( DxLib_Init() == -1 ) {  // DXライブラリ初期化処理
		return -1;             // エラーが起きたら直ちに終了
	}
	SetDrawScreen( DX_SCREEN_BACK );

	white = GetColor(255,255,255);
	olcl = GetColor(128,128,255);

	while(ProcessMessage() == 0 && ScreenFlip() == 0 && ClearDrawScreen() == 0) {
		switch(sin) {
		case 0: //ゲーム終了
			end_sw = true;
			break;

			//最初のシステム関係
			//OPデモ入れるべきだろうか? そんな技術ないくせに 入れるなら人員募集せねば
		case 1: //ログイン画面
			sin = login();
			break;

		}

		if(end_sw == true) {
			break;
		}
	}

	DxLib_End() ;               // DXライブラリ使用の終了処理

	return 0 ;                  // ソフトの終了

}
login.cpp

コード:

#include "DxLib.h"
#define SCREEN_W 960 // 画面の横幅
#define SCREEN_H 720 // 画面の縦幅

#define FOCUS_DRAWBOX

enum {
	PHASE_INIT,
	PHASE_MAIN,
	PHASE_FINI,
};
static int phase = PHASE_INIT;

enum {
	FOCUS_NONE,
	FOCUS_BUTTON_EXIT,
	FOCUS_INPUT_ID,
	FOCUS_INPUT_PW,
	FOCUS_BUTTON_LOGIN,
};
static int focus_last;
static int focus_next;

static const RECT rcExitButton = {(SCREEN_W / 2 - 90), (SCREEN_H / 2 + 25), (SCREEN_W / 2 + 90), (SCREEN_H / 2 + 45)};
static const RECT rcIdInput = {(SCREEN_W / 2 - 49), (SCREEN_H / 2 - 22), (SCREEN_W / 2 + 38), (SCREEN_H / 2 -  2)};
static const RECT rcPwInput = {(SCREEN_W / 2 - 49), (SCREEN_H / 2 +  2), (SCREEN_W / 2 + 38), (SCREEN_H / 2 + 22)};
static const RECT rcLoginButton = {(SCREEN_W / 2 + 41), (SCREEN_H / 2 - 24), (SCREEN_W / 2 + 89), (SCREEN_H / 2 + 24)};

void login_pont(void) {

	if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) {
		int MouX, MouY;
		GetMousePoint( &MouX, &MouY );

		POINT pt = { MouX, MouY };
		if (PtInRect(&rcExitButton, pt)) {
			focus_next = FOCUS_BUTTON_EXIT;   //ゲーム終了
		}
		else if (PtInRect(&rcIdInput, pt)) {
			focus_next = FOCUS_INPUT_ID;   //IDボックス
		}
		else if (PtInRect(&rcPwInput, pt)) {
			focus_next = FOCUS_INPUT_PW;   //PASSボックス
		}
		else if (PtInRect(&rcLoginButton, pt)) {
			focus_next = FOCUS_BUTTON_LOGIN;   //ログインボタン
		}
	}
}

static int black;
static int white;
static int white_s;
static int blue;
static int blue_s;
static int red;

static void login_init(void);
static void login_main(void);
static void login_fini(void);

void login_draw(void);

int login(void) {
	// 並行の関係にある処理を振り分ける
	// 描画処理はメイン側で分けるべきだがとりあえずここでやっとく
	switch (phase) {
	case PHASE_INIT:
		login_init();
		login_draw();
		break;
	case PHASE_MAIN:
		login_pont();
		login_main();
		login_draw();
		break;
	case PHASE_FINI:
		login_fini();
		return 0;
	}
	return 1;
}

static const char *id_m ="IDを入力してください";
static const char *pa_m ="PASSを入力してください";
static const char *ip_m ="IDもしくはPASSが違います";
static const char *message;

static int read = -1;
static int log= -1;

static char id_buf[26];
static char pass_buf[26];

static int id_s = -1;
static int pass_s = -1;

void login_init(void) {

	black = GetColor(0,0,0);
	white = GetColor(255,255,255);
	white_s = GetColor(254,254,254);
	blue = GetColor(0,0,255);
	blue_s = GetColor(96,96,255);
	red = GetColor(255,0,0);

	id_buf[0] = '\0';
	pass_buf[0] = '\0';

	SetTransColor(80,80,40);

	read = LoadGraph( "itt.bmp" );
	log= LoadGraph( "log_k.bmp" );

	SetMouseDispFlag( TRUE );

	id_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );
	pass_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );

	SetKeyInputStringColor(
		black, //文字色
		black, //変換しない場合の右の線の色
		white_s, //変換中の変換候補の背景色
		black, //変換中の右の線の色
		white, //変換中のアンダーライン
		blue_s,   //変換中の文字の色
		white,  //???
		white,  //???
		white,  //???
		white,  //???
		blue, //変換中の枠の色
		white_s //変換中の背景色
	);

	focus_last = FOCUS_NONE;
	focus_next = FOCUS_INPUT_ID;

	phase = PHASE_MAIN;
}

void login_fini(void) {
	message = NULL;
	DeleteKeyInput(id_s);
	id_s = -1;
	DeleteKeyInput(pass_s);
	pass_s = -1;
	DeleteGraph(read);
	read = -1;
	DeleteGraph(log);
	log = -1;
	phase = PHASE_INIT;
}

void login_main(void) {

	int focus_change = FOCUS_NONE; // この関数内でフォーカス先を変えたいときに使う

	// すべてのアイテムを並行に処理する
	// 各々が、自身の状態と周囲の状況から、自身の次の状態を設定する

	// ※本来フォーカスとクリックは別モノだがとりあえず同一視している

	if (focus_last == FOCUS_INPUT_ID) {
		// IDを入力中
		if (CheckKeyInput(id_s) != 0) {
			// 次のアイテムにフォーカス移動
			focus_change = FOCUS_INPUT_PW;
		}
		if (focus_next > 0 && focus_next != FOCUS_INPUT_ID) {
			// フォーカスが移動しようとしている
			GetKeyInputString(id_buf ,id_s);
		}
	}
	else {
		// IDを入力中ではない
		if (focus_next == FOCUS_INPUT_ID) { //IDボックスの位置が押された
			SetActiveKeyInput(id_s);
		}
	}

	if (focus_last == FOCUS_INPUT_PW) {
		// PASSを入力中
		if (CheckKeyInput(pass_s) != 0) {
			// 次のアイテムにフォーカス移動
			focus_change = FOCUS_BUTTON_LOGIN;
		}
		if (focus_next > 0 && focus_next != FOCUS_INPUT_PW) {
			// フォーカスが移動しようとしている
			GetKeyInputString(pass_buf ,pass_s);
		}
	}
	else {
		// PASSを入力中ではない
		if (focus_next == FOCUS_INPUT_PW) { //PASSボックスの位置が押された
			SetActiveKeyInput(pass_s);
		}
	}


	if (focus_next == FOCUS_BUTTON_EXIT) { //ゲーム終了ボタンが押される
		phase = PHASE_FINI;
	}

	if (focus_next == FOCUS_BUTTON_LOGIN) { //ログインボタンが押される
		message = NULL;
		if( ( strcmp( id_buf , "test" ) == 0 ) && ( strcmp( pass_buf , "test" ) == 0 ) ) {
			phase = PHASE_FINI;
		}
		else if( strcmp( id_buf , "" ) == 0 ) {
			message = id_m;
			focus_change = FOCUS_INPUT_ID;
		}
		else if( strcmp( pass_buf , "" ) == 0 ) {
			message = pa_m;
			focus_change = FOCUS_INPUT_PW;
		}
		else {
			message = ip_m;
			focus_change = FOCUS_INPUT_ID;
		}
	}

	if (focus_next != FOCUS_NONE) {
		focus_last = focus_next;
	}
	focus_next = focus_change;
}

#ifdef FOCUS_DRAWBOX
static void drawbox(const RECT &rc) {
	DrawBox(rc.left, rc.top, rc.right, rc.bottom, GetColor(255,0,0), FALSE);
}
#endif

void login_draw(void) {

	DrawGraph( 0  , 0 , read , FALSE ) ;
	DrawGraph( SCREEN_W / 2 - 90 , SCREEN_H / 2 -45 , log , TRUE ) ;

#ifdef FOCUS_DRAWBOX
	drawbox(rcExitButton);
	drawbox(rcIdInput);
	drawbox(rcPwInput);
	drawbox(rcLoginButton);
#endif

	if (focus_last == FOCUS_INPUT_ID) {
		DrawKeyInputString( SCREEN_W / 2 - 47 , SCREEN_H / 2 - 20 , id_s ) ;
	} else {
		DrawString( SCREEN_W / 2 - 47 , SCREEN_H / 2 -20 , id_buf, black );
	}
	if (focus_last == FOCUS_INPUT_PW) {
		DrawKeyInputString( SCREEN_W / 2 - 47 , SCREEN_H / 2 +  4 , pass_s ) ;
	} else {
		DrawString( SCREEN_W / 2 - 47 , SCREEN_H / 2 +4 , pass_buf, black );
	}

	if (message != NULL) {
		int w = GetDrawStringWidth( message , strlen( message ) ) ;
		DrawString( SCREEN_W / 2 - w / 2 , SCREEN_H / 2 -64 , message, red );
	}
}

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 02:20
by フィア
少々遅くなりました。
softya(ソフト屋) さんが書きました: メインにある
switch( sin ) {
の考え方をID/PASSにも取り入れるのです。

下記に有る「メニュー画面の作り方」などを参考にされたほうが良いでしょう。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/

参考サイトを教えていただきありがとうございます。
こちらのサイトを元に手直ししてみました。

さすがに参考元のように細かく分けすぎだと私がどうなっているのかがわからないので機能毎にわけるようにしました。

おかげで、別の場所をクリックするとその場所に対応するように切り替わるようになりましたが、新たなバグと遭遇しました。

IDとPASSが一致してればゲーム終了(場面を切り替える) という命令を出しているのですが動いてくれません。

デバッガで調べてみるとゲーム終了せよという命令は出しているっぽいのですがその命令がどこかにとんでいってるっぽいのです。
そのどこにとんで行ってるかが全く追えないのですがどこら辺が間違ってますでしょうか?

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 02:26
by フィア

コード:

#include "DxLib.h"

#define MOJI_SIZE 24 // 文字のサイズ
#define SCREEN_X 960 // 画面の横幅
#define SCREEN_Y 720 // 画面の縦幅
char script[10000]={0};//文字データ全体
char LoadFname[100];
int LoadFsize;

//文字
int DrawPointX , DrawPointY;	// 文字列描画の位置
int CP;	// 参照する文字列中の文字ポインタ

//絵
int Background;	 //背景
int Background2; //背景2 絵師の人が背景画書いてくれたら不要

//マウス
int MouX,MouY; //マウスの位置
int Mou_Point; //マウスのポインタ

//色の定義
int black = GetColor(0,0,0);
int white = GetColor(255,255,255);
int white_s = GetColor(254,254,254);
int blue = GetColor(0,0,255);
int blue_s = GetColor(96,96,255);
int red = GetColor(255,0,0);
int olcl = GetColor(128,128,255);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){

	int i = 0;

	int DrawPointX = 0;
	int	DrawPointY = 0;	// 文字列描画の位置

	int sin = 1; //ゲームの進行度
	bool end_sw = false;

	char fn[100] = "op.s";
	int z;
	
	SetMainWindowText("神さまの箱庭");
	SetOutApplicationLogValidFlag( FALSE ); //ログを出力しない
	SetBackgroundColor( 255, 255, 255 );
	SetGraphMode( SCREEN_X , SCREEN_Y , 16 );

	ChangeWindowMode( true );
	if( DxLib_Init() == -1 ){	// DXライブラリ初期化処理
		 return -1;				// エラーが起きたら直ちに終了
	}

	SetDrawScreen( DX_SCREEN_BACK );
	SetMouseDispFlag( TRUE );

	while(ProcessMessage() == 0){
		switch(sin){
			case 0: //ゲーム終了
				end_sw = true;
				break;
			
			//最初のシステム関係
			//OPデモ入れるべきだろうか? そんな技術ないくせに 入れるなら人員募集せねば
			case 1:	//ログイン画面
				sin = login();
				break;

		}

		if(end_sw == true){
			break;
		}
	}

	DxLib_End() ;				// DXライブラリ使用の終了処理

	return 0 ;					// ソフトの終了

}

コード:

void login_first(void){
	Background  = LoadGraph( "itt.bmp" );
	Background2 = LoadGraph( "log_k.bmp" );
}

void login_end(void){
	DeleteGraph( Background );
	DeleteGraph( Background2 );
}

void login_draw(void){
	DrawGraph( 0  , 0 , Background , FALSE );
	DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 -45 , Background2 , TRUE );
}

int login_point(void){
	while(ProcessMessage() == 0 ){
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) {
			GetMousePoint( &MouX, &MouY );

			if( ( ( SCREEN_X / 2 - 90 ) < MouX && MouX < ( SCREEN_X / 2 + 90 ) )&&
				( ( SCREEN_Y / 2 + 25 ) < MouY && MouY < ( SCREEN_Y / 2 + 45 ) ) ){
				return 0; //ゲーム終了
			}

			else if( ( ( SCREEN_X / 2 - 49 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 - 22 ) < MouY && MouY < ( SCREEN_Y / 2 -  2 ) ) ){
				return 1;	//IDボックス
			}

			else if( ( ( SCREEN_X / 2 - 49 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 +  2 ) < MouY && MouY < ( SCREEN_Y / 2 + 22 ) ) ){
				return 2;	//PASSボックス
			}

			else if( ( ( SCREEN_X / 2 + 41 ) < MouX && MouX < ( SCREEN_X / 2 + 89 ) )&&
					 ( ( SCREEN_Y / 2 - 24 ) < MouY && MouY < ( SCREEN_Y / 2 + 24 ) ) ){
				return 3;	//ログインボタン
			}

			else{
				return 4;
			}
		}

	}
	return 0;
}

int login_point2(void){
	while(ProcessMessage() == 0 ){
		if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) {
			GetMousePoint( &MouX, &MouY );

			if( ( ( SCREEN_X / 2 - 90 ) < MouX && MouX < ( SCREEN_X / 2 + 90 ) )&&
				( ( SCREEN_Y / 2 + 25 ) < MouY && MouY < ( SCREEN_Y / 2 + 45 ) ) ){
				return 0; //ゲーム終了
			}

			else if( ( ( SCREEN_X / 2 - 49 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 - 22 ) < MouY && MouY < ( SCREEN_Y / 2 -  2 ) ) ){
				return 1;	//IDボックス
			}

			else if( ( ( SCREEN_X / 2 - 49 ) < MouX && MouX < ( SCREEN_X / 2 + 38 ) )&&
					 ( ( SCREEN_Y / 2 +  2 ) < MouY && MouY < ( SCREEN_Y / 2 + 22 ) ) ){
				return 2;	//PASSボックス
			}

			else if( ( ( SCREEN_X / 2 + 41 ) < MouX && MouX < ( SCREEN_X / 2 + 89 ) )&&
					 ( ( SCREEN_Y / 2 - 24 ) < MouY && MouY < ( SCREEN_Y / 2 + 24 ) ) ){
				return 3;	//ログインボタン
			}

			else{
				return 4;
			}
		}

		else{
			return 5;
		}
	}
	return 0;
}

コード:

int id_b(int *id_s,char *id_buf,char *pass_buf){

	int han;
	login_first();

	SetActiveKeyInput( *id_s );
	
	while(ProcessMessage() == 0 ){
		han=login_point2();  

		if( han !=1 && han !=5 ){
			GetKeyInputString( id_buf , *id_s );
			//login_end();
			return han;
		}

		if( CheckKeyInput( *id_s ) ==1 ){
			GetKeyInputString( id_buf , *id_s );
			//login_end();
			return 4;
		}

		if(han==5){

		ClearDrawScreen();
		login_draw();

		if( strcmp(pass_buf,"") !=0){
			DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , pass_buf, black );				
		}

		DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 - 20 , *id_s ) ;

		ScreenFlip();
		}

	}
	return 4;

}

int pass_b(int *pass_s,char *id_buf,char *pass_buf){

	int han;
	login_first();

	SetActiveKeyInput( *pass_s );

	while(ProcessMessage() == 0 ){
		han=login_point2();

		if( ( han != 2 ) && ( han != 5 ) ){
			GetKeyInputString( pass_buf , *pass_s );
			//login_end();
			return han;
		}

		if( CheckKeyInput( *pass_s ) == 1 ){
			GetKeyInputString( pass_buf , *pass_s );
			//login_end();
			return 4;
		}

		if( han == 5 ){

		ClearDrawScreen();
		login_draw();

		if( strcmp(id_buf,"") !=0){
			DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 -20 , id_buf, black );				
		}

		DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , *pass_s ) ;

		ScreenFlip();
		}

	}
	return 4;
}

int login_b(int *id_s,char *id_buf,int *pass_s,char *pass_buf){

	login_first();

	char *id_m ="IDを入力してください";
	char *pa_m ="PASSを入力してください";
	char *ip_m ="IDもしくはPASSが違います";

	int id_n = GetDrawStringWidth( id_m , strlen( id_m ) ) ;
	int pa_n = GetDrawStringWidth( pa_m , strlen( pa_m ) ) ;
	int ip_n = GetDrawStringWidth( ip_m , strlen( ip_m ) ) ;

	login_draw();

	if( ( strcmp( id_buf , "test" ) == 0 ) && ( strcmp( pass_buf , "test" ) == 0 ) ){
		login_end(); 
		return 6; //キャラクタ選択画面ではなく ゲーム終了 おかしいゲーム終了しないどうなってるの?
	}

	else if( strcmp( id_buf , "" ) == 0 ){
		login_draw();
		if( strcmp( pass_buf , "") !=0){
			DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , pass_buf, black );				
		}
		DrawString( SCREEN_X / 2 - id_n / 2 , SCREEN_Y / 2 -64 , id_m, red );
	}

	else if( strcmp( pass_buf , "" ) == 0 ){
		login_draw();
		if( strcmp(id_buf,"") !=0){
			DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 -20 , id_buf, black );				
		}
		DrawString( SCREEN_X / 2 - pa_n / 2 , SCREEN_Y / 2 -64 , pa_m, red );
	}

	else {
		login_draw();
		DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 -20 , id_buf, black );
		DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , pass_buf, black );				
		DrawString( SCREEN_X / 2 - ip_n / 2 , SCREEN_Y / 2 -64 , ip_m, red );
	}

//	login_end();

	return 0;
}

int first_b(char *id_buf,char *pass_buf){

	login_first();
	login_draw();
	
	if( strcmp(id_buf,"") !=0){
		DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 -20 , id_buf, black );				
	}

	if( strcmp(pass_buf,"") !=0){
		DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 +4 , pass_buf, black );				
	}

//	login_end();

	return 4;
}

int login_update(int *id_s,char *id_buf,int *pass_s,char *pass_buf){

	static int han = 4;

	switch( han ){
			case 1: //IDボックスの位置が押される
				han = id_b(id_s,id_buf,pass_buf);
				break;

			case 2: //PASSボックスの位置が押される
				han = pass_b(pass_s,id_buf,pass_buf);
				break;

			case 3: //ログインボタンが押される
				han = login_b(id_s,id_buf,pass_s,pass_buf);
				break;

			case 4:
				han = first_b(id_buf,pass_buf);
				break;

			case 6: //IDとPASSがあっている
				login_end();
				InitKeyInput();
				return 0; //キャラクタ選択画面ではなく ゲーム終了 おかしいゲーム終了しないどうなってるの?
				break;

			case 0: //ゲーム終了ボタンが押される
				login_end();
				InitKeyInput();
				return 0;
				break;

	}

	han =login_point();

	return 9;
}

int login(void){

	char id_buf[18] = "";
	char pass_buf[18] = "";
	int id_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );
	int pass_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );

	int sin = NULL;

	login_first();

	SetKeyInputStringColor(
		black, //文字色
		black, //変換しない場合の右の線の色
		white_s, //変換中の変換候補の背景色
		black, //変換中の右の線の色
		white, //変換中のアンダーライン
		blue_s,   //変換中の文字の色
		white,  //???
		white,  //???
		white,  //???
		white,  //???
		blue, //変換中の枠の色
		white_s //変換中の背景色
	);

	login_draw();

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

		login_draw();
		sin=login_update(&id_s,id_buf,&pass_s,pass_buf);

		if( sin == 0){
			break;
		}
	}
	login_end();
	return 0;
}
DeleteKeyInput()ではなくInitKeyInput()を使ってますが問題はありますか?

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 02:46
by フィア
ISLe さんが書きました: フィアさんとわたしとでは並列処理という言葉の意味が違うようなので回答できません。
少なくともわたしが並列処理と書いていないことだけは確かです。
では質問の仕方を変えます。
ISLeさんの言い方をまねて言うのであれば

このコードはすべての事象が同時に並行して進行する必要性があるのですか?

何か質問の内容が聞きたいことと違っているような気がしますが言い方がわからないので申し訳ありません。
ISLe さんが書きました: 質問者さんがお戻りにならないようですが、せっかくなのでこちらで改造したコードを投稿します。
できるだけ元のコードを残そうと思いましたがほとんど別のものになりました。
何度も試行錯誤してどうしてもできない
もしくは
何度か試行錯誤してできた場合

に戻ろうと思っていたので返事が遅くなってしまって申し訳ありませんね。
多少の改良でうまくいかなくて聞くのは、何の努力もせず聞く事になりそれは失礼だろうと思って戻らなかったのです。
そのことでご心配をかけてしまって申し訳ありませんね。

試行錯誤自体ができないか、何度も試行錯誤してどうにもならなくなった場合は質問するのは早いんですけどね。

ソースを書いていただきありがとうございます。
書いていただいたソースを基に間違っていそうな場所を調べてみますね

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 05:11
by フィア
そういえば参考サイトを見たときからすっごく疑問に思っていたのですが

大体こうなってることは理解しました

全体で使える関数群

処理書き込み


全体の操作関数

1を選択したら

1の初期化関数呼び出し
1の描画関数呼び出し
1の更新関数呼び出し
1の終了関数呼び出し


1の関数群

1の初期化関数
1の描画関数
1の更新関数
1の終了関数


2の関数群

2の初期化関数
2の描画関数
2の更新関数
2の終了関数



サイトはこんな感じだと把握しています
ここで疑問なのですが

全体で使える関数群

処理書き込み


全体の操作関数「

1を選択したら

1の関数呼び出し


1の関数「
1の初期化、描画、更新、終了処理してあるよ


2の関数「
2の初期化、描画、更新、終了処理してあるよ


何故下の書き方のようにしないのですか?
上の書き方だと細かく分化しすぎてわかりずらいと感じました。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 11:30
by softya(ソフト屋)
フィア さんが書きました:そういえば参考サイトを見たときからすっごく疑問に思っていたのですが
何故下の書き方のようにしないのですか?
上の書き方だと細かく分化しすぎてわかりずらいと感じました。
すいません、両方の違いがあるように見えません。
超推理で書くとなぜ、いちいちメインループに戻っくるのか?と言う質問だと推理します。

それは次のような理由です。

1.ProcessMessage()が複数あると終了処理が複雑化して終了できないなどバグを生みやすい。
あとProcessMessage()をうっかり呼び忘れるなどの問題も起きやすい。これは一番してはいけません。

2.ScreenFlip()が複数あるとフレームレートの制御を一本化出来ない。
ScreenFlip()のタイミングが分かりづらくなるので、フェードアウトやら演出系の制御で失敗が多くなる。
謎の処理落ちなどのバグが発生する。

3.ProcessMessage()やScreenFlip()とセットでキーボードなどの処理も呼び出すので複数あるとキーボードを押してからフレーム数のカウントなどがマトモにできなくなります。

4.ClearDrawScreen()は背景の消し忘れのバグを起こしやすい。特に3Dだと分けの分からない描画のバグを産みます。

5.何処のループで回っているか本人も分からなくなる事がある。

6.もうひとつ有った。他の人が流れを追い辛いので質問しても回答が少なくなる or バグを解析してもらえない。
メインループの一本化は共同作業のために生まれたベター解といって良いと思いますので、それから外れることはこういう質問掲示板で質問することや共同作業を困難にします。
実力でなんとでも出来る人はすごい(壮絶な)プログラムを書きますが、それでもちゃんと動きます。ただし本人しかプログラムは解読できません。つまり自分で何とか出来る共同作業しない人にしか向かない方法です。【追記】ついでに書くと全部の事象の流れが全て頭の中で見えている特別な頭脳の持ち主にしか向いていませんので一般人が真似してはいけません。

プログラムは、同じような処理は複数の所で扱うとバグを生みやすく流れが読みづらくなります。
一見分かりやすいようにみえるかもしれませんがデバッグを困難にしているのでおすすめできないのです。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 12:32
by softya(ソフト屋)
ぜひ、コンパイルが通る形で掲載して欲しいですね。
zipファイルでソースと画像(ダミーでも可)だけ添付してもらうほうが早いかもしれません。

今回の件は、login_point()でhanを6以外に書き換えているからでは?デバッガで確認してみて下さい。
つまり、hanの書き換えが関数の流れで2箇所あるのが問題かと。これも ProcessMessage() ループが複数ある弊害じゃないかと思います。
それと1,2,3,4とかが分かり辛いのでenumして名前をつけて下さいね。

その他ざっと見た感じでは、
1)InitKeyInput()で問題は無さそうですがlogin_end();を多箇所で読んでいるのがやばそうです。

2)関数外に有るGetColor()が正しいカラーを得る保証はありません。PCに依存します。必ずDxLib_Init()後にGetColor()してください。

3)ProcessMessage() ループがどう回っているかやはり複雑です。
たとえば、loginのループ → login_pointのループ となっていると思いますが、マウス処理の時無意味に全力でループを回っているのでCPU使用率が無駄に上がっていると思います。
この状況で終了処理の時に、
int login_point(void){
while(ProcessMessage() == 0 ){
return 0;
ときてlogin_updateで
han =login_point();
return 9;
と流れてloginで
sin=login_update(&id_s,id_buf,&pass_s,pass_buf);
if( sin == 0){
break;
}
と来た上で
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
としているので、しなくて良いScreenFlip()やら ProcessMessage()の2回めをしている自覚はありますか?
DXLIB側で気をつけてくれていると思いますので動くとは思いますが好ましい処理の仕方ではありません。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 16:58
by ISLe
フィア さんが書きました:このコードはすべての事象が同時に並行して進行する必要性があるのですか?
必要性があるかどうかということなら、最初の回答に「基本中の基本」と書きましたが、必要性がないと読めますか?

具体的な理由はsoftyaさんが説明しているとおりです。
同じコードをあちこちに書いたりあちこちから呼び出したりする無駄や重複を省き、発見しにくい上に致命的なバグを埋め込まないための工夫です。

特に前半。
無駄や重複がないようにと意識しないで済むこと自体が、とても重要なことです。

コードを書くときは個々の事象のみに注目すれば良いのでとても気が楽です。
考え方としてはいわゆるオブジェクト指向に近く、流れに沿ってコーディングするバッチとは対極です。

ボタンや入力ボックスのコンポーネントとそれを制御するフレームワークがあらかじめ用意されているのなら、それを利用してバッチ処理を書くのは簡単ですが、今回はそのフレームワークを作ろうとしているのですから。
GUIフレームワークはオブジェクト指向がもっとも適しているプログラムのひとつです。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月06日(水) 17:24
by ISLe
フィア さんが書きました:大体こうなってることは理解しました

全体で使える関数群
(略)

全体の操作関数

1を選択したら

1の初期化関数呼び出し
1の描画関数呼び出し
1の更新関数呼び出し
1の終了関数呼び出し


(略)

サイトはこんな感じだと把握しています
違いますよ。
1を選択したら1関連の関数とは、シーン遷移のことでしょう。

項目1と項目2がメニュー画面にある場合、項目はどちらも並行に処理されます。

項目1が選択されていたら…
項目1は選択されているふうにふるまい
項目2は選択されていないふうにふるまう。
項目2が選択されたら…
項目1は選択されていないふうにふるまいを変え
項目2は選択されているふうにふるまいを変える。

それぞれの項目が独立してふるまうようにしてあれば、項目3が増えても、項目1,2には影響しません。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 17:17
by フィア
少々遅くなりました。
softya(ソフト屋) さんが書きました:
1.ProcessMessage()が複数あると終了処理が複雑化して終了できないなどバグを生みやすい。
あとProcessMessage()をうっかり呼び忘れるなどの問題も起きやすい。これは一番してはいけません。

2.ScreenFlip()が複数あるとフレームレートの制御を一本化出来ない。
ScreenFlip()のタイミングが分かりづらくなるので、フェードアウトやら演出系の制御で失敗が多くなる。
謎の処理落ちなどのバグが発生する。

3.ProcessMessage()やScreenFlip()とセットでキーボードなどの処理も呼び出すので複数あるとキーボードを押してからフレーム数のカウントなどがマトモにできなくなります。

4.ClearDrawScreen()は背景の消し忘れのバグを起こしやすい。特に3Dだと分けの分からない描画のバグを産みます。

5.何処のループで回っているか本人も分からなくなる事がある。

6.もうひとつ有った。他の人が流れを追い辛いので質問しても回答が少なくなる or バグを解析してもらえない。
メインループの一本化は共同作業のために生まれたベター解といって良いと思いますので、それから外れることはこういう質問掲示板で質問することや共同作業を困難にします。
実力でなんとでも出来る人はすごい(壮絶な)プログラムを書きますが、それでもちゃんと動きます。ただし本人しかプログラムは解読できません。つまり自分で何とか出来る共同作業しない人にしか向かない方法です。【追記】ついでに書くと全部の事象の流れが全て頭の中で見えている特別な頭脳の持ち主にしか向いていませんので一般人が真似してはいけません。

プログラムは、同じような処理は複数の所で扱うとバグを生みやすく流れが読みづらくなります。
一見分かりやすいようにみえるかもしれませんがデバッグを困難にしているのでおすすめできないのです。
このまま今までの私自身が読みやすいと思ったプログラムを書き続けていたら、先の未来でよくわからんバグに遭遇いてたんでしょうね

ある意味、突き詰めれば誰も読むことができない防衛力は最高だけれども、共同作業が全くできない最低なプログラムになっていたことでしょう。

しかし、今までは私一人でがんばってプログラムを作ればよかったのですが、今回は共同作業する可能性があるため、他人に見づらいプログラムを書いてはいけないので、私が見づらくも他人が見やすいプログラムの書き方を習得してみました。

ISLeさんの書いたプログラムを見て最初こそ何でこういう処理を施しているのかわかるづらい部分がいくつもあったのですが、何度も何度も眺めたり修正したり、試行錯誤してるうちにだんだん理解してきていつの間にか、ほぼ同じになってしまいました。

最初は原型を残そうとしていたのですがおかしいですね
softya(ソフト屋) さんが書きました:ぜひ、コンパイルが通る形で掲載して欲しいですね。
zipファイルでソースと画像(ダミーでも可)だけ添付してもらうほうが早いかもしれません。
何故コンパイルが通らないのかがわからないのですが

申し訳ありません。
原形をとどめようとはしたのですが、何度も修正を施した結果バグがあったソースコードはなくなってしまったのですよ。
全く予想できませんでした。

今後は同じことがないように、予めバグのソースを保存してZIP形式にまとめておきますね

softya(ソフト屋) さんが書きました:今回の件は、login_point()でhanを6以外に書き換えているからでは?デバッガで確認してみて下さい。
つまり、hanの書き換えが関数の流れで2箇所あるのが問題かと。これも ProcessMessage() ループが複数ある弊害じゃないかと思います。
それと1,2,3,4とかが分かり辛いのでenumして名前をつけて下さいね。
前のバグのあったソースはデバッガで確認してみたところ書き換えている可能性のあるところは一通りみたのですがどこも変なところが見つかりませんでした。

ProcessMessage() ループを2つ作ったのは、そうしないとあの時点では動いてくれなかったからです。

enueも今までは見ずらくなるから使わなかったのですが、今回、何度か使ってみて大体慣れました。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 17:20
by フィア
softya(ソフト屋) さんが書きました: その他ざっと見た感じでは、
1)InitKeyInput()で問題は無さそうですがlogin_end();を多箇所で読んでいるのがやばそうです。

2)関数外に有るGetColor()が正しいカラーを得る保証はありません。PCに依存します。必ずDxLib_Init()後にGetColor()してください。

3)ProcessMessage() ループがどう回っているかやはり複雑です。
たとえば、loginのループ → login_pointのループ となっていると思いますが、マウス処理の時無意味に全力でループを回っているのでCPU使用率が無駄に上がっていると思います。
この状況で終了処理の時に、
int login_point(void){
while(ProcessMessage() == 0 ){
return 0;
ときてlogin_updateで
han =login_point();
return 9;
と流れてloginで
sin=login_update(&id_s,id_buf,&pass_s,pass_buf);
if( sin == 0){
break;
}
と来た上で
while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
としているので、しなくて良いScreenFlip()やら ProcessMessage()の2回めをしている自覚はありますか?
DXLIB側で気をつけてくれていると思いますので動くとは思いますが好ましい処理の仕方ではありません。
ここら辺は気をつけて修正してみました。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 17:25
by フィア
ISLe さんが書きました: 必要性があるかどうかということなら、最初の回答に「基本中の基本」と書きましたが、必要性がないと読めますか?

具体的な理由はsoftyaさんが説明しているとおりです。
同じコードをあちこちに書いたりあちこちから呼び出したりする無駄や重複を省き、発見しにくい上に致命的なバグを埋め込まないための工夫です。

特に前半。
無駄や重複がないようにと意識しないで済むこと自体が、とても重要なことです。

コードを書くときは個々の事象のみに注目すれば良いのでとても気が楽です。
考え方としてはいわゆるオブジェクト指向に近く、流れに沿ってコーディングするバッチとは対極です。
申し訳ありません。
あの時は質問の仕方があってるかどうかがわからなかったのですが、間違えていたようです。

私が書いたコードはすべての事象が同時に並行して進行していないのですか?

が、正しい言い方でした。
申し訳ありません。

ISLeさんが書いたプログラムは最初こそなれずにどうしてこんな書き方しているんだろうと思っていたのですが何度も眺めたり修正したりしてるうちに理解できました。

非常にソースの修正やプログラムの追加が簡単になってることがわかりました。

ISLeさんの書かれたlogin_main()の関数の重複部分をまとめようとはしたのですがよくわからないバグがでてしまうのと、処理の流れがみやすいこともあり重複部分を変更しませんでした。

できたソースは多少変更と追加しています。

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 17:36
by フィア
main.cpp

コード:

#include "DxLib.h"

#define MOJI_SIZE 24 // 文字のサイズ
#define SCREEN_X 960 // 画面の横幅
#define SCREEN_Y 720 // 画面の縦幅
char script[10000]={0};//文字データ全体
char LoadFname[100];
int LoadFsize;

//文字
int DrawPointX , DrawPointY;	// 文字列描画の位置
int CP;	// 参照する文字列中の文字ポインタ

int login(void);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){

	int i = 0;

	int DrawPointX = 0;
	int	DrawPointY = 0;	// 文字列描画の位置

	int sin = 1; //ゲームの進行度
	bool end_sw = false;

	char fn[100] = "op.s";
	int z;
	
	SetMainWindowText("神さまの箱庭");
	SetOutApplicationLogValidFlag( FALSE ); //ログを出力しない
	SetBackgroundColor( 255, 255, 255 );
	SetGraphMode( SCREEN_X , SCREEN_Y , 16 );

	ChangeWindowMode( true );
	if( DxLib_Init() == -1 ){	// DXライブラリ初期化処理
		 return -1;				// エラーが起きたら直ちに終了
	}

	SetDrawScreen( DX_SCREEN_BACK );
	SetMouseDispFlag( TRUE );

	while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
		switch(sin){
			case 0: //ゲーム終了
				end_sw = true;
				break;
			
			//最初のシステム関係
			//OPデモ入れるべきだろうか? そんな技術ないくせに 入れるなら人員募集せねば
			case 1:	//ログイン画面
				sin = login();
				break;

		//	case 2: //キャラクター選択画面
		//		sin = kyar_sen();
		//		break;

		//	case 3: //キャラクター製作
		//		break;

		//	/*case 4: //作るかどうかわからないけれどおまけモード
		//		break;*/

		//	//ゲームの基本関係
		//	case 11: //拠点画面
		//		sin=bese_k();
		//		break;

		//	case 12: //拠点内部画面
		//		sin=honb_k();
		//		break;

		//	case 13: //エリア画面
		//		sin=aria_k();
		//		break;

		//	case 14: //ワールド画面
		//		sin=wold_k();
		//		break;

		//	case 15: //戦闘準備画面
		//		break;

		//	case 16: //戦闘画面
		//		break;
		//	
		//	//AD関係
		//	case 21: //ゲーム開始
		//		SetFontSize( MOJI_SIZE );
		//		z = loadfile( fn );
		//		scriptOrder( z );
		//		break; //送りだされるまで

		//	case 22: //送り出されてから
		//		//ここから種族毎の分岐が始まる
		//		break;
		//	//RPG関係
		//	//SL関係
		}

		if( end_sw == true ){
			break;
		}
	}

	DxLib_End() ;				// DXライブラリ使用の終了処理

	return 0 ;					// ソフトの終了

}

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 17:42
by フィア
login.cpp

コード:

#include "DxLib.h"

#define SCREEN_X 960 // 画面の横幅
#define SCREEN_Y 720 // 画面の縦幅

//イベント
enum{
	end_i,
	id_i,
	pass_i,
	login_i,
	other_i,
	none_i,
};

//モード
enum{
	first_md,
	usually_md,
	next_md,
	end_md,
};

//イベント、モード初期化
static int sin_now  = none_i;
static int sin_next = id_i;

static int mode = first_md;

//マウスの位置
static int MouX,MouY;

//色
static int black;
static int white;
static int white_s;
static int blue;
static int blue_s;
static int red;

//文字列表示
static const char *id_m = "IDを入力してください";
static const char *pa_m = "PASSを入力してください";
static const char *ip_m = "IDもしくはPASSが違います";
static const char *mess = NULL;

//判定文字列
static char id_buf[16];
static char pass_buf[16];

//文字読み取り
static int id_s   = -1;
static int pass_s = -1;

//絵
static int Background  = -1; //背景
static int Background2 = -1; //背景2 絵師の人が背景画書いてくれたら不要

//明度
static int br_bc;

//判定個所
static const RECT end_rc=   { ( SCREEN_X / 2 - 90 ),( SCREEN_Y / 2 + 25 ),( SCREEN_X / 2 + 90 ),( SCREEN_Y / 2 + 45 ) };
static const RECT id_rc=    { ( SCREEN_X / 2 - 49 ),( SCREEN_Y / 2 - 22 ),( SCREEN_X / 2 + 38 ),( SCREEN_Y / 2 -  2 ) }; 
static const RECT pass_rc=  { ( SCREEN_X / 2 - 49 ),( SCREEN_Y / 2 +  2 ),( SCREEN_X / 2 + 38 ),( SCREEN_Y / 2 + 22 ) };
static const RECT login_rc= { ( SCREEN_X / 2 + 41 ),( SCREEN_Y / 2 - 24 ),( SCREEN_X / 2 + 89 ),( SCREEN_Y / 2 + 24 ) };

bool login_next_sw = false;

int login(void);

void login_point(void){

	if( ( GetMouseInput() & MOUSE_INPUT_LEFT ) != 0 ) {
		GetMousePoint( &MouX, &MouY );

		POINT pt = { MouX, MouY };

		if( PtInRect( &end_rc , pt ) ){
			sin_next = end_i; //ゲーム終了
		}

		else if( PtInRect( &id_rc , pt ) ){
			sin_next = id_i; //IDボックス
		}

		else if( PtInRect( &pass_rc , pt ) ){
			sin_next = pass_i; //PASSボックス
		}

		else if( PtInRect( &login_rc , pt ) ){
			sin_next = login_i; //ログインボタン
		}

		else{
			sin_next = other_i;
		}
	}
}

void login_first(void) {
 
    black   = GetColor(0,0,0);
    white   = GetColor(255,255,255);
    white_s = GetColor(254,254,254);
    blue    = GetColor(0,0,255);
    blue_s  = GetColor(96,96,255);
    red     = GetColor(255,0,0);
 
    Background  = LoadGraph( "itt.bmp" );
    Background2 = LoadGraph( "log_k.bmp" );

	br_bc = 255;

    SetMouseDispFlag( TRUE );

	id_buf[0] = '\0';
	pass_buf[0] = '\0';
 
    id_s   = MakeKeyInput( 8 , FALSE , FALSE , FALSE );
    pass_s = MakeKeyInput( 8 , FALSE , FALSE , FALSE );
 
    SetKeyInputStringColor(
        black,   //文字色
        black,   //変換しない場合の右の線の色
        white_s, //変換中の変換候補の背景色
        black,   //変換中の右の線の色
        white,   //変換中のアンダーライン
        blue_s,  //変換中の文字の色
        white,   //???
        white,   //???
        white,   //???
        white,   //???
        blue,    //変換中の枠の色
        white_s  //変換中の背景色
    );
 
	mode = usually_md;
}

void login_end(void){

	InitKeyInput();
	InitGraph();

	id_s   = -1;
	pass_s = -1;
	Background  = -1;
	Background2 = -1;
	mess = NULL;
	mode = first_md;

}

void login_manege(void){

	int change = none_i;

	if( sin_next == end_i ){
		mode = end_md;
	}

	if( sin_now == id_i ){
        if( CheckKeyInput( id_s ) != 0 ){
			if( ( strcmp( pass_buf , "" ) == 0 ) ){
				change = pass_i;
			}
			
			else{
				change = login_i;
			}
            
        }

        if ( sin_next > 0 && sin_next != id_i ) {
            GetKeyInputString( id_buf , id_s );
        }
    }

    else {
        if ( sin_next == id_i ){
            SetActiveKeyInput( id_s );
        }
    }

	if( sin_now == pass_i ){
        if( CheckKeyInput( pass_s ) != 0 ){
			if( ( strcmp( id_buf , "" ) == 0 ) ){
				 change = id_i;
			}
			
			else{
				change = login_i;
			}
        }

        if( sin_next > 0 && sin_next != pass_i ) {
            GetKeyInputString( pass_buf , pass_s );
        }
    }

    else {
        if ( sin_next == pass_i ){
            SetActiveKeyInput( pass_s );
        }
    }

	if( sin_now == login_i ){
		if( ( strcmp( id_buf , "test" ) == 0 ) && ( strcmp( pass_buf , "test" ) == 0 ) ){
			mode = next_md;
		}

		else if( strcmp( id_buf , "" ) == 0 ){
			mess = id_m;
			change = id_i;
		}
		
		else if( strcmp( pass_buf , "" ) == 0 ){
			mess = pa_m;
			change = pass_i;
		}
 
		else {
			mess = ip_m;
			change = id_i;
		}
	}

	if(	sin_next != none_i ){
		sin_now = sin_next;
	}

	sin_next = change;

}

void login_draw(void){

	int ml;

	if( mode == next_md ){

		SetDrawBright( br_bc, br_bc , br_bc );
		br_bc -= 8;
		
		if( br_bc < 0 ){
			login_next_sw = true;
		}

	}

	DrawGraph( 0  , 0 , Background , FALSE );
    DrawGraph( SCREEN_X / 2 - 90 , SCREEN_Y / 2 - 45 , Background2 , TRUE );
	
	if( strcmp( id_buf, "" ) !=0 ){
		if( sin_next != id_i ){
			DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 - 20 , id_buf , black );
		}
    }

	if( sin_now == id_i ){
		DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 - 20 , id_s );
	}	

	if( sin_now == pass_i ){
		DrawKeyInputString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 + 4 , pass_s );
	}
	
	if( strcmp( pass_buf , "" ) !=0 ){
		if( sin_next != pass_i ){
			DrawString( SCREEN_X / 2 - 47 , SCREEN_Y / 2 + 4 , pass_buf , black );
		}
	}
	
	if( mess != NULL){
		ml = GetDrawStringWidth( mess , strlen( mess ) ) ;
		DrawString( SCREEN_X / 2 - ml / 2 , SCREEN_Y / 2 - 64 , mess , red );
	}
}

int login(void){

	switch( mode ){
		case first_md:
			login_first();
			login_draw();
			break;

		case usually_md:
			login_point();
			login_manege();
			login_draw();
			break;

		case next_md:
			login_draw();
			if( login_next_sw == true ){
				login_end();
				return 0; //キャラクター選択画面に移動させたいけどとりあえずゲーム終了
			}
			break;

		case end_md:
			login_end();
			return 0;
			break;

	}
	return 1;

}

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 18:11
by フィア
ソースの指摘や参考サイトをおしえてくださり、見本のソースを見せていただきありがとうございました

Re: 別の場所をクリックされたら入力途中から入力完了にするには?

Posted: 2013年3月12日(火) 19:01
by ISLe
フィア さんが書きました:ISLeさんが書いたプログラムは最初こそなれずにどうしてこんな書き方しているんだろうと思っていたのですが何度も眺めたり修正したりしてるうちに理解できました。

非常にソースの修正やプログラムの追加が簡単になってることがわかりました。
お役に立てて何よりです。

enumなどの定数(値の変わらない識別子)は、大文字にするのがスタンダードです。
現状のコードはとても平坦な印象なので、ぱっと見で印象に違いが出るよう名前の付け方に気を配るとなお良くなります。

適度にコメントを入れることも大切です。
プログラムコードの読み書きにおいては、三ヵ月後の自分は赤の他人と言います。