ページ 11

関数が呼びだされない&文字が突然消える

Posted: 2009年8月06日(木) 22:37
by アトラス
またまた行き詰ってしまったので質問させていただきます。
1つ目は、debugでビルドするとうまく動くのに、releaseでビルドすると一部の関数が呼びだされなくなります。
--------------------------------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){



    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 || SetMainWindowText( "RPG" ) == -1 ) return -1; //ウィンドウ化と初期化処理

	while(f_status != 2){

		title();

		if( f_status == 0 ){
			map(0);

		}
		if( f_status == 1 ){
			map(1);
		}
	}


    DxLib_End();
    return 0;
}
-----------------------------------------------------------------------------------------------
f_statusは大域変数です。
title()はタイトル画面で、map()はマップ画面です。
マップでのメニューで「終了」を選択するとmap()関数は終了する設定なのですが、なぜかtitle()は呼びだされず、
map(0)関数が呼びだされ続けます。(ループ1回目だけはtitle()は呼び出されます)
どうしてこうなるのかわからず、大変困ってます。



2つ目は、プログラムの実行中に、突然文字が消えることがあります。
--------------------------------------------------------------------------------------------
void window(int x1,int y1,int x2,int y2){
	DrawBox(x1,y1,x2,y2,GetColor(50,50,50),TRUE);
	DrawBox(x1,y1,x2,y2,GetColor(0,0,0),FALSE);
	DrawBox(x1+1,y1+1,x2-1,y2-1,GetColor(255,255,255),FALSE);
}
void message(char *text){
    int Key[256];
	int font4=CreateFontToHandle("HGS明朝B",20,5,DX_FONTTYPE_ANTIALIASING_EDGE);
    SetDrawScreen( DX_SCREEN_BACK );
		while(!ProcessMessage() && GetHitKeyStateAll_2(Key)==0 && Key[ KEY_INPUT_Z ]!=1){
			window(0,448,640,480);
			DrawFormatStringToHandle(4,454,GetColor(255,255,255),font4,"%s",text);
			ScreenFlip();
		}

}
文字の描写は、まずDrawBoxでメッセージウィンドウをつくり、そこにDrawStringToHandleとDrawFormatStringToHandleを使って文字を表示させてます。
ですが、たまに文字が全部消えてしまうんです。ウィンドウはなぜか消えません。

どなたか回答よろしくおねがいします。

Re:関数が呼びだされない&文字が突然消える

Posted: 2009年8月06日(木) 22:49
by kazuoni
1は、関数の中身まで提示しないと、わかりかねるかと思います。

2では、その関数がどのように使用されているか提示することが必要かと思いますが・・・
message関数を毎ループよんでいるのだとしたら、
関数に入るたびに、フォントハンドルを作り続けているので、
そこが気になります。

Re:

Posted: 2009年8月07日(金) 01:23
by アトラス
debugとreleaseの違いで起こるエラーなので補助関数の中身は関係ないだろうと思って書きませんでしたが
やはりまずかったみたいですね・・・すみません。
先ほど試しに下のようにmap()の直後にtitle()を追加するとうまくいきましたので、とりあえず自己解決しました。

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



    if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 || SetMainWindowText( "RPG" ) == -1 ) return -1; //ウィンドウ化と初期化処理

	while(f_status != 2){

		title();

		if( f_status == 0 ){
			map(0);
			title();
		}
		if( f_status == 1 ){
			map(1);
			title();
		}
	}


    DxLib_End();
    return 0;
}
-----------------------------------------------------------------------------------------------


2についてですが、やはり何度もフォントハンドルを作るのは処理が重くなりよくないみたいですね。
だいたい15回くらいmessage関数を呼びだすと文字がすべて消えます。
message()関数は、毎ループではないですが、バトル中に「敵にダメージを与えた」等のイベントが起きるたびに呼んでます。
最初は大域変数としてフォントハンドルを定義していたんですが、それだとメッセージが表示されなかったので
message関数内で定義しています。

Re:

Posted: 2009年8月07日(金) 01:51
by Justy
[color=#d0b0c0" face="monospace]
>下のようにmap()の直後にtitle()を追加するとうまくいきましたので、とりあえず自己解決しました。
[/color]

 それは解決とはいえないと思います。
 何が原因かはソースがないのでわかりませんが、根本的に解決しないといつか
(プログラムがより複雑になった段階で)再発したりするとその原因調査・修正のコストは
今よりもっと高いものになります。

 本当にそれでいいのならいいのですが、時間の許す限りきちんと調べた方がいいかと思います。


 あとプログラムの構造も見直すことをお勧めします。
 message関数のようにただメッセージを出す為の関数に ProcessMessage()~ScreenFlip()のループが
あるような現状の構造では(多分 titleや mapも同様なのでしょうか)そのうち無理が来る可能性が
高いです。

Re:

Posted: 2009年8月08日(土) 17:11
by アトラス
アドバイスありがとうございます。
一応動いたからいいやと思ってましたが、やはりよくないですよね・・・。
map関数の中身を全部消したところ正常に動いてくれたのでやはりmap関数に問題があるみたいです。
あと一つ聞いておきたいことがあって、releaseビルドでは処理が「最適化」されると聞いたのですが、
具体的にはdebugビルドの時とどういう具合に処理が違うのでしょうか?
それが分かれば1については解決できそうな気がします。

ProcessMessage()~ScreenFlip()についてですが、これは何回も書くのではなく、すべての処理が一通り終わった後1回で済ましたほうがいいということでしょうか。

今まではとりあえずおもいついたままプログラムを書いていってたので、一度全体的に整理してみようと思います。

Re:

Posted: 2009年8月08日(土) 19:09
by Justy
[color=#d0b0c0" face="monospace]
>具体的にはdebugビルドの時とどういう具合に処理が違うのでしょうか?
[/color]

 環境やコンパイラによって内容が異なりますし、コンパイラオプションをどう設定したのか
によっても変わってくるので、なかなかひと口には説明しづらいんですが、
よくあるのが

・ 頻繁に使う変数の値を、メモリではなくレジスタに格納する
・ 使わないプログラムや意味のないプログラム、或いは変数を削除する
・ 分岐命令を減らす
・ 複雑な演算式を、同じ結果になるより単純な式で置換する
・ 同じ条件式を削除する
・ 内部的なデバッグ機能の削除

 というもので、実際には非常に多岐にわたっています。
(コンパイラの中にはとても貧弱な最適化性能しかないものもありますが……)

コンパイラ最適化 - Wikipedia
ttp://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E6%9C%80%E9%81%A9%E5%8C%96


[color=#d0b0c0" face="monospace]
>1については解決できそうな気がします
[/color]

 大抵、未初期化変数や不定な動作となるコードがあったり、ポインタや配列の範囲外への
アクセスが原因であることが多いです。

 慣れないと、Releaseビルドでのデバッグは大変だと思いますが、頑張ってください。


[color=#d0b0c0" face="monospace]
>すべての処理が一通り終わった後1回で済ましたほうがいいということでしょうか
[/color]

 きちんと設計されて、それが必要なものであれば複数あるのはかまわないのですが、
数が多くなればなるほど後でいろいろと不都合が出ることがあります。

 例えば一例を挙げると、何か全てに共通する処理をそこに追加で入れたい時とか、
何か修正する必要が出てきた時に、それを全ての箇所で行わなければなりません。
 手間ですし、修正が複雑だとミスも出てくるかもしれません。

 ProcessMessage()~GetHitKeyStateAll()~ClearDrawScreen()~ScreenFlip()は
毎フレーム行うべき定型処理、といっても過言ではないものなので、
1カ所にまとまってた方がなにかと管理しやすと思います。

Re:

Posted: 2009年8月09日(日) 23:26
by アトラス
一通りソースの整理してみると、今回はちゃんと動くようになりました。
どの部分がエラーの原因かは結局分からずじまいになってしまいましたが・・・。

2についてなんですが、ビルドログを見ると

フォントハンドル値が異常です

というメッセージが大量に出てました(汗
これはkazuoniさんのおっしゃるように、フォントハンドルを毎回作っているのが原因なのでしょうか?

Re:

Posted: 2009年8月10日(月) 00:42
by Justy
[color=#d0b0c0" face="monospace]
>これはkazuoniさんのおっしゃるように、フォントハンドルを毎回作っているのが原因なのでしょうか?
[/color]

 その可能性はあります。
 
 そのメッセージは指定されたフォントハンドルが不正であることを示しています。

 現状作成できるフォントハンドルは 40個までですので、
ハンドルを解放せずに次から次へと新しいフォントハンドルを作り続ければ、
いつかは枯渇します。

 そうなるとフォントハンドルの生成には失敗しますが、それに気付かずに
フォントハンドルを使おうとするとそのメッセージが出ますので、可能性は高いです。

Re:

Posted: 2009年8月17日(月) 14:52
by アトラス
しばらく間があいてしまい申し訳ありません。

起動時にのみフォントハンドルを作るようソースを書きかえると正常に動いてくれました。
ありがとうございます。


今日もまた一つ質問があるのですが、プログラミングの館のセーブデータの作成、読み込みについて、

freadとfwriteの第2引数は"sizeof(save_data_t)"となってますが、
"sizeof(save_data)"としても問題は無いですか?
自分で試したところ誤作動は起きなかったのですが、気になるので聞いてみました。

Re:

Posted: 2009年8月17日(月) 15:29
by ねこ
「save_data_t」が構造体、「save_data」がその変数だと予測しますが、それなら問題無いです。
どちらも同じサイズになります。

Re:

Posted: 2009年8月17日(月) 16:30
by アトラス
そうなんですか!
回答ありがとうございました。