ページ 1 / 1
シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 04:53
by 独学初心者
はじめまして。
シューティングゲームの館を見て、初めてVC++インストールしたような初心者です。
何とか、試行錯誤しながら理解して自機ショットを敵に当てて倒すことはできたのですが、逆がどうしてもできなくって困っています。
C2065で実際に(x*x)…と計算する際のx,y,rangeが定義されてないとなってしまいます…(エラー文はこれだけです)
あれ?
double x,y;
int range;
の下の定義が生きてない?
と思ったのでいろいろ試したのですが…多分もっと前とかでしくじってると思うのですがいかんせん見当がつかないです…
どこが悪いんでしょうか…?
void CollisionDetection2(){
for(int i=0;i<ENEMY_TOTAL_NUM;i++){//敵の最大数100体分ループ
if(EnemyShot.flag==1){//敵のショットが発射中なら
for(int j=0;j<ENEMY_TOTAL_SHOT_NUM;j++){//1組200個分のループ
if(EnemyShot.EnemyShots[j].flag==1){//1個でも発射中の弾があれば
if(Player.flag==1){//プレイヤーの表示中なら
double x,y;
int range;
x=(int)(EnemyShots[j].x-Player.x);//x=(弾のx位置-プレイヤーのx位置)
y=(int)(EnemyShots[j].y-Player.y);//x=(弾のy位置-プレイヤーのy位置)
range=9;//(弾の当たり判定)
break;
}
if((int)sqrt(x*x+y*y) < range+Player.range){
EnemyShot.flag=0;
break;
}
}
}
}
}
}
また、これに伴い
Global、Externの両方の.hのプレイヤーの構造体にrangeとflagを足して
initial.cppに
Player.range=25;
Player.flag=1;
それから
PlayerControl.cppに
if(Player.flag==1){
DrawGraph((int)Player.x,(int)Player.y,img_player[0],TRUE);//プレイヤーを描画
}
の一文追加しています
(このプログラムコードは管理人によって字下げされました)
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 09:52
by Mist
ソースコードは規約を読んで字下げしてください。
変数の有効範囲について勉強してください。
if(Player.flag==1){//プレイヤーの表示中なら
double x,y;
int range;
x=(int)(EnemyShots[j].x-Player.x);//x=(弾のx位置-プレイヤーのx位置)
y=(int)(EnemyShots[j].y-Player.y);//x=(弾のy位置-プレイヤーのy位置)
range=9;//(弾の当たり判定)
break;
}
if((int)sqrt(x*x+y*y) < range+Player.range){
今回のようにifの中で変数を宣言した場合、その変数が有効なのはifの中だけになります。
そのため、次のifでその変数を使用するとコンパイラはその変数は存在しないというエラーになります。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 14:17
by 独学初心者
Mist様
読み辛いものを上げてしまい申し訳ないです。以後気をつけます;
また読みづらいにも関わらず御返答いただきありがとうございました。
break下の } を変えたら無事起動できました。
それと、良く読むと結構 EnemyShot. を付け忘れてるとこがあったので、double x,y の計算と最後の弾が当たったら消える…という所にも追加してみました。
結果…見事に貫通です;
当たったら弾が消えるで当たり判定だけ見たいんですが、プログラミング自体を始めて1週間、なかなか難しいもんです…
代入してる項目に何か問題があるんだろうか?と思うのですが…
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 14:35
by 管理人
コードは見易いように修正しておきました。
投稿された生データみましたが、コピペされた時点で正確な字下げが出来ていなかったようでした。
字下げしないと括弧の対応の把握が困難でバグの元になるので、
きちんと字下げすることオススメします。
後、貫通するのは、たまたまその判定円の中に入っていなかったのではないでしょうか?
例えば・・
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 14:51
by 管理人
黒丸が自機だと思って下さい。
今赤い弾が自機に向かって飛んできているとします。
弾は1つです。モーションがわかりやすいように時間ごとの様子を表現しています。
場合1はこの瞬間黒にあたったことが判定出来ますね。
しかし場合2のようにすごい速さで弾が飛んできている時は、丁度そのフレームでは弾同士が当たらないかもしれません。
数学でならったような方程式で交点を求めているわけではなく、
単に弾を移動させて、そこであたったかどうか見ているだけなので、条件にあわないこともあります。
ですから、場合2の場合でも場合1のように弾の当たり判定の大きさずつ移動させてあたったかどうかシミュレートしてみなければいけません。
または、方程式などで軌跡を計算して当たり判定を計算する方法もあると思います。
計算スピードとしては方程式で解く方が早いでしょうけど、めんどうだったので、
龍神録では弾の当たり判定ずつ移動させてあたったかどうかシミュレートする方法とっています。
もしバグの原因がこれじゃなかったらごめんなさい。
それから当たり判定の計算はdouble型でやった方がいいと思いますよ。
弾の移動速度をゆっくりにしても貫通するならこれが原因じゃありません。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 19:02
by 独学初心者
管理人様
丁寧に図までつけていただきありがとうございます。
スピードは4.0から1.0まで落として試してみたのですが、どうやらだめみたいです;
構文エラーはMist様のおかげで解消できたので、式として成り立ってはいるはずなのですが…
とりあえず、現在管理人様にいただいたアドバイス等を元に作ったソースがこんな形になりました。
/*enemy_shot.cpp内*/
void CollisionDetection2(){
for(int i=0;i<ENEMY_TOTAL_NUM;i++){//敵の最大数100体分ループ
if(EnemyShot.flag==1){//敵のショットが発射中なら
for(int j=0;j<ENEMY_TOTAL_SHOT_NUM;j++){//1組200個分のループ
if(EnemyShot.EnemyShots[j].flag==1){//1個でも発射中の弾があれば
if(Player.flag==1){//プレイヤーの表示中なら
double x,y;
int range;
x=(double)(EnemyShot.EnemyShots[j].x-Player.x);//x=(弾のx位置-プレイヤーのx位置)
y=(double)(EnemyShot.EnemyShots[j].y-Player.y);//x=(弾のy位置-プレイヤーのy位置)
range=20;//(弾の当たり判定)
break;
if((double)sqrt(x*x+y*y) < range+Player.range){
EnemyShot.EnemyShots[j].flag=0;
break;
}
}
}
}
}
}
}
式自体が無効になってしまってるんでしょうか?
main.cppの方にもexternもwhile以下も書いてはあるんですが…
それともinitial.cppに貼り付けたPlayer.range=25とかがまずいのでしょうか?
構造体には追加してるので、有効かと思うんですが…
うーん…;
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 19:12
by 御津凪
当たり判定の所で、ブレイクポイントをセットして、
プログラムがそこを通るか、チェックしたほうが良いかもしれませんね。
式的には合っているようですし。
もしかしたら関数が呼ばれていないかもしれないし、
フラグの立て間違いで当たり判定チェックまで届いていないかもしれません。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 19:24
by 管理人
プログラミングを始めて1週間ということで、ブレイクポイントをご存知ないかもしれないので、一応補足を。
まず、VC++の画面のメニューバー付近に「Debug」または「Release」どちらかが表示されていると思います。
Debugになっている場合はそれでOKで、ReleaseになっていたらDebugにして下さい。
そして、プログラムを書くエディタのすぐ左側にクリックできるスペースがあります。
そこをクリックすると、赤い●が表示されます。
SSをご覧下さい。
この●の位置まで処理が来ると自動的に処理をとめてくれます。
また、同時にその時その変数に何の値が入っているか表示してくれます。
このサンプルに使ったプログラムはこちらです。
aの値は常に変わっているので、パッとみ、何が入ってるかわからないですよね。
でもSSのように自動変数の表示で確認出来ます。
なので、ブレイクポイントを使うと
「そこまで処理がきているか」「そこの変数に何が入っているか」の2つが確認できるわけです。
デバッグを実行するときはF5を押します。
デバッグは必要ない時にはデバッグ無しの実行であるCtrl+F5を押しましょう。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 23:02
by 独学初心者
御津凪様、管理人様
ご返答ありがとうございます。
ブレイクポイントでデバックしたところ、プレイヤーのショットと比較して
発射された弾が実際に描写される前(発射音の時点)でウィンドウが止まる
見てみると発射されてないからか、どうやらdouble x,yの値を求める計算になるときに
EnemyShot
まではフラグも立ってるんですが
これがEnemyShot.EnemyShots[j]
EnemyShot.EnemyShots[j]={flag=0,x=0.000000000000,y=0.000000000000}
になってしまってるみたいです。
実際にプレイヤーのショットの同じ項をブレイクポイントで指定してみたところ
ちゃんと弾が発射された状態でウィンドウが閉じ
PlayerShotもflagが1でxもyもウィンドウが消える直前、つまりちゃんと発射後の状態になっていました。
デバックの際EnemyShotとEnemyShot.EnemyShots[j]の間にEnemyShot.EnemyShotsという項がありましたが、ここですでに全てが0にリセット状態になっているためか、最後の
if((double)sqrt(x*x+y*y) < range+Player.range)
の式はスルーされちゃってるみたいです。
ヘッダの構造体かとおもっていじってみたりもしたのですが、一向に直る気配がないです;
なので一応今のヘッダの構造体Global.hの構造体部分を載せておきます。
// 敵のショットの構造体
typedef struct{
int flag;
double x,y;
} ENEMY_SHOTS_t;
ENEMY_SHOTS_t EnemyShots[ENEMY_TOTAL_SHOT_NUM];//[2000];
typedef struct{
int pattern,counter,img,range;
double x,y,mem_ex,mem_ey,mem_px,mem_py,Angle[ENEMY_TOTAL_SHOT_NUM];//[2000];
ENEMY_SHOTS_t EnemyShots[ENEMY_TOTAL_SHOT_NUM];//[2000];
int flag;
} ENEMY_SHOT_t;
ENEMY_SHOT_t EnemyShot[ENEMY_TOTAL_NUM];//[100];
Extern側は、ENEMY_SHOTS_t、ENEMY_SHOT_tの前にexternがついてます。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 23:39
by 独学初心者
すみません、やっぱり構造体のミスでx,yが算出できなかったみたいで、EnemyShotの側のx,y直したら算出できました。
…が、やっぱりif((double)sqrt(x*x+y*y) < range+Player.range){の行にさしかかるとスルーです;
どうしたものですか…
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月23日(木) 23:57
by 管理人
スルーというのはどういうことでしょう?
もし条件文に入らないのならその時x,y、rangeなどの値はどうなっていますか?
どのように値が遷移しているか確認していけば解ると思います。
なお、x,yがdoubleならdoubleでキャストする必要はありません。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月24日(金) 00:17
by 独学初心者
管理人様
ご返答ありがとうございます。
ブレイクポイントの●をその行に打つと、例えばdouble x,yの値を求める式とかは計算が発生したらウィンドウが閉じて自動変数等の表示がされるところ、この所に来ると自機と弾が重なっても全くそんな素振りもなく、といった感じです;
それと先程書き忘れましたが、弾自体の座標のxとyはどうやらウィンドウ閉じる時点で敵機と全く一緒の様です。
発生した瞬間にウィンドウを閉じてるのか、プレイヤーショットの同じ行の場合、ショット発生してちょっと前に飛んでウィンドウが閉じてるのですが…座標もウィンドウが消えた時点の座標の様です
また判定されてないsqrtの文もプレイヤー側だとショット押した瞬間にウィンドウが閉じて計算されてる様なのですが、その辺もどうしてなのか色々やってみてはいるのですが…;
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月24日(金) 00:31
by 管理人
う~ん。。。やはりプログラムの全文がないとこれだけではよくわからないです・・。
もし解決しないようならこちらにプロジェクト一式送ってもらえませんか?
どこが悪いか見てみます。
その際はデータは最小限でいいです。例えば音楽ファイルとか重くなりそうなら添付しないでOKです。
プロジェクトのファイルは~~.slnと~~.vcprojだけで大丈夫です。
特に~~.ncbファイルはいらないのに10M位あると思うのでどけておいて下さい。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月24日(金) 01:13
by Justy
スレを読んでも今ひとつ、何が起きているのかよくわからないのですが、
気になるところが1点。
これはもう修正されていますか?
[color=#d0d0ff" face="monospace]
if(Player.flag==1){//プレイヤーの表示中なら
double x,y;
int range;
x=(double)(EnemyShot.EnemyShots[j].x-Player.x);//x=(弾のx位置-プレイヤーのx位置)
y=(double)(EnemyShot.EnemyShots[j].y-Player.y);//x=(弾のy位置-プレイヤーのy位置)
range=20;//(弾の当たり判定)
break;
if((double)sqrt(x*x+y*y) < range+Player.range){
[/color]
ここに breakがあると、いつまで経っても距離判定の if文には来ないような・・・。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月24日(金) 01:17
by 管理人
なるほど・・原因はそれですね・・。
Re:シューティング、自機の当たり判定ががが…
Posted: 2008年10月24日(金) 02:17
by 独学初心者
管理人様、Justy様
ご返答ありがとうございました。
先ほど駄目なようなら…と言っていただき、なるだけご迷惑を…と思って自力でがんばっていたらキーボードに突っ伏していて大惨事に…;;
beak…そ、そっか!
最初に } 取ったときに、構文エラーが直ったので「そーなのかー」とそこでストップしてて気がついてなかったです;
そうですよね…そこの } が下に移ったのだから弾が消えるようにしたその後のbreakが…
このbreak消して無事弾消えました!!
ご返答くださった皆様、本当にありがとうございました!
すっごく初歩な質問にも暖かく答えていただき、大変感謝です!
重ねてありがとうございました!