ページ 11

DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 12:22
by しし
今私はVC++でDXライブラリを使って、ゲームクリアするまでに何秒時間がかかったか計測するというプログラムを作成しています。

そこでGetNowCount関数を使おうと決めプログラムを組みました。

コード:

int stime,etime,cnt;//現在の経過時間を入れる変数、ゲーム終了時の経過時間を入れる変数、ゲーム終了のカウント変数
int col;
col = GetColor(255,255,255);
void game(){
stime = GetNowCount() ;
~~中略~~
       if(cnt==10){ //ゲームが終了したら
   ClearDrawScreen();
    etime=GetNowCount() - stime;	
	DrawFormatString( 0, 0, col, "%d", etime ) ;
       }
}
このようなソースで実行したのですが、etimeにあたる数字が0と1が交互に高速で描写されてしまいます。
原因がいまいち分かりません。良かったらご教授お願いします。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 12:57
by softya(ソフト屋)
プログラムのループがどうなっている分かりませんが、stime = GetNowCount() ;って毎フレーム実行されてませんか?
ならプレイ時間の計測にはなりませんよ。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 13:09
by しし
毎フレームというのがいまいち分からないのですが、どこで宣言すればよいのでしょうか?

コード:

int WINAPI WinMain(HINSTANCE hI,HINSTANCE hP,LPSTR lpC,int nC)
{
	ChangeWindowMode(TRUE); //ウインドウモードに指定
	SetDrawScreen(DX_SCREEN_BACK);
	if(DxLib_Init() == -1) return(-1); //DXライブラリの開始処理
    while(ProcessMessage()==0 && CheckHitKey(KEY_INPUT_ESCAPE)==0)
	{	
		ClearDrawScreen();
		game();
       ScreenFlip();//裏画面反映

	}

	DxLib_End(); //DXライブラリ終了処理
	return(0); //終了
}
このように関数を呼び出しているのですが(なぜこういう仕様なのか気になさらずに)
どこの位置で現在までの経過時間を代入すればいいのでしょうか?
毎フレームごとというのがいまいちわかりません・・・

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 13:56
by softya(ソフト屋)
フレームと言うのは1回の画面の単位で1コマともいます。
DXライブラリを普通に使うと毎秒60フレーム(コマ)で毎秒60回更新されますので、while(ProcessMessage()==0 && CheckHitKey(KEY_INPUT_ESCAPE)==0)のループも毎秒60回行われます。
つまり、game()関数は毎秒60回呼びさだれることになります。
stime = GetNowCount() ;
がgame()関数内にあるので毎回値が代入されて、そこから差分時間しか計算されません。
なので、0から1msしか経過していないという時間が表示されます。
なので、
stime = GetNowCount() ;
はwhileループの前に入れる必要があります。

それとClearDrawScreen()はメインループにあるので、game()関数内にあってはいけません。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 14:45
by しし
そういうことですか!良く分かりました。ありがとうございます。
ではwhileループの外でGetNowCount関数を呼び出しその時点での経過時間を変数に代入したいと思うのですが、
その代入した変数をgame関数で使うというやり方が分かりません・・・

また、ゲーム終了時に画面を切り替えたいのですが、ClearDrawScreen()関数を使わないと画面が綺麗にならないのですがどうすればいいのでしょう?
お手数ばかり掛けますがご教授お願いします。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 14:50
by softya(ソフト屋)
game()関数の中の流れが分からないので一般的なことしか書けませんが、

「34. メイン関数の書き方。」
http://dixq.net/g/37.html
の様に状態でやることを分けたほうがすっきりと書けます。
ゲームクリア後をgame()と分離できないのでしょうか?

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 14:52
by softya(ソフト屋)
書き忘れましたね。

>その代入した変数をgame関数で使うというやり方が分かりません・・・

stimeが関数外にあるならWinMain()からもgame()からも参照出来るはずです。
game()が別ファイルなら、もっと工夫がいりますが。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 14:57
by しし
何度も本当にありがとうございます。
実はgame()関数は別ファイルなのでうまく行かずどうしようかと考えていました。
値渡しの場合の実引数と仮引数がよくわからなくて・・・

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 15:05
by softya(ソフト屋)
あっ言い忘れてましたがetimeも一回しかカウントしないように制限を掛ける必要があります。
毎フレーム更新されると値がどんどん増えますからね。

ところで、ゲームクリア後の処理は別ファイルに分けますか?
それ次第で提案が変わるのですが。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 15:08
by しし
クリア後の処理は別ファイルには分けず同じ関数かファイル内でお願いします。
わざわざすいません。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 15:25
by softya(ソフト屋)
game()関数で分けるとしたら
if(cnt==10){ //ゲームが終了したら
ならgame()関数の頭でgame_end();でそれ以外はgame_main();関数の呼び出し(同じファイル)としてはどうでしょうか?
そうすれば、ClearDrawScreen()は不要ではないですか?

あと同じファイルにgame_init()関数を追加して
stime = GetNowCount() ;
をこの関数の中に書きます。
そしてWinMainからgame_init()を呼び出すようにすれば解決しますよね。

あとは、

コード:

	etime=GetNowCount() - stime;  
    DrawFormatString( 0, 0, col, "%d", etime ) ;
に関しては、

コード:

	static bEndFirst = FALSE;
	if( !bEndFirst ) {
		bEndFirst = TRUE;
		etime=GetNowCount();
	}
    DrawFormatString( 0, 0, col, "%d", etime-stime ) ;
とする手もあります。
ソースコード全体がわかれば、もっとシンプルに書けるかも知れませんが今分かる範囲だとこれ以上は難しいです。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 16:17
by しし
本当にありがとうございます。
言われたとおりに自分で考えて実行しましたが、しかし、二桁(または3ケタ)の数字がentime - stimeの答えになるはずなのですが、
15712など5ケタもの数字が表示されてしまいました。
cnt==10までにかかった時間は1分にも満たないと思います。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月29日(月) 16:26
by softya(ソフト屋)
GetNowCount()の単位はms(ミリ秒)です。
つまり、1/1000秒ですね。
秒単位なら1000で割る必要があります。

15712なら約16秒ではないでしょうか。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 00:41
by しし
遅れてしまい申し訳ありません。
すっかり忘れていました。すいません・・・

最後になんですがClearDrawScreen()関数の件で"game()関数の頭でgame_end();でそれ以外はgame_main();関数の呼び出し"
というのが良く分からず困っています。
良かったらお手数掛けますが宜しくお願いします。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 10:08
by softya(ソフト屋)
ClearDrawScreen()関数が必要なのは、その前に何か描画しているからですよね?
なので、なにか描画する前に[ゲームが終了したら]分岐したらどうでしょう?って話です。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 10:31
by しし
そういうことですか!ありがとうございます。
では
endflgという変数を用意して、if(endflg==0) ゲーム処理;
if(endflg==1) メニュー画面に戻る;
という処理をしようと思ったのですがうまくメニュー画面に戻らずstackoverflowのエラーが出てしまいます。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 10:35
by softya(ソフト屋)
stackoverflowのエラーが出てしまいます。
それは再帰呼び出し(自分自身の関数の呼び出し)をしていませんか?
ソースコードがないので推測でしか書けません。
せめて、問題の関数のソースコードを載せてもらえると正確に答えられると思います。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 10:55
by ししとう
すいませんお願いします。

コード:

#include "DxLib.h"
#include "Keyboard.h"
#include "menu.h"
int endflg,cnt;
endflg=0;
cnt=0;
void game(){
 if(endflg==0){
     ゲーム処理、カウント処理(cnt+=1)など
   if(Keyboard_Get(KEY_INPUT_BACK)==1 || cnt==5)		endflg=1;
 }
if(endflg==1)      menu(); //別ファイルのメニュー画面関数に戻りたい
ちなみにmenu関数からgame()関数を呼び出しています

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 11:01
by softya(ソフト屋)
game()もmenu()もWinMainから呼び出すように状態管理してください。
呼び出す順番がぐちゃぐちゃになって、game()→menu()→game()→menu()game()→menu()・・・と無限ループしていると思います。

ゲームプログラミングの館にあるこの手法を使います。
「34. メイン関数の書き方。」
http://dixq.net/g/37.html

[追記]
決してgame()からmenu()を呼び出してはいけません。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 11:07
by ししとう
そうなっているのですね・・・
しっかりこれを参考にして組みなおしていきたいのですが

この場合だと同じファイルの中に Menu()関数やOpening()関数があるため分かりやすいのですが、
違うファイルの中にMenu()関数などがある場合の変数の値受け渡しについて分かりません・・・

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 11:14
by softya(ソフト屋)
ししとう さんが書きました:そうなっているのですね・・・
しっかりこれを参考にして組みなおしていきたいのですが

この場合だと同じファイルの中に Menu()関数やOpening()関数があるため分かりやすいのですが、
違うファイルの中にMenu()関数などがある場合の変数の値受け渡しについて分かりません・・・
Menu()関数で必要な変数が分からないですが、引数と戻り値では解決しない問題でしょうか?
グローバル変数を使うことは避けてください。

新ゲームプログラミングの館の下記内容にも目を通しておいてください。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/
d.1 メイン関数の作り方
d.2 複数のファイルにわけてコンパイルする
d.3 ゲームの設計と分割コンパイル(1)
d.4 ゲームの設計と分割コンパイル(2)
d.5 ゲームの設計と分割コンパイル(3)

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 11:29
by ししとう
WinMain関数に変数の値を返すことはできますか?
WinMainから他の関数には渡せると思うんですが、そこがいまいちわかりません

関数の戻り値ではダメなのですか?
「関数」
http://www9.plala.or.jp/sgwr-t/c/sec11.html

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 11:35
by ししとう
すいません分かった気がします!!
とりあえず自分で組んでやってみたいと思います。本当に迷惑かけました。ありがとうございました。

また組んで不具合等分からないところがあったら質問したいと思うので、まだ解決済にはしないでいようと思います。
ありがとうございました

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 12:09
by ししとう
自分自身これで大丈夫だと思っていたのですが、うまくいきませんでした。
WinMainでの画面切り替え

コード:

staic int mode;
mode=0;
              ~~~~~~中略~~~~~~~~~~~
		switch(mode){
                        case 0:
                        mode = menu(mode);
                                break;
                        case 1:
                        mode = janken();//別ファイルの関数
                                break;
                        case 2:
                        mode = calc();//別ファイルの関数
                                break;
                        case 3:
                        mode = longest();//別ファイルの関数
                                break;
                        case 4:
                        mode = longrnk();//別ファイルの関数
                                break;
                        default:
                                DxLib_End() ;                                // DXライブラリ使用の終了処理
                                return 0;
                                break;
                }
 
		
		ScreenFlip();//裏画面反映

	}

	DxLib_End(); //DXライブラリ終了処理
	return(0); //終了
}
別ファイルのmenu(int mode)関数(ヘッダーインクルード済み)

コード:

int menuyx,menuy;
static int now;

int menu(int now){
 ~~~~~~~中略~~~~~~~~~(menux,menuyの値の増減)
  if(Keyboard_Get(KEY_INPUT_RETURN)==1 && menuy==100 && menux==160){
				now=1;
				return now;
		}
		if(Keyboard_Get(KEY_INPUT_RETURN)==1 && menuy==200 && menux==160){
				now=2;
				return now;
		}
		if(Keyboard_Get(KEY_INPUT_RETURN)==1 && menuy==300 && menux==160){
				now=3;
				return now;
		}
		if(Keyboard_Get(KEY_INPUT_RETURN)==1 && menuy==200 && menux==410){
				now=4;
				return now;
		}
		
}
これでうまくWinMain関数に値が返ると思ったのですが、エラーが出てしまいました。
'=' : 'void' から 'int' に変換できません。というエラーです。
環境はVC++2008Express WindowsVistaです。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 12:12
by softya(ソフト屋)
どの行にエラーが出ているか書いてないので勘ですが、何処かの関数に戻り値void の関数がないか確認してください。
ヘッダなどのプロタイプ宣言も再確認を。

[追記]
static int now;
って意味ないですし、menu関数のあるファイルとっては害ありなので消してください。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 12:20
by ししとう
menu関数のファイルで 'menu' : 値を返さないコントロール パスがあります。
と警告が出ました。
戻り値がvoidとなると、menu関数があるファイル(menu.cpp)内にある初期化するための関数 void init()関数などがあるのが原因なのでしょうか?

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 12:34
by softya(ソフト屋)
さっきとエラーメッセージが違いますね。

>menu関数のファイルで 'menu' : 値を返さないコントロール パスがあります。

これはプログラムの流れ次第でreturn文を通らない可能性があると言う意味です。
menu関数の最後にreturn がないのが原因です。

void init()に関しては戻り値を参照していないなら無関係です。

Re: DXライブラリGetNowCount()関数がうまく働かない

Posted: 2011年8月31日(水) 12:46
by ししとう
すいませんなんとかWinMainから全ての関数を呼び出すことができました!

なんとかあとは自分でやってみます!本当にありがとうございました!
解決済みにします!