ページ 1 / 1
当たり判定の動作
Posted: 2013年8月12日(月) 14:19
by sozai
現在
ゲームとはいえないソフトを作っておりまして、
当たり判定を実装したのですが、なぜか動作しません。
原因は条件式のほうでなく関数の位置にあるのだと思いますがどうなのでしょうか?
関係あると思われる箇所のみ載せます。
コード:
//enemy.cpp
void GameOver_S1(){[tab=30]//当たり判定を行う関数
if( ((x_Draw-x_e1)*(x_Draw-x_e1)+(y_Draw-y_e1)*(y_Draw-y_e1))<=((75+13)*(75+13)) ) { //Draw_x,Draw_yは
//プレイヤーが操作するアイコンの座標
MessageBox(GetMainWindowHandle(),"Game Over!\nメニューへ戻ります。","GAME OVER",MB_OK);
Scene = eScene_Menu; //メニューへ戻るための処理
}
if( (x_Draw-x_e2)*(x_Draw-x_e2)+(y_Draw-y_e2)*(y_Draw-y_e2)<=(75+10)*(75+10) ) { //x_e1やy_e1,x_e2,y_e2は敵の座標
MessageBox(GetMainWindowHandle(),"Game Over!\nメニューへ戻ります。","GAME OVER",MB_OK);
Scene = eScene_Menu;
}
}
コード:
//enemy.h
//ヘッダの宣言
extern void GameOver_S1();
コード:
//Scene.cpp
//現在の場面に関する関数
#include "enemy.h"
void Stage1(){ //ステージ1関連の関数をまとめた関数
GameOver_S1();
The_Func(); //アイコンの描画や操作関係
Other_Func(); //ステージクリア時の処理
Draw_enemy();//敵の描画
if(Key[ KEY_INPUT_SPACE ]>=1){
Scene = eScene_Menu;//スペースキーでメニューへ
}
}
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 15:03
by softya(ソフト屋)
プログラマが必ず身につけないといけないデバッグ方法ですが、
ここの式が
if( ((x_Draw-x_e1)*(x_Draw-x_e1)+(y_Draw-y_e1)*(y_Draw-y_e1))<=((75+13)*(75+13)) ) {
どうなって真偽判定されているかデバッガでも確認できません。
これではデバッグできないので、
式をif文と分離してください。
int diff_x = (x_Draw-x_e1);
int diff_y = (y_Draw-y_e1);
こうすれば、それぞれの値を確認できます。
>原因は条件式のほうでなく関数の位置にあるのだと思いますがどうなのでしょうか?
このコードだけだと処理順番がわかりませんので、答えることは無理ですね。
少なくともデバッガでGameOver_S1が適切なタイミングで呼ばれていることは確認できると思います。
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 15:45
by sozai
softya(ソフト屋) さんが書きました:
>原因は条件式のほうでなく関数の位置にあるのだと思いますがどうなのでしょうか?
このコードだけだと処理順番がわかりませんので、答えることは無理ですね。
少なくともデバッガでGameOver_S1が適切なタイミングで呼ばれていることは確認できると思います。
では、他に必要なコードはどのような箇所でしょうか?
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 16:00
by softya(ソフト屋)
デバッガで毎フレーム適切に呼び出されいる事は確認されましたか?
Stage()が毎フレーム呼び出されるなら、GameOver_S1()も毎フレーム呼び出されているはずです。
> では、他に必要なコードはどのような箇所でしょうか?
出来るだけご自分で確認してもらいたいのですが、無理そうですか?
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 16:36
by sozai
環境はVisualC++Express2010を使っています。
デッバグして実行したところ、ちゃんと敵もユーザーが操作するアイコンのほうも描かれましたし動かすことも出来ましたので、毎フレームにStage1()が呼び出されているのだとは思います。
敵のアイコンにぶつかると、時々動きが微かに鈍くなるような気がしたので、変数を使い、Game Overか否かを判断するように変えてみようと思います。
>出来るだけご自分で確認してもらいたいのですが、無理そうですか?
わかりました。
もう一度見直してみます。
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 16:39
by softya(ソフト屋)
もしかして「デバッガを使う」と言う意味が理解されていないのでは?と思いました。
「太田研究室 > Visual C++ 2010 Express プログラミング入門」
http://cvwww.ee.ous.ac.jp/vc10prog.html#7
ここの、「プログラムのデバッグ実行」をお読みください。
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 18:48
by sozai
>softya様
デバッガの使い方ありがとうございます。
確認したところ、毎フレーム呼び出されているようで、デバッグなしで実行したところ、ぶつかったら、Game Over になりました。
ありがとうございます。
Re: 当たり判定の動作
Posted: 2013年8月12日(月) 18:59
by softya(ソフト屋)
デバッグなしで実行したら正常に動いて、デバッグありの場合は正常動作しないのなら、何か別のバグが有りますよ。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 00:05
by sozai
>softya様
返信遅れてすみません。
前述の通り、ゲームオーバーにはなるのですが、
なぜか縦に動く敵がちょうど一周目にプレイヤーが操作するアイコンとぶつからなければゲームオーバーになりません。
他にも色々あるのですが説明が難しいので、省略します。
要約すると、『二回目以降当たり判定が動作しない』ということになります。
エラーは一切出てこないので、コードに問題があるのだと思います。
原因としてはどんなものが挙げられそうですか?
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 00:12
by softya(ソフト屋)
それこそデバッガで、変数とかの情報を確認してなぜ条件をすり抜けるか調べるべきですね。
提示されているコードだけだと動くんじゃないでしょうか?って感触しかありません。
No: 2で書いたようにif文を分解しないと調べづらいかもしれません。
【補足】
デバッグ方法で分からない事は聞いてください。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 02:21
by sozai
早速で申し訳ないのですが、当たり判定などの瞬間的に処理される場合、その都度タイミングを合わせてブレークポイントを指定するのですか?
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 09:54
by Tatu
日記(
http://dixq.net/forum/blog.php?u=1264&b=3958)で公開されていたコードを見てみました。
当たり判定をうまく行えないのは敵のy座標が増えっぱなしになっているからではないでしょうか。
描画の時は剰余演算子%を使ってごまかしているから正常であるように見えるだけなのでしょう。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 09:58
by softya(ソフト屋)
その瞬間を再現しやすいようにプログラムを一時的に直した方が良いと思います。
つまり、動き出した瞬間に衝突するようにするのです。
あとprintfDxを使って変数の内容を表示しても良いと思います。
> 当たり判定をうまく行えないのは敵のy座標が増えっぱなしになっているからではないでしょうか。
見逃してました。それでしょうね。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 16:15
by sozai
起動した瞬間、当たり判定が動くように下の画像のようにしたのですが、条件式が真になりません。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 16:18
by softya(ソフト屋)
この瞬間の条件式に出てくる変数をprintfDXで表示してみては?
あと条件式を変えていたら最新のもの提示してください。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 16:23
by みけCAT
printfDxなどで、
x_Draw,x_e1,y_Draw,y_e1,((x_Draw-x_e1)*(x_Draw-x_e1)+(y_Draw-y_e1)*(y_Draw-y_e1)),((75+13)*(75+13)),
((x_Draw-x_e1)*(x_Draw-x_e1)+(y_Draw-y_e1)*(y_Draw-y_e1))<=((75+13)*(75+13))
の値をリアルタイムで調べられますか?
運が悪いと、最適化で壊されているかもしれません。(レアケースですが、
前に1度やられたことがあります)
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 16:26
by sozai
まだprintfDxで表示していないのですが、
奇妙なことにブレークポイントをいったん全てはずして続行を押したら数秒後GameOverのメッセージボックスが表示されメニューに戻りました。
ブレークポイントをはずす前までは条件式の値は偽だったはずなのですが...
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 16:29
by みけCAT
数秒後ということは、当たりと判定される範囲がおかしいかもしれません。
「条件式の値は偽」という情報は、画面に表示されていますか?
毎フレームブレークポイントで止まっていて、「当たる」部分に行っていなかった可能性があると感じました。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 17:08
by sozai
ひとまず、条件式をprintfDxで表示したら『62500+4900<=7225』と出ました。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 17:09
by sozai
立て続けにすみません。
コード:
x_de1 = (x_Draw-x_e1);
x_de2 = (x_Draw-x_e2);
y_de1 = (y_Draw-y_e1);
y_de2 = (y_Draw-y_e2);
printfDx("%d+%d<=%d",x_de1*x_de1,y_de1*y_de1,85*85);
if( x_de1*x_de1+y_de1*y_de1<=(75+13)*(75+13) ) {
GameOverFlag=true;
}else if( x_de2*x_de2+y_de2*y_de2<=(75+10)*(75+10) ) {
GameOverFlag=true;
}
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 17:15
by softya(ソフト屋)
printfDxしている数値で85*85じゃなくて88*88だと思いますが、それを置いておいても条件を満たすはずがないですよね?
x_de1*x_de1がなぜ62500なのでしょうか?
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 17:33
by sozai
コード:
printfDx("x_de1=%d\tx_de1^2=%d\n",x_de1,x_de1*x_de1);
を追加してもう一度実行したところ、
『62500+4900<=7744』
『x_de1=-250[tab=10]x_de1^2=62500』
と表示されました。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 17:37
by softya(ソフト屋)
私が聞きたいのは、x_Draw-x_e1が-250となってしまう初期値と言うか状況です。
意図した通りなのですか?
デバッグとは、頭のなかの動作イメージと実際の動作を比べて問題点を探し出すことにあります。
なので、頭のなかにこういう値になるはずというイメージがないとデバッグは出来ません。
逆に言えば、そのイメージ無しに出来たプログラムは実は自分でもよく分かっていないプログラムってことになります。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 17:43
by みけCAT
もしかして、(x|y)_Drawとか(x|y)_e1は画像の左上の座標ですか?
でしたら、条件式中の変数の代わりに、その変数に該当する画像の半径を足した値を使ってください。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 18:29
by sozai
>softya様
ソースコードを確認したところ、誤ってx_Drawが0で初期化されていましたので直したのですが、x_de1はいまだに-250のままです。
何が起きているのかさっぱりです。
みけCAT さんが書きました:もしかして、(x|y)_Drawとか(x|y)_e1は画像の左上の座標ですか?
でしたら、条件式中の変数の代わりに、その変数に該当する画像の半径を足した値を使ってください。
>みけCAT様
x_Drawが0の時アイコンは右半分しか表示されないのでそうではないのだと思います。
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 18:34
by みけCAT
x_Drawとx_e1の値はそれぞれどうなっていますか?
Re: 当たり判定の動作
Posted: 2013年8月16日(金) 18:36
by softya(ソフト屋)
x_Drawとx_e1もそれぞれ表示してみましょう。それは意図した値ですか?
デバッグとは、自分のやった事に疑い持ち、思い込みを排除するために色々と調べる事です。
こうなるはずだ → そうならない → 実は思い違い
と言うことです。
自分のやったこと全てを疑ってください。
Re: 当たり判定の動作
Posted: 2013年8月17日(土) 00:13
by sozai
当たり判定が動作するようになりました。
原因はおそらく、条件式を含む関数を二回呼び出していたことだと思います。
コード:
void Stage1(){
The_Func();
Other_Func();
Draw_enemy();
GameOverIF();
if(GameOverFlag) GameOver();
if(Key[ KEY_INPUT_SPACE ]>=1){
Scene = eScene_Menu;
}
}
コード:
bool GameOverFlag=false;
void GameOver_IF(){
int x_de1,x_de2;
int y_de1,y_de2;
x_de1 = (x_Draw-x_e1);
x_de2 = (x_Draw-x_e2);
y_de1 = (y_Draw-y_e1);
y_de2 = (y_Draw-y_e2);
printfDx("%d+%d<=%d\n\n",x_de1*x_de1,y_de1*y_de1,88*88);
printfDx("x_de1=%d\tx_de1^2=%d\n\n",x_de1,x_de1*x_de1);
printfDx("x_Draw=%d\tx_e1=%d\n\n",x_Draw,x_e1);
if( x_de1*x_de1+y_de1*y_de1<=(75+13)*(75+13) ) {
GameOverFlag=true;
}else if( x_de2*x_de2+y_de2*y_de2<=(75+10)*(75+10) ) {
GameOverFlag=true;
}
}
コード:
void The_Func(){
//**********************************/
//色々な処理 /
// /
//**********************************/
GameOver_IF();
}
Re: 当たり判定の動作
Posted: 2013年8月17日(土) 00:35
by softya(ソフト屋)
少なくも関数の構成が分かりづらいことが原因だとは理解しました。
ただ、提示されたコードでは、2回呼んでも大丈夫なはずです。
で、関数の構成はこちらを参考に直されたほうが良いですよ。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/
d.1 メイン関数の作り方
d.2 複数のファイルにわけてコンパイルする
d.3 ゲームの設計と分割コンパイル(1)
d.4 ゲームの設計と分割コンパイル(2)
d.5 ゲームの設計と分割コンパイル(3)
d.6 管理部の作り方 (似た要素のまとめ方)
Re: 当たり判定の動作
Posted: 2013年8月17日(土) 01:03
by sozai
Tatu さんが書きました:
当たり判定をうまく行えないのは敵のy座標が増えっぱなしになっているからではないでしょうか。
描画の時は剰余演算子%を使ってごまかしているから正常であるように見えるだけなのでしょう。
>Tatu様
ありがとうございます。
遅すぎるとは思いますが、やっと仰ることの意味がわかりました。
次のようにコードを訂正しました。
コード:
void Draw_enemy(){
DrawRotaGraph(x_e1,y_e1,1.0,0.1,E_Load.teki_1,TRUE);
DrawRotaGraph(x_e2,y_e2,1.0,0.0,E_Load.teki_2,TRUE);
y_e1 += 2;
y_e2 += 4;
y_e1 = y_e1%480;
y_e2 = y_e2%480;
}
Re: 当たり判定の動作
Posted: 2013年8月17日(土) 01:07
by sozai
>softya様
わかりました。
では、そのサイト等を参考に一度、リファクタリングなどを行ってみます。
Re: 当たり判定の動作
Posted: 2013年8月17日(土) 10:49
by softya(ソフト屋)
リファクタリング後でも良いですけど、一度全部のコードを圧縮して添付してもらったほうがアドバイスが出来そうです。
Re: 当たり判定の動作
Posted: 2013年8月17日(土) 18:33
by sozai
>softya様
わかりました。では、次に書く日記に添付します。
当たり判定が動作しなかった原因はやはり、
座標が増加し続けるようだったので、そこのコードを訂正したら常に条件を満たせば動作するようになりました。
皆様、本当にありがとうございました。