シューティング、自機の当たり判定ががが…

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
独学初心者

シューティング、自機の当たり判定ががが…

#1

投稿記事 by 独学初心者 » 16年前

はじめまして。
シューティングゲームの館を見て、初めて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);//プレイヤーを描画
}
の一文追加しています
 
 
(このプログラムコードは管理人によって字下げされました)

Mist

Re:シューティング、自機の当たり判定ががが…

#2

投稿記事 by Mist » 16年前

ソースコードは規約を読んで字下げしてください。

変数の有効範囲について勉強してください。
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:シューティング、自機の当たり判定ががが…

#3

投稿記事 by 独学初心者 » 16年前

Mist様
読み辛いものを上げてしまい申し訳ないです。以後気をつけます;
また読みづらいにも関わらず御返答いただきありがとうございました。
break下の } を変えたら無事起動できました。

それと、良く読むと結構 EnemyShot. を付け忘れてるとこがあったので、double x,y の計算と最後の弾が当たったら消える…という所にも追加してみました。

結果…見事に貫通です;

当たったら弾が消えるで当たり判定だけ見たいんですが、プログラミング自体を始めて1週間、なかなか難しいもんです…

代入してる項目に何か問題があるんだろうか?と思うのですが…

管理人

Re:シューティング、自機の当たり判定ががが…

#4

投稿記事 by 管理人 » 16年前

コードは見易いように修正しておきました。
投稿された生データみましたが、コピペされた時点で正確な字下げが出来ていなかったようでした。
字下げしないと括弧の対応の把握が困難でバグの元になるので、
きちんと字下げすることオススメします。

後、貫通するのは、たまたまその判定円の中に入っていなかったのではないでしょうか?
例えば・・

管理人

Re:シューティング、自機の当たり判定ががが…

#5

投稿記事 by 管理人 » 16年前

黒丸が自機だと思って下さい。
今赤い弾が自機に向かって飛んできているとします。
弾は1つです。モーションがわかりやすいように時間ごとの様子を表現しています。

画像

場合1はこの瞬間黒にあたったことが判定出来ますね。
しかし場合2のようにすごい速さで弾が飛んできている時は、丁度そのフレームでは弾同士が当たらないかもしれません。
数学でならったような方程式で交点を求めているわけではなく、
単に弾を移動させて、そこであたったかどうか見ているだけなので、条件にあわないこともあります。
ですから、場合2の場合でも場合1のように弾の当たり判定の大きさずつ移動させてあたったかどうかシミュレートしてみなければいけません。
または、方程式などで軌跡を計算して当たり判定を計算する方法もあると思います。
計算スピードとしては方程式で解く方が早いでしょうけど、めんどうだったので、
龍神録では弾の当たり判定ずつ移動させてあたったかどうかシミュレートする方法とっています。
もしバグの原因がこれじゃなかったらごめんなさい。

それから当たり判定の計算はdouble型でやった方がいいと思いますよ。

弾の移動速度をゆっくりにしても貫通するならこれが原因じゃありません。

独学初心者

Re:シューティング、自機の当たり判定ががが…

#6

投稿記事 by 独学初心者 » 16年前

管理人様
丁寧に図までつけていただきありがとうございます。
スピードは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:シューティング、自機の当たり判定ががが…

#7

投稿記事 by 御津凪 » 16年前

当たり判定の所で、ブレイクポイントをセットして、
プログラムがそこを通るか、チェックしたほうが良いかもしれませんね。
式的には合っているようですし。

もしかしたら関数が呼ばれていないかもしれないし、
フラグの立て間違いで当たり判定チェックまで届いていないかもしれません。

管理人

Re:シューティング、自機の当たり判定ががが…

#8

投稿記事 by 管理人 » 16年前

プログラミングを始めて1週間ということで、ブレイクポイントをご存知ないかもしれないので、一応補足を。
まず、VC++の画面のメニューバー付近に「Debug」または「Release」どちらかが表示されていると思います。
Debugになっている場合はそれでOKで、ReleaseになっていたらDebugにして下さい。
そして、プログラムを書くエディタのすぐ左側にクリックできるスペースがあります。
そこをクリックすると、赤い●が表示されます。
SSをご覧下さい。

画像

この●の位置まで処理が来ると自動的に処理をとめてくれます。
また、同時にその時その変数に何の値が入っているか表示してくれます。
このサンプルに使ったプログラムはこちらです。

aの値は常に変わっているので、パッとみ、何が入ってるかわからないですよね。
でもSSのように自動変数の表示で確認出来ます。
なので、ブレイクポイントを使うと
「そこまで処理がきているか」「そこの変数に何が入っているか」の2つが確認できるわけです。

デバッグを実行するときはF5を押します。
デバッグは必要ない時にはデバッグ無しの実行であるCtrl+F5を押しましょう。

独学初心者

Re:シューティング、自機の当たり判定ががが…

#9

投稿記事 by 独学初心者 » 16年前

御津凪様、管理人様
ご返答ありがとうございます。
ブレイクポイントでデバックしたところ、プレイヤーのショットと比較して

発射された弾が実際に描写される前(発射音の時点)でウィンドウが止まる
見てみると発射されてないからか、どうやら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:シューティング、自機の当たり判定ががが…

#10

投稿記事 by 独学初心者 » 16年前

すみません、やっぱり構造体のミスでx,yが算出できなかったみたいで、EnemyShotの側のx,y直したら算出できました。

…が、やっぱりif((double)sqrt(x*x+y*y) < range+Player.range){の行にさしかかるとスルーです;

どうしたものですか…

管理人

Re:シューティング、自機の当たり判定ががが…

#11

投稿記事 by 管理人 » 16年前

スルーというのはどういうことでしょう?
もし条件文に入らないのならその時x,y、rangeなどの値はどうなっていますか?
どのように値が遷移しているか確認していけば解ると思います。
なお、x,yがdoubleならdoubleでキャストする必要はありません。

独学初心者

Re:シューティング、自機の当たり判定ががが…

#12

投稿記事 by 独学初心者 » 16年前

管理人様
ご返答ありがとうございます。

ブレイクポイントの●をその行に打つと、例えばdouble x,yの値を求める式とかは計算が発生したらウィンドウが閉じて自動変数等の表示がされるところ、この所に来ると自機と弾が重なっても全くそんな素振りもなく、といった感じです;

それと先程書き忘れましたが、弾自体の座標のxとyはどうやらウィンドウ閉じる時点で敵機と全く一緒の様です。

発生した瞬間にウィンドウを閉じてるのか、プレイヤーショットの同じ行の場合、ショット発生してちょっと前に飛んでウィンドウが閉じてるのですが…座標もウィンドウが消えた時点の座標の様です

また判定されてないsqrtの文もプレイヤー側だとショット押した瞬間にウィンドウが閉じて計算されてる様なのですが、その辺もどうしてなのか色々やってみてはいるのですが…;

管理人

Re:シューティング、自機の当たり判定ががが…

#13

投稿記事 by 管理人 » 16年前

う~ん。。。やはりプログラムの全文がないとこれだけではよくわからないです・・。
もし解決しないようならこちらにプロジェクト一式送ってもらえませんか?
どこが悪いか見てみます。
その際はデータは最小限でいいです。例えば音楽ファイルとか重くなりそうなら添付しないでOKです。
プロジェクトのファイルは~~.slnと~~.vcprojだけで大丈夫です。
特に~~.ncbファイルはいらないのに10M位あると思うのでどけておいて下さい。

Justy

Re:シューティング、自機の当たり判定ががが…

#14

投稿記事 by Justy » 16年前

 スレを読んでも今ひとつ、何が起きているのかよくわからないのですが、
気になるところが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:シューティング、自機の当たり判定ががが…

#15

投稿記事 by 管理人 » 16年前

なるほど・・原因はそれですね・・。

独学初心者

Re:シューティング、自機の当たり判定ががが…

#16

投稿記事 by 独学初心者 » 16年前

管理人様、Justy様
ご返答ありがとうございました。
先ほど駄目なようなら…と言っていただき、なるだけご迷惑を…と思って自力でがんばっていたらキーボードに突っ伏していて大惨事に…;;

beak…そ、そっか!
最初に } 取ったときに、構文エラーが直ったので「そーなのかー」とそこでストップしてて気がついてなかったです;
そうですよね…そこの } が下に移ったのだから弾が消えるようにしたその後のbreakが…

このbreak消して無事弾消えました!!


ご返答くださった皆様、本当にありがとうございました!
すっごく初歩な質問にも暖かく答えていただき、大変感謝です!
重ねてありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る