2つの線の交点を見つける方法


7

キャラクターにバウンディングボックスがあり、前のフレームでの位置と現在のフレームです。境界ボックスは軸に揃えられています。

私のキャラクターは洞窟の中を走り回っています。洞窟の壁を表す点(線)のリストがあります(軸が揃っていません)。

私のキャラクターの一部が洞窟の壁の一部と衝突した可能性が高いときに通知する粗いアルゴリズムを持っています。

壁のどのラインがどの時点で衝突したかを明確に示す細かいアルゴリズムはありません。

私の現在の考えは、前のフレームの位置から現在のフレームの位置までの境界ボックスの各コーナーに線を作成し、これらの各線を洞窟内の線との交差についてテストすることでした。壁。

しかし、私のグーグルフーフは交差を計算するための簡単な公式を私に見せてくれませんでした。これを行うには悪い方法を選びましたか、それとも検索が苦手ですか?

私のゲームはscalaで書かれていますが、どのようなcスタイル言語や多くのスクリプト言語でも、あなたが答えたいと思うものは何でも読んだり翻訳したりできます。

回答:


-3

「交差テストラインセグメントラインセグメント」をグーグルで作成すると、次のようになります。

http://paulbourke.net/geometry/lineline2d/


2
解は、2つの線の交点だけよりも大きくなります。Travには地形を表す多数の線があり、キャラクターの任意の部分が任意の地形線の任意の部分と交差している可能性があります。
doppelgreener

ただし、これはアルゴリズムの繰り返しです。交差点の存在をテストし、それが私が見ているセグメント内にあるかどうかをテストし、特定の場所を取得する式は、まさに私が求めているものです
Trav

1
私が答えに答えた理由は、はい、それはアルゴリズムの繰り返しであり、あなたそれ総当たりにすることができるからです。最近はまだまだあると思います。線の交点の数式を指摘するだけでは問題は正解しないと思います。レベルがかなり大きくなり、まったく関係のない壁との交差をチェックするサイクルを無駄にしているときはどうですか?
doppelgreener

ジョナサン:さて、質問から:「私のキャラクターの一部が洞窟の壁の一部と衝突した可能性が高いときに通知する粗いアルゴリズムを持っています。」その粗い詳細アルゴリズムが良いかどうかはわかりませんが...
Olhovsky

7

さまざまなアプローチでそれを行うことができます。

  • パラメトリックラインといくつかの検証を使用したセグメントvsセグメント(ラインはセグメントではないため)。

  • セグメントとボックス

  • セグメントvsサークル(これが私のお気に入りです)

。しかし、セグメントとセグメントの交差テストを要求すると、非常に興味深い本「リアルタイム衝突検出」から抽出された疑似C ++の例がここにあります。

float Signed2DTriArea(Point a, Point b, Point c)
{
    return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
}

int Test2DSegmentSegment(Point a, Point b, Point c, Point d, float &t, Point &p)
{
    // signs of areas correspond to which side of ab points c and d are
    float a1 = Signed2DTriArea(a,b,d); // Compute winding of abd (+ or -)
    float a2 = Signed2DTriArea(a,b,c); // To intersect, must have sign opposite of a1

    // If c and d are on different sides of ab, areas have different signs
    if( a1 * a2 < 0.0f ) // require unsigned x & y values.
    {
        float a3 = Signed2DTriArea(c,d,a); // Compute winding of cda (+ or -)
        float a4 = a3 + a2 - a1; // Since area is constant a1 - a2 = a3 - a4, or a4 = a3 + a2 - a1

        // Points a and b on different sides of cd if areas have different signs
        if( a3 * a4 < 0.0f )
        {
            // Segments intersect. Find intersection point along L(t) = a + t * (b - a).
            t = a3 / (a3 - a4);
            p = a + t * (b - a); // the point of intersection
            return 1;
        }
    }

    // Segments not intersecting or collinear
    return 0;
}

本のソフトウェア使用許諾契約は、コード例を使用するために以下のクレジットを含めることを求めています:

コード例「モーガンカウフマーンパブリッシャーズ発行のChrister EricsonによるReal-Time Collision Detectionから©2005 Elvesier Inc」


4

誰かがすでに満足のいく答えを提供してくれましたが、あなたが説明した方法が正確なインパクトタイム(TOI)をもたらすかどうかはわかりません。私の最初の傾向は、「衝突が発生した場合、プレーヤーが洞窟の一部と衝突する前にどれだけ遠くまで移動できるか」という質問に対する正確な答えを見つけることです。連続衝突検出技術(CCD)を使用する必要があります。

具体的には、AABBを1つのポイントに効果的に「縮小」し、同時にミンコウスキー加算を使用して、同じ量だけ洞窟の線分を「成長」させる手法があります。次に、問題は、凸状のオブジェクトまたは凸状のオブジェクトのセットに対してレイを投影することと見なすことができます(等速で時間を移動する点がレイになるため)。「膨らんだ」洞窟と交差する光線に沿った最も早い距離は、衝撃の最も早い時間(TOI)を表します。

これを達成する方法に関する最も一般的な文献は3次元を扱いますが、2次元にも適用され、簡単に転送する必要があります。現時点では、すべての詳細を詳しく説明したり、疑似コードを提供したりする時間はありませんが、誰かが私が言及していることを確認して拡張できるかもしれません。とりあえず、ここではプロセスを説明する2、3のペーパーと、グーグルに興味のあるいくつかの用語を紹介します。


0

旅行でこれを見つけた人を助けるために、https://stackoverflow.com/a/1968345/431528にあるメソッドを使用した2Dライン交差テストを次に示します

inline bool lines_intersect_2d(Vector2 const& p0, Vector2 const& p1, Vector2 const& p2, Vector2 const& p3, Vector2* i const = 0) {
    Vector2 const s1 = p1 - p0;
    Vector2 const s2 = p3 - p2;

    Vector2 const u = p0 - p2;

    float const ip = 1.f / (-s2.x * s1.y + s1.x * s2.y);

    float const s = (-s1.y * u.x + s1.x * u.y) * ip;
    float const t = ( s2.x * u.y - s2.y * u.x) * ip;

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
        if (i) *i = p0 + (s1 * t);
        return true;
    }

    return false;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.