直線と円の当たり判定はこれで大丈夫ですか?

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

直線と円の当たり判定はこれで大丈夫ですか?

#1

投稿記事 by Ultimate » 14年前

当たり判定をまとめているヘッダファイルの中に、線分と円の当たり判定を作りたいため、それに利用する直線と円の当たり判定を作成しています。

#include<math.h>

//直線と円の当たり判定
int LineHitCircle(double x1,double y1,double x2,double y2,double p,double q,int r){
int lflag;
if(x1 != x2){
double a = y2-y1;
double b = x1-x2;
double c = x2*y1-x1*y2;
double d = (fabs(a*p+b*q+c)/(sqrt(a*a+b*b)));
if(r<=d)lflag=1;
else lflag=0;
}
if(x1 == x2){
if(r <= (x1+r))lflag=1;
else lflag = 0;
}
return lflag;
}


これには以下の公式を利用しました。
http://www004.upp.so-net.ne.jp/s_honma/ ... stance.htm
http://www.cfv21.com/math/strlineq.htm

これでうまく判定できるでしょうか? 画像

Poco

Re:直線と円の当たり判定はこれで大丈夫ですか?

#2

投稿記事 by Poco » 14年前

正しいかどうかは、実際にパラメータを入れてみて検査してみないと、なんとも言えませんが、
↓の処理は要らなくないですか?

> if(x1 == x2){
> if(r <= (x1+r))lflag=1;
> else lflag = 0;
> }

Ultimate

Re:直線と円の当たり判定はこれで大丈夫ですか?

#3

投稿記事 by Ultimate » 14年前

http://www004.upp.so-net.ne.jp/s_honma/ ... stance.htm

見てみたらbが0でも成立するようでした。

その部分は消しておきます。

softya

Re:直線と円の当たり判定はこれで大丈夫ですか?

#4

投稿記事 by softya » 14年前

当たり判定をテストするmain部分のプログラムを添えていただけますか?

Ultimate

Re:直線と円の当たり判定はこれで大丈夫ですか?

#5

投稿記事 by Ultimate » 14年前

まだこの関数は使っていません。(今後弾幕にレーザー攻撃をする敵を作りたいのでそこで使おうかと思っています。)

LineHitCircle(double x1,double y1,double x2,double y2,double p,double q,int r);



x1 は直線の1点のX座標
x2 は直線の1点のY座標
y1 は直線の上のとは別の1点のX座標
y2 は直線の上のとは別の1点のY座標
p  は円の中心のX座標
q  は円の中心のY座標
r は円の半径

で、円が直線にぶつかっていれば1,ぶつかっていなければ0を返す

というようにしようと思っています。

qwea

Re:直線と円の当たり判定はこれで大丈夫ですか?

#6

投稿記事 by qwea » 14年前

>今後弾幕にレーザー攻撃をする敵を作りたい

とありますが、今の場合だと直線なので
レーザーの長さに関係なく判定されてしまいますが、大丈夫でしょうか?

フィールドの端から端までのレーザーならよいのですが、
もしレーザーに長さがあるようならば、
線分と円の当たり判定の方が良いような気がします。

また、上のコードは確認していません。
(自分では理解できませんでしたorz)

Ultimate

Re:直線と円の当たり判定はこれで大丈夫ですか?

#7

投稿記事 by Ultimate » 14年前

>(自分では理解できませんでしたorz)
僕も上で貼ったURLで初めて勉強して、それを利用してなんとかできた状態です。
中学2年でベクトルを習ってないので、理解は結構大変です。。。

>線分と円の当たり判定の方が良いような気がします。
そうですね。
今まさに線分と円の当たり判定を考えてる途中です。
その関数内でこれを使います。


線分と円の当たり判定では、
線分の範囲内で且つこの関数で1が返ってくればあたっているという風にする予定です。
ただ、線分の範囲内の判定が難しいです。

方法、もしくはヒントでもいただけたら嬉しいです。

qwea

Re:直線と円の当たり判定はこれで大丈夫ですか?

#8

投稿記事 by qwea » 14年前

>今まさに線分と円の当たり判定を考えてる途中です

自分もSTGを作っていますが、
自分の場合は外積の値をレーザーの長さで割って、
直線との距離を出しています。

線分の判定は、
もし直線との距離が範囲内ならば、
レーザーの2つの方向から円の位置との内積をとり、
線分の内側に存在しているかで判定しています。

以下、実際に使っているソースコードです。
もっと良い方法があるかもしれないですが;

float obj1_x_ = _obj1->GetX() - _obj2->GetX();
float obj1_y_ = _obj1->GetY() - _obj2->GetY();
float obj2_x_ = _obj2->GetToX() - _obj2->GetX();
float obj2_y_ = _obj2->GetToY() - _obj2->GetY();
// 外積をとる
float dot_ = obj1_x_ * obj2_y_ - obj1_y_ * obj2_x_;
// 上下関係無し
if(dot_ <= 0.f)
    dot_ = -dot_;
// 直線との距離
dot_ /= _obj2->GetLength();
// 直線との距離が(円の大きさ+レーザーの太さ)以下ならば
if(dot_ <= _obj1->GetRange() + _obj2->GetBold())
{
    // 内積をとり、線分の内側にあるか判定
    if(obj1_x_ * obj2_x_ + obj1_y_ * obj2_y_ > 0.f)
    {
        // もう一方からも内積をとる
        obj1_x_ = _obj1->GetX() - _obj2->GetToX();
        obj1_y_ = _obj1->GetY() - _obj2->GetToY();
        obj2_x_ = _obj2->GetX() - _obj2->GetToX();
        obj2_y_ = _obj2->GetY() - _obj2->GetToY();
        if(obj1_x_ * obj2_x_ + obj1_y_ * obj2_y_ > 0.f)
        {
            // 当たっている
            return true;
        }
    }
}
// 当たっていない
return false;
_obj1 が円で、
_obj2 がレーザーです。
GetToX, GetToY はレーザーの先端の座標、
GetX, GetY はレーザーの始点の座標です。


>中学2年でベクトルを習ってないので、理解は結構大変です。。。

確かに、外積・内積が分からないと少し理解が難しいかもしれません;
自分ではこの方法しか思い浮かびませんでした orz

Poco

Re:直線と円の当たり判定はこれで大丈夫ですか?

#9

投稿記事 by Poco » 14年前

円の中心Pから直線に対して垂線を引いたときに、直線と交わる点Hの座標を求めて、
その点Hが直線を形作っていた2点の間にあれば、その線分と円は交わっていることになります。

#もちろん、線分PHの長さが円の半径rより小さいことが前提条件です。
#これは、点と直線の距離の公式で出せます。

めるぽん

Re:直線と円の当たり判定はこれで大丈夫ですか?

#10

投稿記事 by めるぽん » 14年前

>円が直線にぶつかっていれば1,ぶつかっていなければ0を返す
のであれば
if(d<=r)lflag=1;
        else lflag=0;
ではないでしょうか(d と r が逆)。

線分と円の当たり判定は、直線との当たり判定をしなくても、線分と点の距離を求めた上で半径との大きさを比較すればいけます。
// (ax,ay)-(bx,by) の線分と (cx,cy) との距離の平方を返す
double SqDistPointSegment(double ax, double ay, double bx, double by, double cx, double cy)
{
    double abx = bx - ax;
    double aby = by - ay;
    double acx = cx - ax;
    double acy = cy - ay;

    // 点(acx,acy) を線分 (0,0)-(abx,aby) を通る直線上へ射影する(内積を求める)
    double e = abx * acx + aby * acy;
    // 線分の外側だった場合は、(ax,ay)-(cx,cy) 間の距離を求めるか、(bx,by)-(cx,cy) 間の距離を求める
    if (e <= 0.0f)
    {
        return acx * acx + acy * acy;
    }
    double f = abx * abx + aby * aby;
    if (e >= f)
    {
        double bcx = cx - bx;
        double bcy = cy - by;
        return bcx * bcx + bcy * bcy;
    }
    // 線分の内側にある場合、(ax,ay)-(cx,cy) 間の距離と (bx,by)-(cx,cy) 間の距離(つまり f)と、
    // e から求めることができる
    return acx * acx + acy * acy - e * e / f;
}

int SegmentHitCircle(double x1, double y1, double x2, double y2, double p, double q, int r)
{
    double sd = SqDistPointSegment(x1, y1, x2, y2, p, q);
    // 線分と点の距離(の平方)が半径(の平方)より小さければ当たっている
    return sd < r * r;
}

Ultimate

Re:直線と円の当たり判定はこれで大丈夫ですか?

#11

投稿記事 by Ultimate » 14年前

ありがとうございました。

難しいけれどがんばってみます!!!

閉鎖

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