ページ 11

DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 11:01
by usami
お世話になっております。
また、力を貸していただけたらと思います。


現在、DxLibを使用して、簡単な戦略シュミレーションゲームを作成しているのですが、
実行中なぜか強制終了が起こる問題が発生しています。
(エラーが発生したために強制終了される類の問題でなく、ごく自然に画面が閉じられる。なして?)

コード的には、
while(ProcessMessage()==0 && CheckHitKey(KEY_INPUT_ESCAPE)==0){
(中略)
}
DxLib_End();

ということで、
エスケープを押すとかしなければ終了されないはずなのですがなぜなのでしょう?

ちなみに強制終了される場合はいつも決まっており、

1.あるクラスの描画メソッドを呼び出しているとき(この場合、キャラクター選択クラスの描画メソッド)。
(ひとつの画面処理について、1クラスを作成するというスタイルで作成している。
 たとえばタイトル画面で、タイトル画面用のクラスを作成――class title{};
 たとえばバトル、マップ画面で、class buttle{}; class map{};
 みたいな感じで、あとはそのクラスの描画メソッドをグローバル変数のswitchケース分類する)
2.大体目算で15秒くらいはその画面を維持するのだが、そこで強制終了される。


途中、Sleep()を挿むことにより、維持される時間が可変であるように思えるので、
素人考えでは、そのクラスの処理(描画メソッド)が一定回数実行されると、
強制終了が起きているのではと推測するのですが、
何でそのような事態になるのか原因がさっぱりわかりません。

つきましては、DxLibがエラーでなく強制終了される場合をご存知の方がいらっしゃられましたら、
その解決法ともども
是非教えていただけたらと思います。

ちなみに現段階におきましては、
音楽は未使用、
使用画像は一律で.png で統一しています。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 11:08
by kazuoni
>クラスの描画メソッド
>大体目算で15秒くらい

これだとよくわからないので、
コードを挙げたほうがいいかと思います。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 11:23
by usami
ご指摘ありがとうございます。

まず、main.cpp
ということで、
次のような形となっております。

#include "extern.h"
#include "include.h"

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC){
//変数宣言

//基本初期設定
ChangeWindowMode(true);
if(DxLib_Init()==-1) return -1;
//基本変数の初期化
Title tt;
Turn tn;
PlayLocation pl;
BMap bmap;
BStage bsg;
gamestatus=GS_CHARSELECT;//便宜上。

SetDrawScreen(DX_SCREEN_BACK); //描画対象裏面

while(ProcessMessage()==0 && CheckHitKey(KEY_INPUT_ESCAPE)==0){
ClsDrawScreen(); //画面のクリア
GetHitKeyStateAll(HitKey);

/*
諸処理。
*/
switch(gamestatus){
case GS_TITLE:
tt.Draw();
break;
case GS_CHARSELECT:
tn.T_Draw();
break;
case GS_ZINSELECT:
pl.P_Draw();//←問題発生地点
break;
case GS_BUTTLEMAP:
bmap.BM_Draw();
break;
case GS_BUTTLESTATE:
bsg.BS_Draw();
break;
}

/*
FSPの調整。
*/

ScreenFlip(); //画面の入れ替え。
}

DxLib_End();
return 0;
}

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 12:10
by MNS
PlayLocation::Draw()のコードも提示されるべきでは?
メインループには問題ないように思えます

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 12:13
by usami
↑イメージがつかめないと思うので、pl.P_Draw()実行時の画像を添付しておきました。
 この画面で、十数秒放置すると、勝手に終了されてしまうのです。

それではさらに、PlayLocationクラスについて。

とりあえず、長すぎるため、投稿しきれないということなので、
問題となっている
P_Draw();
のみ示します。


void P_Draw(){//総合的な描画。
 if(startflag) //スタート時の初期化。
  start();     //gamestatus=GS_ZINSELECTとなった最初の処理。

 selectSex=mselect[0]; //前画面からの選択変数の格納、男性/女性により、選択できる陣形が変わる。

 SelectNo(); //第一段階。現在選択されている陣形パターンにより、初期化を行う。描画はしない。

 BackGround();  //第二段階。基本となるグラフィック画像の配置。
 Comments();   //コメント用メソッド
 Block();     //背景の補助。ブロック配置。
 NowSelectBox(); //現在の選択。

 secondTurn(); //描画段階制御。アニメーション用変数の変化。

 if(!blight){   //導入部。だんだんと画面が明るくなる。
  ve_flag=true;
  if(!DarkOut())
   blight=true;
 }
 if(blight)
  SelectKey(); //第三段階。キー入力による制御切り替え。

 if(bdark)
  darks();          //だんだん画面が暗くなる。次の画面へ。

 return;
}

強制終了が発生するのは、
gamestatus=GS_ZINSELECT;
に移してから、十数秒後~二十数秒後の間。
その他クラスでは別段問題が発生しているわけではないというのが現状で、
ポイントは、これが不正な処理による強制終了でなく、
あくまで、自然に終了する[デバック停止]ボタンなどをクリックした際と、
同様な終了であるということ(エラーメッセージが出ない)。

おそらく、上記のコードを見ても、解決策はなかなかでないと思うので、
(メソッド多用につき、具体的な処理はなにも記されていないのでイメージしかつかめないと思う)
こんなとき、エラーメッセージなく強制終了が起こる、といった判例を挙げていただくと、
とても参考になります。
よろしくお願いします。

DxLibは(DxLib_VC2_24b.exe)。VC2008での実行。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 13:48
by Justy
 まず、DXライブラリを最新版(2.25b)にしてみてはどうでしょうか。

 それでも再現するのであれば、本当に強制終了かどうかを確認してみましょう。

 DXライブラリが吐き出す Log.txtに

ウインドウを閉じようとしています
ウインドウが破棄されようとしています
ソフトを終了する準備が整いました


の3行はありますか?

 これがあるなら、ある意味正常終了ということなります。


 あとはどこで落ちているかを確認しましょう。

AppLogAddでも OutputDebugString()でもいいんで、メイン関数と
P_Draw()内のあちこちにそこを通過したことが判るようなログを仕掛けて下さい。

 多少処理は重くなりますが、これで落ちてくれればどこまで実行され
どれが実行されずに終わったかがわかると思うので、何回も行えば
該当箇所が絞り込めると思います。


[color=#d0b0c0" face="monospace]
>エラーメッセージなく強制終了が起こる、といった判例
[/color]

 真っ先に思い浮かぶのは exit関数とか、それに類するものが呼ばれた場合ですね。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 17:31
by usami
Justyさん、ありがとうございます。

おっしゃるように、
とりあえずLog.txtにあたってみると(これまでログなど気にしたこともありませんでした)、
原因はあっさりと判明しました。

どうやら、
for文でキャラクターの背景となる、画像を描画していたことに端を発する、
グラフィクス数の許容量オーバーということのようです。
320×320の間に、32×32の画像をおよそ100。16×16の画像を20程度。
あと、キャラクターやら、なにやらで、1回の処理に、150程のグラフィクスを表示し、
その繰り返しで、グラフィクス数の許容量を越え、終了命令が発生していた模様です。

しかしながら疑問なのですが、
俗に弾幕系と呼ばれるシューティングゲームなどでは、
一度の処理に100や200の画像を表示することなど珍しくないことだと思うのですが、
こういったゲームの場合、上記の問題をいかにクリアされているのでしょうか?

とりあえず、今回はこの背景となるレンガを一枚の画像で表現することで、
問題を回避しようと思うのですが、
この問題は後にひきそうなので、
ぜひご存知の方は教えていただけたらと思います。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 17:35
by yu
違う弾ですが、グラフィックは同じなので
そのグラフィックハンドルを使い回せば良いです

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 18:18
by usami
vuさん、書き込みありがとうございます。
言葉が足りなかったようです申し訳ありません。

今回発生した問題は

for(int i=0; i<10; i++) //たとえばこれはレンガを敷くこと。
for(int j=0; j<10; j++)
DrawGraph( 32*i, 32*j, ghandle1, true);

for(int i=0; i<20; i++){ //たとえばこれはレンガの外枠。横軸。
DrawGraph( 16*j, 0, ghandle2, true);
DrawGraph(16*j, rect.botom-32, ghandle3, true);
}

(以下略)
//縦軸とか。
//キャラクターの配置とか。


この場合、グラフィックハンドル自体は使いまわしなのですが、
グラフィック数が許容量を越えている、とログは報告してきています。
なので十数秒~二十数秒、すなわち一万~二万回処理を行い、
処理1回150~200程DrawGraph()呼び出しを行った末の、
描画しすぎの集積によるエラーだと自分は理解しました。

先の質問はこの理解の上のものです。(ひょっとしたら、これ自体が間違っているかもしれないのですが)

この場合、たとえば、弾丸200発が常時画面上に発生する、
シューティングゲームなんかを作成すると、
と同じ問題に直面するのではないか、と単純に思って質問させていただいたのです。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 18:24
by yu
そうでしたか・・・
すみません orz

グラフィックをロードし、解放していなく
これ以上ロードできない状態になっているのかと思っていました

DrawGraph()を多く呼び出しただけで強制終了するのでしょうか?・・・
以前にSTGを作りましたが 1フレーム に3000回ぐらい描画していましたよ
特に特別な処理はしていませんよ(多分

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 18:24
by MNS
画像をロードする処理を見直してみてください。
何らかの手違いで大量に画像がロードされていることはありませんか?
もし、それでも原因が分からなかった場合は、
その処理が書かれている範囲のコードを提示されたほうが良いと思います。

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 18:38
by Justy

>グラフィック数が許容量を越えている、とログは報告してきています。

 このエラーは、LoadGraphなどでテクスチャを生成する際に内部的に最大数を越えた場合に
発生するものだと思うので DrawGraphが原因ではないと思いますが、試しにその DrawGraphを
コメントアウトして表示しないようにしたらどうなりますか?


 又、無駄に LoadGraphなどテクスチャの新規生成を行っている箇所がないか
調べてみて下さい。
(或いは GetGraphNum()で毎フレーム、登録されている画像数を確認してみるのも
いいかもしれません)

Re:DxLibに詳しい人へ質問です

Posted: 2009年9月05日(土) 18:50
by usami
vuさん、MNSさん、Justyさんのおっしゃるように、
見返してみると、確かに結構メモリに画像をロードしているようです。
(他クラス、コンストラクタとかで)

失礼しました。

さらに、チェックしてみると、フラグの立て方のミスにより、
繰り返し画像のロードがされていることも判明。これが致命傷!!


とりあえず、コンストラクタでロードしていたグラフィックを、
Draw()メソッドへまわせば、この問題は解決だと思われます。

お付き合いいただきありがとうございました。