Wie finde ich den Schnittpunkt zweier Linien?

7

Ich habe einen Begrenzungsrahmen für meinen Charakter, dessen Position im vorherigen Frame und im aktuellen Frame. Der Begrenzungsrahmen ist achsenausgerichtet.

Mein Charakter läuft in einer Höhle herum, ich habe eine Liste von Punkten (Linien), die die Wand der Höhle darstellen (nicht achsenausgerichtet)

Ich habe einen grobkörnigen Algorithmus, der mir sagt, wann ein Teil meines Charakters wahrscheinlich mit einem Teil der Höhlenwand kollidiert ist.

Ich habe keinen feinkörnigen Algorithmus, der mir genau sagt, mit welcher Linie der Wand an welchem ​​Punkt kollidiert wurde.

Mein aktueller Gedanke war, dass ich einfach eine Linie für jede Ecke des Begrenzungsrahmens von ihrer Position im vorherigen Frame bis zu ihrer Position im aktuellen Frame erstellen und dann jede dieser Linien auf Schnittpunkte mit einer der Linien in der Höhle testen könnte Wand.

Mein Google Fu hat mir jedoch keine einfache Formel zur Berechnung von Kreuzungen gezeigt. Habe ich einen schlechten Weg gewählt, oder bin ich nur schlecht bei der Suche?

Mein Spiel ist in Scala geschrieben, aber ich kann fast jede Sprache im C-Stil und viele Skriptsprachen lesen / übersetzen, unabhängig davon, worauf Sie antworten möchten

Die Trav
quelle

Antworten:

-3

Googeln "Kreuzungstest Liniensegment Liniensegment" ergab dies:

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

Steve H.
quelle
2
Die Lösung ist größer als nur der Schnittpunkt zwischen zwei Linien. Trav hat eine Reihe von Linien, die das Gelände beschreiben, und jeder Teil des Charakters kann sich mit jedem Teil einer beliebigen Geländelinie schneiden.
Doppelgreener
Das ist jedoch nur eine Wiederholung des Algorithmus. Die Formel, um das Vorhandensein einer Kreuzung zu testen, ob sie sich in den Segmenten befindet, die ich betrachte, und dann den spezifischen Ort zu ermitteln, ist genau das, wonach ich suche
The Trav
1
Der Grund, warum ich auf die Antwort geantwortet habe, ist, dass es sich um eine Wiederholung des Algorithmus handelt und Sie ihn brutal erzwingen können. Ich würde jedoch erwarten, dass heutzutage mehr dahinter steckt. Ich denke nicht, dass nur das Aufzeigen der mathematischen Formel für den Linienschnitt dem Problem gerecht wird. Was ist, wenn Ihr Level anständig groß wird und Sie Zyklen damit verschwenden, nach Kreuzungen mit einer völlig unabhängigen Wand zu suchen?
Doppelgreener
Jonathan: Nun, aus der Frage: "Ich habe einen grobkörnigen Algorithmus, der mir sagt, wann ein Teil meines Charakters wahrscheinlich mit einem Teil der Höhlenwand kollidiert ist." Obwohl wir nicht wissen, ob dieser grobe
Detailalgorithmus
7

Sie können dies mit verschiedenen Ansätzen tun;

  • Segment gegen Segment mit parametrischen Linien plus einigen Überprüfungen (da Linien keine Segmente sind).

  • Segment gegen Box

  • Segment gegen Kreis (dieser wäre mein Favorit)

. Wenn Sie jedoch einen Segment-gegen-Segment-Schnittpunkttest anfordern, finden Sie hier ein Pseudo-C ++ - Beispiel aus dem sehr interessanten Buch "Echtzeit-Kollisionserkennung":

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;
}

Die Softwarelizenzvereinbarung des Buches fordert Sie auf, das folgende Guthaben für die Verwendung der Codebeispiele anzugeben:

Codebeispiel "aus der Echtzeit-Kollisionserkennung von Christer Ericson, veröffentlicht von Morgan Kaufmaan Publishers, © 2005 Elvesier Inc"

Walküre
quelle
4

Obwohl bereits jemand eine als zufriedenstellend erachtete Antwort gegeben hat, bin ich mir nicht sicher, ob die von Ihnen beschriebene Methode einen genauen Wirkungszeitpunkt (TOI) liefert. Meine erste Neigung ist, eine genaue Antwort auf die Frage zu finden: "Wie weit kann sich der Spieler bewegen, bevor er mit einem Teil der Höhle kollidiert, wenn überhaupt eine Kollision auftritt?" erfordert den Rückgriff auf kontinuierliche Kollisionserkennungstechniken (CCD).

Insbesondere gibt es eine Technik, mit der Sie Ihren AABB effektiv auf einen einzigen Punkt "verkleinern" und gleichzeitig die Liniensegmente der Höhle mit Minkowski Addition um den gleichen Betrag "vergrößern" können. Dann kann das Problem darin gesehen werden, einen Strahl gegen ein konvexes Objekt oder einen Satz konvexer Objekte zu werfen (da ein Punkt, der sich mit konstanter Geschwindigkeit durch die Zeit bewegt, zu einem Strahl wird). Die früheste Entfernung entlang des Strahls, die sich mit der "aufgeblähten" Höhle schneidet, repräsentiert den frühesten Zeitpunkt des Aufpralls (TOI).

Am häufigsten befasst sich die Literatur dazu mit drei Dimensionen, gilt jedoch immer noch für zwei Dimensionen und sollte leicht übertragen werden können. Ich habe im Moment keine Zeit, alle Details zu formulieren oder Pseudo-Code bereitzustellen, aber vielleicht kann jemand anderes überprüfen und erweitern, worauf ich mich beziehe. Im Moment finden Sie hier einige Artikel, die den Prozess erläutern, sowie einige Begriffe, die Sie möglicherweise für Googeln interessieren.

user_123abc
quelle
0

Um anderen zu helfen, die dies auf ihren Reisen finden, finden Sie hier einen 2D-Linienkreuzungstest mit den Methoden unter https://stackoverflow.com/a/1968345/431528 .

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;
}
verzögert kaviar
quelle