ページ 12

当たり判定について

Posted: 2010年8月11日(水) 21:21
by たろう
http://www.play21.jp/board/formz.cgi?ac ... &rln=58432
について質問したものですが、返信遅れて申し訳ありません。
当たり判定の処理が出来たのですが、ソースが汚い感じでどうしたらスマートにきれいに出来るのかわかりません。
何かヒントでいいので助言よろしくお願いします。
int atarihantei(float x1,float y1,float x2,float y2,float angle,float spd1,float spd2,float rang1, float rang2)
{
    float r=rang1+CRANG;
    float r2=rang2+CRANG;
    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<(r+r2)*(r+r2))
        return 1;
    if(spd1<0)
        spd1=-1*spd1;
    if(spd2<0)
        spd2=-1*spd2;
    if(spd1+spd2>r)
    {
        
        float pre_x1=x1+cos(0.0)*(spd1+spd2),pre_y1=y1+sin(0.0)*(spd1+spd2);
        float pre_x2=x2,pre_y2=y2;
        float now_x,now_y;
        for(int i=0;i<(spd1+spd2)/(r+r2)-1;i++)
        {
            now_x=pre_x1-pre_x2;
            now_y=pre_y1-pre_y2;
            if(now_x*now_x+now_y*now_y<(r+r2)*(r+r2))
            {
                return 1;
            }
            if(i>=(int)((spd1+spd2)/(r+r2))-1)
            {
                break;
            }
            
            if(i==(int)((spd1+spd2)/(r+r2))-2)
            {
                float t=((spd1+spd2)-i*(r+r2));
                pre_x1-=cos(PI)*t;
                pre_y1-=sin(PI)*t;
            }
            else
            {
                float t=cos(PI)*(r+r2);
                float t2=sin(PI)*(r+r2);
                
                pre_x1+=t;
                pre_y1+=t;
            }
        }
    }

    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<(r+r2)*(r+r2))
        return 1;
    return 0;
}

Re:当たり判定について

Posted: 2010年8月11日(水) 21:34
by たろう
ソース変更したので載せます。
int atarihantei(float x1,float y1,float x2,float y2,float angle,float spd1,float spd2,float rang1, float rang2)
{
    float r=rang1+CRANG;
    float r2=rang2+CRANG;
    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<(r+r2)*(r+r2))
        return 1;
    if(spd1<0)
        spd1=-1*spd1;
    if(spd2<0)
        spd2=-1*spd2;
    if(spd1+spd2>r)
    {
        
        float pre_x1=x1+cos(0.0)*(spd1+spd2),pre_y1=y1+sin(0.0)*(spd1+spd2);
        float pre_x2=x2,pre_y2=y2;
        float now_x,now_y;
        for(int i=0;i<(spd1+spd2)/(r+r2);i++)
        {
            now_x=pre_x1-pre_x2;
            now_y=pre_y1-pre_y2;
            if(now_x*now_x+now_y*now_y<(r+r2)*(r+r2))
            {
                return 1;
            }            
            if(i==(int)((spd1+spd2)/(r+r2))-1)
            {
                float t=((spd1+spd2)-i*(r+r2));
                pre_x1-=cos(PI)*t;
                pre_y1-=sin(PI)*t;
            }
            else
            {
                float t=cos(PI)*(r+r2);
                float t2=sin(PI)*(r+r2);
                
                pre_x1+=t;
                pre_y1+=t;
            }
        }
    }

    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<(r+r2)*(r+r2))
        return 1;
    return 0;
}

Re:当たり判定について

Posted: 2010年8月12日(木) 05:29
by めるぽん
スピードが大きいときは x1, y1 の円の位置を戻していって計算しているみたいなのですが、
cos(0) は 1 で、cos(PI) は -1、sin(0), sin(PI) は 0 ということを考えると、これはお互いに横方向に移動している場合しか正しく計算されないように見えます。
そもそも引数に早さのパラメータはあるのに、それがどの方向なのかというパラメータが無いような気がしますね。


2D上で、お互いに高速に移動している円同士の当たり判定を行うのは、自分が思いつく限り以下の方法があります。

1.移動のフレームレートを上げる。
 最近のマシンならオブジェクトの移動で使う時間なんてよっぽどすごいことをやってない限り 0 に等しいので、例えば1フレームの間に10回移動させてやっても結構平気だったります。こうすることでトンネリングの発生する確率はかなり低くなると思います。
for (int i = 0; i < 10; i++)
    objs.move_all();
objs.draw_all();
2.円が移動してできた軌跡同士で当たり判定を行う。
 "円が移動してできた軌跡"というのは競技場のトラックみたいな形です。3Dではカプセル形って言うのですが、2Dの場合は何て呼ぶのかは分かりません。とりあえず今はカプセル形と呼びます。
 カプセル形同士が当たっているかどうかを判定することで、トンネリングが発生することは無くなります。カプセル形同士の当たり判定の計算はそんなに難しくないです。
 ただし、明らかに当たってない場合も当たってしまうと判断されてしまう場合があります。まあ 60FPS で動くようなゲームであれば気がつくことはまず無いとは思いますが。

3.二分探索を行う
 s=0.0 を最初の位置の時間、e=1.0 を最後の位置の時間、sからeまでの軌跡(カプセル形)同士の計算を行います。ここまでは2.と同じ。
 もし当たっていた場合は、s=0.0からe=0.5の範囲のカプセル形同士で当たっているかどうかと、s=0.5からe=1.0の範囲のカプセル形同士で当たっているかを調べます。これらが当たっているかどうかで更に当たっている範囲を絞り込んでいきます(図が無いと分かりにくいですね・・・)。
 こうすることで、2.のような間違って当たっていると判断されることも無くなり、移動の最初の時間から最後の時間の間の、どの時間で当たったのかというのも分かるようになります。

Re:当たり判定について

Posted: 2010年8月12日(木) 19:14
by たろう
回答ありがとうございます。
>3.二分探索を行う。
二分探索を数学の何を勉強すればよいのでしょうか?

Re:当たり判定について

Posted: 2010年8月12日(木) 20:44
by たろう
すみません。二分探索は数学ではないですね。
二分探索でどうやってやるのでしょうか。

Re:当たり判定について

Posted: 2010年8月12日(木) 20:57
by めるぽん
二分探索法自体は有名なアルゴリズムなのでちょっとグーグル先生に聞けば教えてくれると思います。
ただこの3.の方法は、ほんとに二分探索と言っていいのかちょっと分からないです(これは安易に自分が二分探索って言っちゃったのがいけませんね)
3.の内容も含めて、当たり判定のアルゴリズム全般は、自分は『ゲームプログラミングのためのリアルタイム衝突判定』という本で勉強しました。ただこれは少し内容が難しいかもしれません。

Re:当たり判定について

Posted: 2010年8月13日(金) 18:06
by たろう
新たに作り直したので載せます。
実行した感じは当たり判定は出来ていると思うのですが、これではダメでしょうか?
int atarihantei(float x1,float y1,float x2,float y2,float angle,float spd1,float spd2,float rang1, float rang2)
{
    float r=rang1+CRANG;
    float r2=rang2+CRANG;
    if(spd1<0)
        spd1=-1*spd1;
    if(spd2<0)
        spd2=-1*spd2;
        if(spd1+spd2>r+r2){

            double pre_x=x1+cos(atan2(x1-x2,y1-y2))*(spd1+spd2);
            double pre_y=y1+sin(atan2(x1-x2,y1-y2))*(spd1+spd2);
            double px,py;
            for(int j=0;j<(spd1+spd2)/(r+r2);j++){
                px=pre_x-x2;
                py=pre_y-y2;
               if(px*px+py*py<(r+r2)*(r+r2))
                   return 1;
               if(j==(int)((spd1+spd2)/(r+r2))-1){
                    pre_x+=cos(atan2(x1-x2,y1-y2)+PI)*((spd1+spd2)-(j*(r+r2)));
                    pre_y+=sin(atan2(x1-x2,y1-y2)+PI)*((spd1+spd2)-(j*(r+r2)));
               }
               else{
                    pre_x+=cos(atan2(x1-x2,y1-y2)+PI)*(r+r2);
                    pre_y+=sin(atan2(x1-x2,y1-y2)+PI)*(r+r2);
               }
            }
        }
    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<(r+r2)*(r+r2))
        return 1;
}

Re:当たり判定について

Posted: 2010年8月13日(金) 18:28
by 組木紙織
高速に移動する物体の当たり判定についてはワードにまとめているものがあります。(まだ未完成ですが)
計算手順の部分は日本語で書いてあるのでコードに直してください。

http://cid-c5316c7c226c93d9.office.live ... c%e9%96%8b

Re:当たり判定について

Posted: 2010年8月13日(金) 18:47
by たろう
返信ありがとうございます。
参考にしたいのですが計算式が載ってません。
あと、このソースだとだめという解釈でよろしいのでしょうか?

Re:当たり判定について

Posted: 2010年8月13日(金) 23:11
by たろう
できたらダメな(当たり判定ができない部分などの)理由など教えてくださると助かります。
わかる方いらしたらよろしくお願いします。

Re:当たり判定について

Posted: 2010年8月13日(金) 23:44
by めるぽん
2つの円は必ずお互いに反対の方向に進んでいるわけではなく、ばらばらな方向へ移動してますよね?
その atan2 の使い方だと、(x1,y1) が必ず (x2,y2) の方向に進んでいるという計算になる気がします。
パラメータにそれぞれの円が進む方向というパラメータが足りないので、そのパラメータを追加した上で、(x1,y1)の円だけでなく(x2,y2)も同時に動かす必要がありそうです。
あと atan2 は atan2(Y, X) のように Y 座標を先に指定するので、それも気をつける必要がありますね。
それから、r+r2ずつ移動させて計算すると、例えば
○↑
↓○
という感じでお互いに微妙にずれて(でも物理的に考えれば当たる)移動しているときに、トンネリングが発生する可能性があります。まあこれは分割して判定する方法を使っている限りはどうしようも無いので諦めるしか無いと思います。


コンパイルすらしていないので間違ってる可能性がかなり高いですけど、こんな感じではないでしょうか
// 動いてない円同士の当たり判定
int test_circle_circle(float x1, float y1, float r1, float x2, float y2, float r2)
{
    float x = x1 - x2;
    float y = y1 - y2;
    float r = r1 + r2;
    return x * x + y * y <= r * r;
}

// 動いている円同士の当たり判定
int atarihantei(
    // X座標, Y座標, 半径, 角度, 速度
    float x1, float y1, float r1, float a1, float v1,
    float x2, float y2, float r2, float a2, float v2)
{
    // 経過時間
    // 円がそれぞれ a1, a2 の方向に v1, v2 だけ進んだ時間を 1.0 とする
    float t = 0.0f;

    while (t < 1.0f)
    {
        // 初期位置から t だけ進んだ円同士の当たり判定を行う
        if (test_circle_circle(
            x1 + cos(a1) * v1 * t, y1 + sin(a1) * v1 * t, r1,
            x2 + cos(a2) * v2 * t, y2 + sin(a2) * v1 * t, r2))
        {
            return 1;
        }

        // 適当に時間を進ませる
        // ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
        t += 0.1f;
    }
    // 初期位置から 1.0 だけ進んだ円同士の当たり判定を行う
    return test_circle_circle(
        x1 + cos(a1) * v1, y1 + sin(a1) * v1, r1,
        x2 + cos(a2) * v2, y2 + sin(a2) * v1, r2);
}
まあこれだと効率がかなり悪いですけれども、参考になれば幸いです。

Re:当たり判定について

Posted: 2010年8月14日(土) 07:39
by シエル
私がやってる当たり判定方法は、まさにぬるぽんさんが説明していただいてる方法と
同じような感じです。

Re:当たり判定について

Posted: 2010年8月14日(土) 21:52
by たろう
めるぽんさん回答ありがとうございます。
すみません勉強不足で、まったくわかりません。
出来たら説明していただけないでしょうか。申し訳ないです。
それらは数学やアルゴリズムを勉強すればよいのでしょうか?
「ゲームプログラミングのためのリアルタイム衝突判定」読めばわかるようになるのでしょうか?

Re:当たり判定について

Posted: 2010年8月14日(土) 22:39
by たろう
あとソース変えてみました。
めるぽんさんのは参考にしていませんが、
以下のサイトを利用させていただきました。
http://www5d.biglobe.ne.jp/~tomoya03/sh ... ection.htm
これではどうでしょうか?
int atarihantei(float x1,float y1,float x2,float y2,float angle1,float angle2,float spd1,float spd2)
{
    float tc=(x1-y1+(cos(angle1)*spd1)*(y2-y1)+(y1-y1+sin(angle2)*spd1)*(x1-x2));
    float td=(x1-(y1+cos(angle1)*spd1))*((y2-sin(angle2)*spd2)-y1)+(y1-y1+sin(angle2)*spd1)*(x1-(x2-cos(angle2)*spd2));
    float ta=(x2-x2+cos(angle2)*spd2)*(y1-y2)+(y2-(y2+sin(angle2)*spd2))*(x2-x1);
    float tb=(x2-x2+cos(angle2)*spd2)*((y1+sin(angle1)*spd1)-y2)+(y2-(y2+sin(angle2)*spd2))*(x2-(x1+cos(angle1)*spd1));

    if(tc*td<0&&ta*tb<0)
    {

        return 1;
    }
    if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<(r+r2)*(r+r2))
        return 1;
    return 0;
}
ダメでしょうか?

Re:当たり判定について

Posted: 2010年8月15日(日) 18:17
by たろう
この方法はいいと思ったのですがどうでしょうか?
だめな理由をよろしくお願いします。

Re:当たり判定について

Posted: 2010年8月15日(日) 20:19
by 組木紙織
>だめな理由をよろしくお願いします。
何故駄目だと思ったのでしょうか?
その理由をお願いします。


>参考にしたいのですが計算式が載ってません。

No:58896
で私が提示したものには、ベクトルと二次関数が理解できれば分かるレベルで計算式と計算手順を載せているつもりです。
分からないとこを指摘していただければ解説します。


あと根本的な問題として、どのような状況の当たり判定を考えているのでしょうか?
具体的に説明をお願いします。

Re:当たり判定について

Posted: 2010年8月15日(日) 20:56
by たろう
組木紙織さん返信ありがとうございます。
>だめな理由をよろしくお願いします。
>何故駄目だと思ったのでしょうか?
>その理由をお願いします。
すいません。自分の載せたソースがダメな理由が聞きたっかただけです。
ダメじゃなければよいのですが?
どうでしょうか?これで大丈夫でしょうか?

>あと根本的な問題として、どのような状況の当たり判定を考えているのでしょうか?
>具体的に説明をお願いします。
龍神録の18章の当たり判定で相手のスピードが当たり判定の範囲以上の時の当たり判定を知りたいのです。
たとえばスピードが50で相手の当たり判定が4のとき通り抜けてしまうのでそれをなくしたいのです。
わかりにくかったらすみません。

>で私が提示したものには、ベクトルと二次関数が理解できれば分かるレベルで計算式と計算手順を載せている>つもりです。
>分からないとこを指摘していただければ解説します。

わからないのは提示していただいた文章から
1現在重なっているかどうかの判定
係数が負である場合は現在二円が重なっており、そうでない場合は離れている。これは一般的な静的な当り判定と同じである。

2平行移動の判定
係数aが0の場合は二円の運動方向ベクトルが同じなので同じ速度で同じ方向に平行移動をしている状況となる。時間がたっても二円の位置関係が変わらないので結果は1.と変わらない。

3時間間隔後の判定
時間間隔がたった後に当っているかどうかの判定は式(5)の二次式の時間にを入れることによって判定できる。

4時間によらずいつかは重なる可能性があるかどうかの判定
二次式の判別式の時は負の無限大~正の無限大の時間を考えたときに二円は重なる状況にある。の時は当らず、の場合のみ二円は当る可能性がある。

5次の時刻までに当り判定
1-3よりほとんどの場合の判定ができた。残る条件は現在当っておらず、次の時刻までに当り、次の時刻になったら離れるという場合である。最小値を取る時間が0~の間にあればよい。

の1は多分わかります。
多分ソースに載せた計算式ですよね?2からがわかりません。
すみません勉強不足で。
すみませんが説明よろしくおねがいします。

Re:当たり判定について

Posted: 2010年8月15日(日) 22:36
by 組木紙織
>解説
状況は分かりました。先に確認したいことがあるので後回し。

>>だめな理由をよろしくお願いします。
>>何故駄目だと思ったのでしょうか?
>>その理由をお願いします。
>すいません。自分の載せたソースがダメな理由が聞きたっかただけです。
>ダメじゃなければよいのですが?
>どうでしょうか?これで大丈夫でしょうか?

大丈夫かどうかの判断は(基本的に)私たち回答者にはできません。
判断できるのは質問者さんです。
今までいくつか方法が提案されていますが、それぞれ特徴があってどの方法が一番適切であるかは
(想像は出来ますが)質問者さんが判断することです。

線分交差法による当たり判定の方法は何故大丈夫だと考えているのでしょうか?
先ほど書いていただいたソースはどうして大丈夫だと思っているのでしょうか?

#線分交差法は厳密な意味で考えると駄目だとおもってます。
#ただ厳密性がどこまで必要かも考える必要がありますよね。

Re:当たり判定について

Posted: 2010年8月16日(月) 06:48
by たろう
>#線分交差法は厳密な意味で考えると駄目だとおもってます。
の理由を教えて下さい。

>#ただ厳密性がどこまで必要かも考える必要がありますよね。
とりあえず当たり判定が出来てればいいです。

Re:当たり判定について

Posted: 2010年8月16日(月) 07:42
by シエル
とりあえず、質問に対して全て答えたほうが良いのでは?
それと、実際に線分交差法で試してみて、正しく当たり判定できていたのですか?

Re:当たり判定について

Posted: 2010年8月16日(月) 08:26
by 組木紙織
>とりあえず当たり判定が出来てればいいです。
それを確認するのはあなたです。

>>#線分交差法は厳密な意味で考えると駄目だとおもってます。
>の理由を教えて下さい。
線分交差法のアルゴリズムを理解していればすぐわかるはずです。(と投げ返してみる)
その方法は円を使ってないからです。

#同じところを堂々巡りしてる。

Re:当たり判定について

Posted: 2010年8月16日(月) 09:27
by めるぽん
>出来たら説明していただけないでしょうか。申し訳ないです。
どの辺が分からなかったのでしょうか。

1.その atan2 の使い方だと、(x1,y1) が必ず (x2,y2) の方向に進んでいるという計算になる
2.パラメータを追加した上で(x1,y1)の円だけでなく(x2,y2)も同時に動かす
3.atan2 は atan2(Y, X) のように Y 座標を先に指定する
4.
○↑
↓○
という感じでお互いに微妙にずれて(でも物理的に考えれば当たる)移動しているときに、トンネリングが発生する可能性があります

5.コードのどこか

あと No:58970 のコードですが、計算式の単純なミスが多いようです。例えば
float tc=(x1-y1+(cos(angle1)*spd1)*(y2-y1)+(y1-y1+sin(angle2)*spd1)*(x1-x2));
は、上記のサイトを読む限りは、X1=x1, X2=x1+cos(angle1)*spd1, X3=x2, X4=x2+cos(angle2)*spd2 なので、
float tc=(x1-(x1+cos(angle1)*spd1))*(y2-y1)+(y1-(y1+sin(angle2)*spd1))*(x1-x2);
となるのではないでしょうか(適当に置き換えただけなのでまだ間違ってる可能性もありますが)

で、もし線分交差法で正しく計算できたとしても、以下のような場合(赤い円は移動先です)

http://twitpic.com/2f5jip/fulle=
最初の例と2番目の例は物理的に考えると明らかに当たっていると思うのですけど、線分が交差していないため、交差しないと判定されます。3番目の例は、物理的な時間経過を考えると当たっていないと予想されるのですけど、実際には線分が交差しているため当たっていると判断されます。

ただ物理シミュレーションみたいなことをする場合はもっと正確に計算した方がいいでしょうけど、60FPS でどんどん移動しているゲームでこれらが実際に問題になるかというと、あまり無いような気もします。だから組木紙織さんは
>#ただ厳密性がどこまで必要かも考える必要がありますよね。
と仰っているのだと思います。 画像

Re:当たり判定について

Posted: 2010年8月16日(月) 13:16
by たろう
返信ありがとうございます。
3番目の例は、物理的な時間経過を考えると当たっていないと予想されるのですけど、実際には線分が交差しているため当たっていると判断されます。
>物理的な時間経過を考えると当たっていないと予想されるのですけど、実際には線分が交差しているため当た>っていると判断されます。
実際は当たり判定されないと言うことでしょうか?
理解力がなくて申し訳ありません。



>ただ物理シミュレーションみたいなことをする場合はもっと正確に計算した方がいいでしょうけど、60FPS で>どんどん移動しているゲームでこれらが実際に問題になるかというと、あまり無いような気もします。だから>組木紙織さんは
>#ただ厳密性がどこまで必要かも考える必要がありますよね。
とは別に気になしなくてもよいと言うことでしょうか?

Re:当たり判定について

Posted: 2010年8月16日(月) 13:22
by たろう
シエルさん返信ありがとうございます。
>それと、実際に線分交差法で試してみて、正しく当たり判定できていたのですか?
見た感じは出来ていたと思います。
組木紙織 さん返信ありがとうございます。
>>>#線分交差法は厳密な意味で考えると駄目だとおもってます。
>>の理由を教えて下さい。
>線分交差法のアルゴリズムを理解していればすぐわかるはずです。(と投げ返してみる)
>その方法は円を使ってないからです。
当たり判定は出来ていいるということでしょうか?

Re:当たり判定について

Posted: 2010年8月16日(月) 13:47
by めるぽん
>実際は当たり判定されないと言うことでしょうか?
実際にあの小さい円があの軌道上を同時に移動したとして、当たると思いますか?

>別に気になしなくてもよいと言うことでしょうか?
それはたろうさんが考えることです。

Re:当たり判定について

Posted: 2010年8月16日(月) 22:41
by たろう
>実際にあの小さい円があの軌道上を同時に移動したとして、当たると思いますか?
思いました。これは間違った考えでしょうか?

Re:当たり判定について

Posted: 2010年8月16日(月) 23:24
by めるぽん
3番目の例を少しずつ動かしてみました。

http://twitpic.com/2fbos8/full

線分は交差していますが、円同士は当たっていませんよね。

>>別に気になしなくてもよいと言うことでしょうか?
>それはたろうさんが考えることです。
この線分交差による判定方法がダメだということではなく、こういった状況が発生したときに、たろうさんの作っているゲームはそれが許容できるのかどうかということになってきます。
で、それが許容できるかどうかというのはたろうさんにしか判断できないので、どの当たり判定の方法を使うのかはたろうさんが考えて決めることになります。

Re:当たり判定について

Posted: 2010年8月17日(火) 12:17
by たろう
>線分は交差していますが、円同士は当たっていませんよね。
当たっていないと言うことは、当たり判定ができていないということでしょうか?普通に考えると当たっていると言うことでしょうか?

>この線分交差による判定方法がダメだということではなく、こういった状況が発生したときに、たろうさんの>作っているゲームはそれが許容できるのかどうかということになってきます。
許容できる範囲だと思うのですが、
めるぽんさんならどうでしょうか?

Re:当たり判定について

Posted: 2010年8月17日(火) 12:24
by シエル
ぬるぽんさんではありませんが、少なくとも私は許容できる範囲ではありません。

Re:当たり判定について

Posted: 2010年8月17日(火) 15:24
by めるぽん
>当たっていないと言うことは、当たり判定ができていないということでしょうか?
>普通に考えると当たっていると言うことでしょうか?
「当たり判定ができている」や「普通に考える」というのがどういう意味なのかによりますね。
現実世界での連続的な移動に対するシミュレーションができているのかどうか、ということであれば、できていませんし、実際にそれをできるようにするのはかなり難しいと思います。
ただ、繰り返しになりますが、たろうさんの作っているゲームで許容できる範囲かどうかということであれば、たろうさんの考え次第ということになります。

>許容できる範囲だと思うのですが、
>めるぽんさんならどうでしょうか?
自分の意見はあまり関係無いと思うのですけれども、多分自分なら大抵のゲームは No:58917 で書いたようなコードにすると思います。
ただまあ、許容できないと感じたら atarihantei 関数の中身を書き換えるだけで済みますし、実際にどんどん作っていってから考えてもいいんじゃないでしょうか。

Re:当たり判定について

Posted: 2010年8月17日(火) 18:45
by たろう
めるぽんさん返信ありがとうございます。
話を戻しますが、「ゲームプログラミングのためのリアルタイム衝突判定」読めばわかるようになるのでしょうか?
あと、No:58917 で書いたソースで
// ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
t += 0.1f;
r1,r2,v1,v2からどうやって求めるのでしょうか?

Re:当たり判定について

Posted: 2010年8月18日(水) 00:31
by たろう
ヒントだけでもいいのでよろしかったら教えてください。よろしくお願いします。

Re:当たり判定について

Posted: 2010年8月18日(水) 01:33
by めるぽん
>「ゲームプログラミングのためのリアルタイム衝突判定」読めばわかるようになるのでしょうか?
この本の内容をちゃんと理解できれば、このコードぐらいはすぐに書けるようになると思います。

>// ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
>t += 0.1f;
これが何をやっているかというと、円の移動を 10 分割して判定してるだけです。
で、この値が 0.1f ではなく r1, r2, v1, v2 から適切に求めるべきと書いた理由は、v1 や v2 が r1 や r2 の 10 倍以上の大きさになっている場合にはやっぱりすり抜けてしまう現象が起きてしまう可能性が高くなってしまいますし、v1 や v2 が r1 や r2 より十分に小さい場合には 10 分割して判定するのは処理の無駄だからです。
ただ、v1 や v2 が r1 や r2 の 10 倍以上というのはあまり無いと思いますし、10 倍程度のコストなら大したこと無かったりするので、これで良かったりする可能性もあります。

で、それを踏まえた上でこの加算値を調整するのであれば、上記の問題を解消するために、半径に大して速度が小さいのであれば分割する回数を少なく(つまり加算値を大きくする)して、半径に大して速度が大きいのであれば分割する回数を増やす(つまり加算値を小さくする)ようにしましょう。
float get_atarihantei_add_time(float r1, float v1, float r2, float v2)
{
    // 半径に対する速度の割合
    float ratio1 = v1 / r1;
    float ratio2 = v2 / r2;
    // 大きい方を使う
    float max_ratio = ratio1 > ratio2 ? ratio1 : ratio2;
    // 割合が小さければ加算値を大きくして、割合が大きければ加算値を小さくする必要があるので、逆数にする
    //(ratio の計算を r / v として小さい方を求めても構わないけど説明のためにこうする)
    float rec = 1 / max_ratio;
    // 適当に分割する(この 10 という値は適当に調整する)
    float time = rec / 10;
    // つまりこれは、1フレームで半径と同じだけの量を進む場合には 0.1f となり 10 分割され、
    // 1フレームで半径の10倍の量を進む場合には 0.01f となり 100 分割されることになる。
    return time;
}

int atarihantei(...)
{
    ...
    t += get_atarihantei_add_time(r1, v1, r2, v2);
    ...
}
という感じでしょうか(例によって全然試していないので間違っている可能性があります)。


追記:v1 や v2 が 0 の場合は 0 除算になるので、v1 と v2 の両方が 0 の場合は特別な処理(例えば 1.0f を返すとか)をしてやる必要がありそうですね 画像

Re:当たり判定について

Posted: 2010年8月18日(水) 01:58
by たろう
返信ありがとうございます。読みながら考えてみたいと思います。
またわからなくなったら聞きたいと思いますのでそのときはよろしくお願いします。

Re:当たり判定について

Posted: 2010年8月18日(水) 10:19
by softya
横から失礼します。

>>「ゲームプログラミングのためのリアルタイム衝突判定」読めばわかるようになるのでしょうか?
>この本の内容をちゃんと理解できれば、このコードぐらいはすぐに書けるようになると思います。

まず、今まで出てきたコードを理解出来ないのに本の内容が理解できるか何とも言えません。高い本ですので、書店で眺めてみると良いと思います。
まずその前に高校数学が大事でしょう。数I~数IIIまで関係あるところをじっくり読みなおしてみてください。あと分からないコードを読むだけでなく、動かしてみて理解する事も必要だと思います。ダミーのmainを作ってどんなふうに動くか試されてはどうでしょうか?色んなポイントにprintfなどを挟みこんでみると分かりやすくなるかも知れません。

Re:当たり判定について

Posted: 2010年8月19日(木) 22:31
by たろう
>数I~数IIIまで関係あるところをじっくり読みなおしてみてください。
高校数学の関係あるところというのは何でしょうか?

Re:当たり判定について

Posted: 2010年8月19日(木) 22:56
by Poco
> 高校数学の関係あるところというのは何でしょうか?

根本的に必要なのは、自分が抱えている問題を数式で表す(立式)能力です。
数式を作成するにあたって、軌跡、領域、ベクトル、三角関数等が役に立つと思います。

Re:当たり判定について

Posted: 2010年8月19日(木) 23:40
by たろう
回答ありがとうございます。
軌跡、領域、ベクトル、三角関数ですね。勉強してみたいと思います。

Re:当たり判定について

Posted: 2010年8月20日(金) 00:02
by softya
私の教科書は古いので同じとは思えませんが、少なくとも三角関数と空間図形とベクトルはみっちりやることと、図形全般は必須として行列も何かと出てくるので理解しておいたほうが良いでしょう。

下記サイトの2D衝突編が理解できるとお望みのものが作れるようになると思います。
http://marupeke296.com/COL_main.html
極端なカーブを描いているものでなければ、楕円と楕円の衝突で時間成分を加味した当たり判定でほぼ実現出来ると思います。ただ、たろうさんのやろうとしてる当たり判定に必要な精度が分からないので断言はできません。

「失礼しました」
名前を打ち間違えていたので修正しました。
画像

Re:当たり判定について

Posted: 2010年8月20日(金) 23:45
by たろう
返信ありがとうございます。
参考のサイト利用させていただきます。わからなくった時はまたよろしくお願いします。

Re:当たり判定について

Posted: 2010年8月20日(金) 23:59
by たろう
楕円と楕円の衝突のところを理解できたら、出来るようになるのでしょうか?

Re:当たり判定について

Posted: 2010年8月21日(土) 00:41
by たろう
すみませんどこを具体的に読んでいいかわかりません。
楕円と楕円の衝突のところを読んでみたのですが、当たり判定でどこでどうやって使えばよいのかわかりません。すみません、ご教授願えませんでしょうか。

Re:当たり判定について

Posted: 2010年8月21日(土) 01:16
by softya
出来れば最初の方から理解していってください。
で、楕円を使うと良いといった理由は円範囲同士の当たり判定をする移動物体が例えば1/60秒間で10ピクセル移動するとして、当たり範囲が直径5ピクセルの円だったとしましょう。
この時、1/60秒前の位置から現在位置までの当たり判定を合成して絵で描くとどうなるかイメージできますか? 実際に図を書いて確認してみてください。

同様の質問が出てますのでそちらも参考に。
http://www.play21.jp/board/formz.cgi?ac ... &rln=59666t=

Re:当たり判定について

Posted: 2010年8月21日(土) 01:27
by たろう
イメージできました。10ピクセルの中に5ピクセル入っています。

Re:当たり判定について

Posted: 2010年8月21日(土) 01:35
by softya
本当にそうですか?
直線に10ピクセル分の点を打って、1ピクセルずつ移動しながら直径5ピクセルの円を11個書いてみてください。そんな絵になるでしょうか?

Re:当たり判定について

Posted: 2010年8月21日(土) 01:48
by たろう
できました。5ピクセルまでは5個5ピクセルの円は入っています。が6個目から1ピクセルずつ超えてしまいます。

Re:当たり判定について

Posted: 2010年8月21日(土) 02:05
by たろう
http://marupeke296.com/COL_2D_No7_EllipseVsEllipse.html
のなぜこの式になるのでしょうか?

Re:当たり判定について

Posted: 2010年8月21日(土) 11:47
by softya
>できました。5ピクセルまでは5個5ピクセルの円は入っています。が6個目から1ピクセルずつ超えてしまいます。

???
絵に書いてみてもらえますか。

>のなぜこの式になるのでしょうか?
私も式を完全に追っているわけではないので、ピンポイトで尋ねられても答えられというか、そもそも式のどの部分を解説して欲しいんでしょうか?

その前にその1からその6は理解されたのでしょうか?
少なくとも「その6 楕円と点の衝突」は先に理解すべきだと思いますが。
答えを急ぎ過ぎというか、一歩一歩しっかり理解していかないと応用はおぼつかないですよ。

Re:当たり判定について

Posted: 2010年8月21日(土) 18:05
by たろう
返信ありがとうございます。
拙いですが、絵に描いてみました。
>私も式を完全に追っているわけではないので、ピンポイトで尋ねられても答えられというか、そもそも式のどの部分を解説して欲しいんでしょうか?
式自体なぜこうなるのかわからないのです。

>その前にその1からその6は理解されたのでしょうか?
理解していませんでした。その6ですね。勉強してみます。

Re:当たり判定について

Posted: 2010年8月21日(土) 19:18
by softya
>拙いですが、絵に描いてみました。
やはり私の言いたいことは伝わっていなかったみたいです。
こちらも絵を用意してみました。
移動する当たり判定は、楕円に近似できるって意味です。
真ん中の黒棒が移動範囲で、円が当たり範囲、黒の楕円が近似できる当たり範囲です。


>>私も式を完全に追っているわけではないので、ピンポイトで尋ねられても答えられというか、そもそも式のどの部分を解説して欲しいんでしょうか?
>式自体なぜこうなるのかわからないのです。

そこに到るまでの計算式は理解されているのでしょうか?
間をすっ飛ばして理解できるとは思えないんですが。

Re:当たり判定について

Posted: 2010年8月22日(日) 12:16
by たろう
>移動する当たり判定は、楕円に近似できるって意味です。
>真ん中の黒棒が移動範囲で、円が当たり範囲、黒の楕円が近似できる当たり範囲です。
これを知ってどうなるというのでしょうか?

すみません理解力がなくて。。。

Re:当たり判定について

Posted: 2010年8月22日(日) 12:54
by softya
>これを知ってどうなるというのでしょうか?

当たり判定の根本的な問題をカバーするための楕円のテクニックを理解してもらうためです。

もっと根本的な当たり判定の話から理解してもらうほうが良いみたいですね。
この質問の流れも、そこが分かっていないと解決に持っていけない気がします。

絵を添えましたので見てください。
状況を説明するとAからBに移動する物体とCからDに移動する物体で1/60秒ごとに直径5ピクセルの円の当たり判定すると仮定しています。移動速度は10ピクセルです。
見てもらうとわかるのですが、円や線分の当たり判定ではABとCDの物体は当たり状態と判定されません。
これは理解できますか?

これらの問題を擬似的、あるいは何とかしようというのが当たり判定の様々な方法なのです。

Re:当たり判定について

Posted: 2010年8月22日(日) 13:04
by softya
少し例として悪かったので絵を修正。
これから明日の夜まで出かけますので申し訳ないですが返答できません。
今までの他の皆さんの話も含めて絵を書いてイメージを固めることと各当たり判定方式の問題点をちゃんと把握することを目指してくださいね。

Re:当たり判定について

Posted: 2010年8月22日(日) 18:09
by たろう
返信ありがとうございます。
>見てもらうとわかるのですが、円や線分の当たり判定ではABとCDの物体は当たり状態と判定されません。
これは理解できますか?
はい。
A,B,C,Dの5ピクセルの範囲内に入っていないのでそれはわかります。

Re:当たり判定について

Posted: 2010年8月24日(火) 18:36
by softya
えーと、結局現状はどうなっていますか?
なにも進んでない気がするんですが。

現状を確認してみましょう。
1つ1つ明確に答えてください。
1)自分の目指していて満足できる衝突判定アルゴリズムはありましたか?
2)線分交差法が問題があると言われていた理由が理解できましたか?
3)めるぽんさんのアルゴリズムは理解されましたか?
また、めるぽんさんのアルゴリズムに追加質問はないのでしょうか?
4)実は、楕円と楕円の衝突判定方法にも問題があります。
それは何か理解さていますでしょうか?

めるぽんの名前を間違っていたので修正。 画像

Re:当たり判定について

Posted: 2010年8月24日(火) 19:44
by たろう
返信ありがとうございます。
1)自分の目指していて満足できる衝突判定アルゴリズムはありましたか?
めるぽんさんのがいいのかと思いました。

2)線分交差法が問題があると言われていた理由が理解できましたか?
いいえ

3)めるぽんさんのアルゴリズムは理解されましたか?
すみませんが、いいえ、
float max_ratio = ratio1 > ratio2 ? ratio1 : ratio2;
// 割合が小さければ加算値を大きくして、割合が大きければ加算値を小さくする必要があるので、逆数にする
//(ratio の計算を r / v として小さい方を求めても構わないけど説明のためにこうする)
float rec = 1 / max_ratio;
のところの意味がわかりません。
4)実は、楕円と楕円の衝突判定方法にも問題があります。
いいえ。
こんな答え方しか答えられないのですがよろしくお願いします。

Re:当たり判定について

Posted: 2010年8月24日(火) 21:01
by softya
じゃあ、更に整理して見ましょう。

絵は、前のが分かりづらいので更に絵に変更を加えましたCD間の移動速度が極端に遅い場合です。
2)私の絵で示したつもりですが、「その2」の場合、当たりと判定すべきでしょうか?それとも当たらなかったとみなすべきでしょうか?(もちろん、線分交差法では当たりではありません)
衝突判定も含めゲームは計算式の理解も大事ですがイメージ力を使って動きを理解しプログラムする側面が大きいです。

3)に関しては根本として
>これが何をやっているかというと、円の移動を 10 分割して判定してるだけです。
辺のことが、まず理解出来ている必要があります。
何のために10分割するか考えてみましたか?
10分割でダメな場合と10分割で無駄な場合ってなんでしょう?

4)に関しては課題としましょう。紙に色々と絵を書いて考えてみてください。

Re:当たり判定について

Posted: 2010年8月24日(火) 23:56
by たろう
>2)私の絵で示したつもりですが、「その2」の場合、当たりと判定すべきでしょうか?それとも当たらなかったとみなすべきでしょうか?(もちろん、線分交差法では当たりではありません)
A,Bの範囲に入っていないので当たり判定とみなしません。
>何のために10分割するか考えてみましたか?
>3)に関しては根本として
>10分割でダメな場合と10分割で無駄な場合ってなんでしょう?
10分割は長さを細かく計るためにするに10分割すると思いました。
10分割でダメな理由は10分割を細かくしたよりも小さい長さを求められないからだと思います。
>4)に関しては課題としましょう。紙に色々と絵を書いて考えてみてください。
書いてみましたが、楕円の当たり判定の円外のところも計ってしまうからでしょうか?

Re:当たり判定について

Posted: 2010年8月25日(水) 01:20
by softya
もう一度整理してみましょう。

>2)線分交差法が問題があると言われていた理由が理解できましたか?
> ⇒ いいえ ⇒ 2)私の絵で示したつもりですが、「その2」の場合、当たりと判定すべきでしょうか?それとも当たらなかったとみなすべきでしょうか?(もちろん、線分交差法では当たりではありません) ⇒ A,Bの範囲に入っていないので当たり判定とみなしません。

a)それではこの状況はゲームとしては当たっていてほしい状況ですか?
それとも当たらなくても気になりませんか?
b)線分交差法に問題は感じませんか?

>3)めるぽんさんのアルゴリズムは理解されましたか?また、ぬるぽんさんのアルゴリズムに追加質問はないのでしょうか?
> ⇒ float rec = 1 / max_ratio;のところの意味がわかりません。 ⇒ 何のために10分割するか考えてみましたか? 10分割でダメな場合と10分割で無駄な場合ってなんでしょう? ⇒ 10分割は長さを細かく計るためにするに10分割すると思いました。10分割でダメな理由は10分割を細かくしたよりも小さい長さを求められないからだと思います。

c)長さを細かく計ると何が良いのでしょうか?重要なポイントです。私は長さよりも時間と空間の問題だと思うのですが表現が違うだけかも知れませんのでお聞きします。出来るだけ具体例を挙げてください。
d)10分割でダメな理由は10分割を細かくしたよりも小さい長さを求められないからだと思います。
これは何故でしょうか?どういう状態を想定してしていますか?具体的な例を書いてみてください。
e)10分割で無駄な理由の答えがありませんね。考えてみてください。 

>4)実は、楕円と楕円の衝突判定方法にも問題があります。 それは何か理解さていますでしょうか?
⇒ いいえ。 ⇒ 4)に関しては課題としましょう。紙に色々と絵を書いて考えてみてください。⇒ 
書いてみましたが、楕円の当たり判定の円外のところも計ってしまうからでしょうか?

円での当たり判定は理想の当たり判定ですね。楕円は擬似的な当たり判定に過ぎません。
f)これも時間と空間の問題で少なくとも2つ以上の問題があります。思いつく限りの問題を挙げてみてください。

Re:当たり判定について

Posted: 2010年8月25日(水) 14:07
by たろう
返信ありがとうございます。
>a)それではこの状況はゲームとしては当たっていてほしい状況ですか?
それとも当たらなくても気になりませんか?
当たってほしい状況です。
>b)線分交差法に問題は感じませんか?
感じました。AからBのAB、CからDのCDは当たり判定されるけど、ABとCDでは当たり判定されないと言うことですよね。
>c)長さを細かく計ると何が良いのでしょうか?
すみません、わかりません。教えてください
>d)10分割でダメな理由は10分割を細かくしたよりも小さい長さを求められないからだと思います。
これは何故でしょうか?
すみません。感です。わかりません。教えてください。
e)10分割で無駄な理由の答えがありませんね。考えてみてください。 
すみません。検討がつきません。教えてください。
f)これも時間と空間の問題で少なくとも2つ以上の問題があります。思いつく限りの問題を挙げてみてください。
思いつきません。教えてください。

Re:当たり判定について

Posted: 2010年8月25日(水) 15:40
by softya
結局、ぬるぽんさんのアルゴリズムを理解されていないんですね。
これだと堂々巡りなので、ぬるぽんさんのプログラムを解析してみてください。
教えるというか、これ以上は理解してもらうしか無いです。

cについて考えてみましょう。d~fは保留します。
最初のNo:58917 の回答の方にあるプログラムで10分割だけしている方です。
ちなみに距離を10分割しているんじゃなくて時間を10分割していると思ってください。
あちこちにprintf/printfDXを挟んで数値を追うも良し、実際に円をグラフィック化して表示してシミュレーションしてみるも良し、フローチャートなどを書いてみてアルゴリズムを理解するのも良しです。自分で出来るだけの事をやってみてなぜこうなっているのか推論を働かせてみてください。
意味もなく10分割はしていません。2分割だと何が違うんでしょう?プログラムを動かして考えてみてください。

Re:当たり判定について

Posted: 2010年8月25日(水) 21:06
by たろう
返信ありがとうございます。
>最初のNo:58917 の回答の方にあるプログラムで10分割だけしている方です。
>ちなみに距離を10分割しているんじゃなくて時間を10分割していると思ってください。
これは10分割しているのはわかります。
すみません。ただなぜ、float rec = 1 / max_ratio;
と逆数にする必要があるでしょうか?

Re:当たり判定について

Posted: 2010年8月25日(水) 22:11
by softya
うーん。そもそも何故10分割しているか理解されましたか?
そこが理解出来ていないと以下の回答も意味ないんですが。

で質問の
max_ratio自体の意味は、半径に対する速度の割り合いですので逆数にすると言うことは速度に対する半径の割合です。
float rec = 1 / max_ratio;
で求められるのは、速度が大きいほど小さな値で当たり半径が大きいほど大きな値になります。
つまり何をしようとしているかというと、速度が大きくなるほど細かい時間に分割して当たり判定をしようとしています。
当たり判定の円の半径が10で移動速度が10なら、1/10フレームの時間単位で当たり判定をします。
当たり判定の円の半径が10で移動速度が100なら、1/100フレームの時間単位で当たり判定をします。
ただ、めるぽんさも書いている通り
float time = rec / 10;
が適当かは私も疑問ですので調整が必要です。
その調整もアルゴリズムを理解していてこそですので、まず1/10フレームの時間単位でなぜ当たり判定をしているか理解した上って事になります。 画像

Re:当たり判定について

Posted: 2010年8月26日(木) 01:19
by たろう
返信ありがとうございます。
10分割している理由は、当たり判定の円の半径が10以上のとき、フレーム数を移動速度に合わせるためでしょうか。。。
だから、当たり判定の円の半径が10未満のときは、当たり判定されなかったのでしょうか?
すみません。わかりません。。。

Re:当たり判定について

Posted: 2010年8月26日(木) 01:32
by たろう
すみません。
>当たり判定の円の半径が10以上
の10以上ではなく、10単位以上の間違えでした。

Re:当たり判定について

Posted: 2010年8月26日(木) 01:34
by softya
10分割は時間を分割しているのであって、距離や大きさを分割しているのではありません。時間が関係してくるのは速度だけです。速度は時間あたりの移動距離ですからね。
10分割は1秒間の描画フレーム数と別に当たり判定専用のフレーム数を増やす為です。
10分割するということは、毎秒60回の描画数だとすると当たり判定は毎秒600回になります。
これは何のためでしょうか?毎秒60回を10倍にして毎秒600回だと何がめるぽんの処理で変わるのかよーく考えてみてください。ヒントは今までの私やめるぽんさんや組木紙織さんなどの回答に散りばめられていますよ。

ヒントになる絵も添えておきます。
1、2、3、4、5は時間だと思ってください。仮にmsでも良いです。
赤い丸は移動する当たり範囲。青い丸は停止している当たり範囲です。 画像

Re:当たり判定について

Posted: 2010年8月26日(木) 01:37
by たろう
>当たり判定の円の半径が10未満ではなく
10単位未満でした。
何度もすみません。

Re:当たり判定について

Posted: 2010年8月26日(木) 02:11
by たろう
>10分割するということは、毎秒60回の描画数だとすると当たり判定は毎秒600回になります。
これは何のためでしょうか?
より細かい当たり判定ができると思います。
なぜ10分割かは、FPSが60なので、その10倍だと都合がいいからでしょうか?

Re:当たり判定について

Posted: 2010年8月26日(木) 10:32
by softya
>より細かい当たり判定ができると思います。
より細かいって言うのが分かってもらえたのか微妙ですね。
念のために具体例を書いてもらえますか?

>なぜ10分割かは、FPSが60なので、その10倍だと都合がいいからでしょうか?
うーん。めるぽんさんが10分割したのは特に理由はないと思います。
ちゃんと当たり判定できるなら、別に4分割でも8分割でも構わないんですよ。
めるぽんさんが機能追加したNo:59296 のmax_ratioの計算は、それを補正するために計算しているわけですしね。

【追記】
念のために追記しておきます。
分割自体は当たり判定としてすごく意味がありますよ。
でも回数自体は10回は最適解じゃないです。
ベストでもベターでも無く、このぐらいやっておけば大丈夫じゃね?ぐらいの意味しかないです。 画像

Re:当たり判定について

Posted: 2010年8月26日(木) 17:54
by たろう
返信ありがとうございます。
>念のために具体例を書いてもらえますか?
1から5までの円が並んであるとして、1なら1の円の直径を10分割を求めるということでしょうか?
これを100分割した場合はより細かく求めるということでしょうか?
例が下手ですみません。。。

Re:当たり判定について

Posted: 2010年8月26日(木) 18:05
by softya
>1から5までの円が並んであるとして、1なら1の円の直径を10分割を求めるということでしょうか?
>これを100分割した場合はより細かく求めるということでしょうか?
>例が下手ですみません。。。

めるぽんさんの回答No:58917 のプログラムは本当にそんなプログラムですか?
No:58917のプログラムのたろうさんなりのアルゴリズムの解説を書いてみてください。

Re:当たり判定について

Posted: 2010年8月26日(木) 20:27
by たろう
1から5と言うのは、 1につき1 / max_ratioのことです。
それを10分割するということは、より細かくすることにより、移動速度をより細かく処理をするためにと言うことでしょうか?
すませんわかりません。教えてください。。。

Re:当たり判定について

Posted: 2010年8月26日(木) 20:43
by softya
>1から5と言うのは、 1につき1 / max_ratioのことです。
>それを10分割するということは、より細かくすることにより、移動速度をより細かく処理をするためにと言うことでしょうか?
>すませんわかりません。教えてください。。。

それはめるぽんさんの回答No:59296ですよね。
そっちじゃなくて、No:58917の方です。検索してみてくださいね。
今回は、1から5も忘れてもらって良いですか。

Re:当たり判定について

Posted: 2010年8月26日(木) 21:20
by たろう
if (test_circle_circle(
x1 + cos(a1) * v1 * t, y1 + sin(a1) * v1 * t, r1,
x2 + cos(a2) * v2 * t, y2 + sin(a2) * v1 * t, r2))
{
は、V1が50でV2が50のとき、tは1 / max_ratioを10分割したやつをかけてそうすると、
例えば、r1が10でr2が5のとき5/50を10分割して、移動速度をより細かくしていき、
それをtに加算していく。

x1 + cos(a1) * v1 * tは位置に移動速度のV1の距離にtをかけて(0.1なら10分の1それを10回繰り返される)
while(t<1.0f)になるまで繰り返す。

です。

Re:当たり判定について

Posted: 2010年8月26日(木) 21:43
by softya
回答No:59296のmax_ratio件は、今は忘れてください。
今回解説してもらいたいのは、回答No:58917だけの話です。
それと書かれているのはプログラムの内容そのもので、アルゴリズムと言うか仕様の説明になっていません。
tは何を表す変数でしょうか?日本語で書くとしたら?
v1,v2,r1,r2は分かりますよね。書いてもらえますか。

x1 + cos(a1) * v1 * t
の式は、何を求めるための式でしょうか?
解説してもらえますか。

これらも含めて全体の内容が解説出来て始めてプログラムを理解したことになります。

Re:当たり判定について

Posted: 2010年8月26日(木) 21:59
by たろう
>tは何を表す変数でしょうか?日本語で書くとしたら?
tは、任意の数を分割した数を表す変数。
>v1,v2,r1,r2は分かりますよね。書いてもらえますか。
V1,v2は移動速度。r1,r2は当たり判定の範囲です。
x1 + cos(a1) * v1 * t
の式は、何を求めるための式でしょうか?
は移動位置の分割した数を求める式です。
これでいいでしょうか?

Re:当たり判定について

Posted: 2010年8月26日(木) 22:20
by softya
めるぽんさんの代わりに解説しているので、勘違いもあるかも知れませんが。
tは時間経過を表す変数で1フレーム内の時間の経過を表します。たぶんtimeの略だと思われます。
t=0が始まりで、t=1で1フレーム分の時間が経過したことになります。
なので、t=0.5なら0.5フレームの時間が経過したことになる訳です。

>V1,v2は移動速度。r1,r2は当たり判定の範囲です。
正確に言うとV1,v2は1フレーム当たりの移動距離で速度としての単位はピクセル/フレームです。
r1,r2は当たり判定の範囲ですが半径ですね。

じゃあ、
x1 + cos(a1) * v1 * t
は何を表す式になるでしょうか?
x1とa1も合わせて解説してください。

>は移動位置の分割した数を求める式です。
これって意味分かってます?
5回とか回数が出る式には見えませんが。

Re:当たり判定について

Posted: 2010年8月26日(木) 22:27
by palladium
>すみません勉強不足で。 すみませんが説明よろしくおねがいします

ご自分の勉強不足はご自分で補うべきです。

Re:当たり判定について

Posted: 2010年8月26日(木) 22:30
by たろう
返信あありがとうございます。
>x1 + cos(a1) * v1 * t
>は何を表す式になるでしょうか?
フレームの時間経過分の位置を表しています。

>は移動位置の分割した数を求める式です。
>これって意味分かってます?
意味はわかるのですが、なんて説明していいのかわかりません。

Re:当たり判定について

Posted: 2010年8月26日(木) 22:53
by softya
>フレームの時間経過分の位置を表しています。
???
tは1以上になりませんよ。tの値は0~1の範囲です。
言葉の間違いかも知れませんが。

じゃあ、回答No:58917を使ってWinMainだけを付け加えてt=0.7の時に衝突するプログラムを作ってみてください。
計算の意味がが分かっているならx1,v1,r1などの値も決められるはずです。
画像表示が大変だったら、printfDXだけでも構いません。tの変化と衝突の有無、2つの物体の位置も表示してください。

Re:当たり判定について

Posted: 2010年8月26日(木) 23:29
by ookami
なんだか横やりを入れるのがためらわれますが、

たろうさん、「どんな当たり判定を実装したいのか」、すいませんが、もう一度詳しく説明してもらえませんか?

なるべく、誰もが同じように解釈できる表現で、お願いします。

Re:当たり判定について

Posted: 2010年8月27日(金) 00:18
by たろう
返信ありがとうございます。
できたのでソース載せます。
#define GLOBAL_INSTANCE 
#include "include/DxLib.h"
#include"GV.h"
// 動いてない円同士の当たり判定
int test_circle_circle(float x1, float y1, float r1, float x2, float y2, float r2)
{
    float x = x1 - x2;
    float y = y1 - y2;
    float r = r1 + r2;
    return x * x + y * y <= r * r;
}

// 動いている円同士の当たり判定
int atarihantei(
    // X座標, Y座標, 半径, 角度, 速度
    float x1, float y1, float r1, float a1, float v1,
    float x2, float y2, float r2, float a2, float v2)
{
    // 経過時間
    // 円がそれぞれ a1, a2 の方向に v1, v2 だけ進んだ時間を 1.0 とする
    float t = 0.0f;

    while (t < 1.0f)
    {
        // 初期位置から t だけ進んだ円同士の当たり判定を行う
        if (test_circle_circle(
            x1 + cos(a1) * v1 * t, y1 + sin(a1) * v1 * t, r1,
            x2 + cos(a2) * v2 * t, y2 + sin(a2) * v2 * t, r2))
        {
            return 1;
        }

        // 適当に時間を進ませる
        // ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
        t += 0.7f;
    }
    // 初期位置から 1.0 だけ進んだ円同士の当たり判定を行う
    return test_circle_circle(
        x1 + cos(a1) * v1, y1 + sin(a1) * v1, r1,
        x2 + cos(a2) * v2, y2 + sin(a2) * v1, r2);
}


int Prossessloop()
{
    if(ProcessMessage()!=0)
        return -1;
    if(ClearDrawScreen()!=0)
        return -1;
    GetHitKeyStateAll_2();
    GetHitPadStateAll();
    return 0; 

}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

    while(Prossessloop()!=-1){


//当たり判定

    printfDx("%d",atarihantei(7.0f,0.0f,7.0f,0.0f,10.0f,0.0f,0.0f,0.0f,0.0f,0.0f));
//x1を1上げると当たらない、rを下げると当たらない



        if(CheckStateKey(KEY_INPUT_ESCAPE)==1)
            break;

        ScreenFlip();
    }

    DxLib_End();
    return 0;
}
です。

Re:当たり判定について

Posted: 2010年8月27日(金) 00:30
by ookami
softyaさんは

> t=0.7の時に衝突するプログラムを作ってみてください

との事でしたが、たろうさんのプログラムでは t=0.0の時に衝突するような...

あと、

> tの変化と衝突の有無、2つの物体の位置も表示してください。

は、どこに反映されていますか?

と、あと、私の上の質問も、回答おまちしてます。

Re:当たり判定について

Posted: 2010年8月27日(金) 00:54
by たろう
返信ありがとうございます。
> t=0.7の時に衝突するプログラムを作ってみてください

>との事でしたが、たろうさんのプログラムでは t=0.0の時に衝突するような...

0.7にするの忘れてました。

>衝突の有無。
atarihantei()で判断していると思うのですが
//x1を1上げると当たらない、rを下げると当たらないと書いているのですが、
何か勘違いしていたらすみません。
>2つの物体の位置も表示してください。
これは、 printfDx("%d",atarihantei(7.0f,0.0f,7.0f,0.0f,10.0f,0.0f,0.0f,0.0f,0.0f,0.0f));

のx1とX2、Y1、Y2の所だと思ったのですが・・・
>たろうさん、「どんな当たり判定を実装したいのか」、すいませんが、もう一度詳しく説明してもらえませんか?
>なるべく、誰もが同じように解釈できる表現で、お願いします。
とりあえず、めるぽんさんのような、フレーム数で、当たり判定ができるように実装したいです。
説明が下手でごめんなさい。

Re:当たり判定について

Posted: 2010年8月27日(金) 01:18
by softya
atarihanteiの関数内のアルゴリズムは変えないでください。0.1刻みで0から1.0までです。
0.0から0.6と0.8から0.9は当たらずに0.7だけに当たるようにしてくださいね。

Re:当たり判定について

Posted: 2010年8月27日(金) 01:25
by softya
あとGv.hとか使っているもの一式は何処で手に入れたやつでしょうか?
環境を合わせるのが大変なので、入手元を教えてください。

Re:当たり判定について

Posted: 2010年8月27日(金) 01:41
by たろう
返信ありががとうございます。
ソース変えました。
#define GLOBAL_INSTANCE 
#include "include/DxLib.h"
#include"GV.h"
// 動いてない円同士の当たり判定
int test_circle_circle(float x1, float y1, float r1, float x2, float y2, float r2)
{
    float x = x1 - x2;
    float y = y1 - y2;
    float r = r1 + r2;
    return x * x + y * y <= r * r;
}

// 動いている円同士の当たり判定
int atarihantei(
    // X座標, Y座標, 半径, 角度, 速度
    float x1, float y1, float r1, float a1, float v1,
    float x2, float y2, float r2, float a2, float v2)
{
    // 経過時間
    // 円がそれぞれ a1, a2 の方向に v1, v2 だけ進んだ時間を 1.0 とする
    float t = 0.0f;

    while (t < 1.0f)
    {
        // 初期位置から t だけ進んだ円同士の当たり判定を行う
        if (test_circle_circle(
            x1 + cos(a1) * v1 * t, y1 + sin(a1) * v1 * t, r1,
            x2 + cos(a2) * v2 * t, y2 + sin(a2) * v2 * t, r2))
        {
            return 1;
        }

        // 適当に時間を進ませる
        // ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
        t += 0.1f;
    }
    // 初期位置から 1.0 だけ進んだ円同士の当たり判定を行う
    return test_circle_circle(
        x1 + cos(a1) * v1, y1 + sin(a1) * v1, r1,
        x2 + cos(a2) * v2, y2 + sin(a2) * v1, r2);
}


int Prossessloop()
{
    if(ProcessMessage()!=0)
        return -1;
    if(ClearDrawScreen()!=0)
        return -1;
    GetHitKeyStateAll_2();
    GetHitPadStateAll();
    return 0; 

}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

    while(Prossessloop()!=-1){


//当たり判定

    printfDx("%d",atarihantei(7.0f,0.0f,7.0f,0.0f,10.0f,21.0f,0.0f,0.0f,0.0f,0.0f));
//x1を1上げると当たらない、rを下げると当たらない



        if(CheckStateKey(KEY_INPUT_ESCAPE)==1)
            break;

        ScreenFlip();
    }

    DxLib_End();
    return 0;
}
です。よろしくお願いします。

Re:当たり判定について

Posted: 2010年8月27日(金) 07:39
by ookami
> とりあえず、めるぽんさんのような、フレーム数で、当たり判定ができるように実装したいです。

もうちょっと詳しく書いてもらってもいいですか?

「フレーム数」を具体的にはどうするのでしょう。

「めるぽんさんのような」ではなく、たろうさんの言葉でお聞きしたい。

Re:当たり判定について

Posted: 2010年8月27日(金) 13:52
by たろう
例えば、フレーム数を1フレームにつき移動経過時間を計ってそれを調べていくような当たり判定がしたいです。

Re:当たり判定について

Posted: 2010年8月27日(金) 14:23
by softya
>例えば、フレーム数を1フレームにつき移動経過時間を計ってそれを調べていくような当たり判定がしたいです。
それは私の例えですね。
ookamiさんの求めているのは、もっと具体的な話だと思いますよ。

ところで私のリクエストは、どうなってます?

Re:当たり判定について

Posted: 2010年8月27日(金) 14:28
by がくせい
もう悪あがきはおよしなさい
堂々巡りです

Re:当たり判定について

Posted: 2010年8月27日(金) 17:18
by あろう
返信ありがとうございます。

>0.0から0.6と0.8から0.9は当たらずに0.7だけに当たるようにしてくださいね。
0.0から0.6までは当たらなくすることは出来るのですが、0.8と0.9は当たらずにすることはできません。
というかできないと思います。
0.8から0.9は範囲内にどうしても入ってしまうからです。

Re:当たり判定について

Posted: 2010年8月27日(金) 17:20
by たろう
すみません。名前間違えてしまいました。
返信ありがとうございます。

>0.0から0.6と0.8から0.9は当たらずに0.7だけに当たるようにしてくださいね。
0.0から0.6までは当たらなくすることは出来るのですが、0.8と0.9は当たらずにすることはできません。
というかできないと思います。
0.8から0.9は範囲内にどうしても入ってしまうからです。

Re:当たり判定について

Posted: 2010年8月27日(金) 17:39
by softya
>0.0から0.6までは当たらなくすることは出来るのですが、0.8と0.9は当たらずにすることはできません。
というかできないと思います。
>0.8から0.9は範囲内にどうしても入ってしまうからです。

角度も半径も移動速度も自在に調整できるのになぜ出来ないんでしょうか?
理由を教えてください。

ちなみに私は実行できていないのでプログラムを検証していません。
理由は既に書いてあります。

Re:当たり判定について

Posted: 2010年8月27日(金) 18:23
by たろう
すみません。気づきませんでした。
>角度も半径も移動速度も自在に調整できるのになぜ出来ないんでしょうか?
>理由を教えてください。
V1の移動速度が10でa1の角度0、r1の半径1.2、V2が8,a2が0,r2が0.0にした場合、
tが0.1の時
return x * x + y * y <= r * r;
のxが0.2、yが0で、rが1.2で当たらなくて、
それをtが0.6まで進めて、tが0.7のときxが1.2でyが0で当たってtが0.8のときが1.4になり当たりになり0.9で1.6になり当たりになるからです。

ソース変えました。
#define GLOBAL_INSTANCE 
#include "include/DxLib.h"
#include<math.h>
//#include"GV.h"
// 動いてない円同士の当たり判定
int test_circle_circle(float x1, float y1, float r1, float x2, float y2, float r2)
{
    float x = x1 - x2;
    float y = y1 - y2;
    float r = r1 + r2;
    return x * x + y * y <= r * r;
}

// 動いている円同士の当たり判定
int atarihantei(
    // X座標, Y座標, 半径, 角度, 速度
    float x1, float y1, float r1, float a1, float v1,
    float x2, float y2, float r2, float a2, float v2)
{
    // 経過時間
    // 円がそれぞれ a1, a2 の方向に v1, v2 だけ進んだ時間を 1.0 とする
    float t = 0.0f;

    while (t < 1.0f)
    {
        // 初期位置から t だけ進んだ円同士の当たり判定を行う
        if (test_circle_circle(
            x1 + cos(a1) * v1 * t, y1 + sin(a1) * v1 * t, r1,
            x2 + cos(a2) * v2 * t, y2 + sin(a2) * v2 * t, r2))
        {
            return 1;
        }

        // 適当に時間を進ませる
        // ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
        t += 0.1f;
    }
    // 初期位置から 1.0 だけ進んだ円同士の当たり判定を行う
    return test_circle_circle(
        x1 + cos(a1) * v1, y1 + sin(a1) * v1, r1,
        x2 + cos(a2) * v2, y2 + sin(a2) * v1, r2);
}


int Prossessloop()
{
    if(ProcessMessage()!=0)
        return -1;
    if(ClearDrawScreen()!=0)
        return -1;
    return 0; 

}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

    while(Prossessloop()!=-1){


//当たり判定

    printfDx("%d",atarihantei(7.0f,0.0f,7.0f,0.0f,10.0f,21.0f,0.0f,0.0f,0.0f,0.0f));
//x1を1上げると当たらない、rを下げると当たらない
        ScreenFlip();
    }

    DxLib_End();
    return 0;
}

Re:当たり判定について

Posted: 2010年8月27日(金) 18:48
by ookami
softyaさんは、
「なぜ当たってしまうか」ではなく
「なぜ当たらないようにできないのか」を聞いているように思います。

atarihanteiに渡すパラメータ次第で、
0.7で当たり、0.8,0.9では当たらないように
できると思います。

> 例えば、フレーム数を1フレームにつき移動経過時間を計ってそれを調べていくような当たり判定がしたいです。

「それ」を具体的に書いてみて下さい。
あと、「ような」ということは、
たろうさんの中でも、
はっきりしていないんでしょうか?

Re:当たり判定について

Posted: 2010年8月27日(金) 18:48
by softya
少々処理を変えました。これを使ってください。
それと、半径、角度、速度をうまく調整すればt=0.7の近辺だけ当たる様に必ず出来ます。
【追記】
もし出来ないなら図形のイメージ、動きのイメージ、アルゴリズムのイメージがちゃんと出来ていない事になります。


#define GLOBAL_INSTANCE
#include "include/DxLib.h"
#include<math.h>
//#include"GV.h"
// 動いてない円同士の当たり判定
int test_circle_circle(float x1, float y1, float r1, float x2, float y2, float r2)
{
float x = x1 - x2;
float y = y1 - y2;
float r = r1 + r2;
return x * x + y * y <= r * r;
}

// 動いている円同士の当たり判定
int atarihantei(
// X座標, Y座標, 半径, 角度, 速度
float x1, float y1, float r1, float a1, float v1,
float x2, float y2, float r2, float a2, float v2,
float count
)
{
// 経過時間
// 円がそれぞれ a1, a2 の方向に v1, v2 だけ進んだ時間を 1.0 とする
float t = 0.0f;

while (t < 1.0f)
{
// 初期位置から t だけ進んだ円同士の当たり判定を行う
if (test_circle_circle(
x1 + cos(a1) * v1 * t, y1 + sin(a1) * v1 * t, r1,
x2 + cos(a2) * v2 * t, y2 + sin(a2) * v2 * t, r2))
{
printfDx("t=%f count=%2.f hit=1\n",t,count);
return 1;
}

// 適当に時間を進ませる
// ここの値は r1, r2, v1, v2 から適切に求めるべきだけど、ここでは面倒なのでやらない
t += (1/count);
}
// 初期位置から 1.0 だけ進んだ円同士の当たり判定を行う
int hit =test_circle_circle(
x1 + cos(a1) * v1, y1 + sin(a1) * v1, r1,
x2 + cos(a2) * v2, y2 + sin(a2) * v1, r2);

printfDx("t=1 count=%2.f hit=%d\n",count,hit);
return hit;
}


int Prossessloop()
{
if(ProcessMessage()!=0)
return -1;
if(ClearDrawScreen()!=0)
return -1;
return 0;

}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode(TRUE);//ウィンドウモード

if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

while(Prossessloop()!=-1){


//当たり判定

// X座標, Y座標, 半径, 角度, 速度
for( int icount=1 ; icount<=10 ; icount++ ) {
atarihantei(7.0f, 0.0f, 7.0f, 0.0f, 10.0f,
21.0f,0.0f, 0.0f, 0.0f, 0.0f,
(float)icount);
}
//x1を1上げると当たらない、rを下げると当たらない
ScreenFlip();
}

DxLib_End();
return 0;
} 画像

Re:当たり判定について

Posted: 2010年8月27日(金) 19:42
by たろう
>もし出来ないなら図形のイメージ、動きのイメージ、アルゴリズムのイメージがちゃんと出来ていない事になります。
出来ていないみたいです。
すみません。
一つ聞いてもよろしいでしょうか?
角度は0のままでも出来るのでしょうか?

Re:当たり判定について

Posted: 2010年8月27日(金) 21:43
by ookami
確認なんですが、たろうさんがやりたい当たり判定では、
図のような場合は、当たりとみなしますか?
赤・青、それぞれ、矢印の尾が移動前、先が移動後です。

Re:当たり判定について

Posted: 2010年8月27日(金) 21:46
by たろう
返信ありがとうございます。いいえ、当たりとみなしません。