Schnelltipp Kollisionserkennung zwischen einem Kreis und einer Linie

In meinem vorherigen Quick Tip haben wir uns allgemein mit der Idee der Kollisionserkennung befasst und insbesondere auf Kollisionen zwischen zwei Kreisen. In diesem Schnelltipp werden wir eine Kollision zwischen einem Kreis und einer Linie erkennen.


Dies ist das Ergebnis, an dem wir arbeiten werden. Klicken Sie auf die Schaltfläche Neu starten, um alle Kreise oben auf der Bühne neu zu positionieren und zu sehen, wie sie herunterfallen.

Beachten Sie, dass die Kreise mit der Linie außerhalb des gezeichneten Segments kollidieren. Mein nächster Schnelltipp zeigt, wie Sie dies beheben können.


Schritt 1: Die allgemeine Idee

Um zu prüfen, ob ein Kreis mit einer Linie kollidiert ist, müssen Sie das überprüfen senkrechte Länge Von der Linie zum Kreis. Beachten Sie das folgende Diagramm.

Aus dem obigen Diagramm ist klar, dass die Fälle 3 und 4 eine Kollision zwischen dem Kreis und der Linie erkennen sollen. Wir schließen daraus, dass wenn die senkrechte Länge (rot markiert) gleich oder kleiner als der Radius des Kreises ist, eine Kollision aufgetreten ist, weil der Kreis die Linie berührt oder überlappt. Die Frage ist, wie berechnen wir diese senkrechte Länge? Vektoren können helfen, unser Problem zu vereinfachen.


Schritt 2: Linie Normal

Um auf der Bühne eine Linie zu zeichnen, benötigen wir zwei Koordinaten (c1 und c2). Die von c1 nach c2 gezeichnete Linie bildet einen Vektor, der auf c2 zeigt. (Beachten Sie die Richtung des Pfeils)..

Als nächstes müssen wir die Leitung finden normal. Die Normale der Linie ist eine andere Linie, die 90 ° mit der ursprünglichen Linie bildet und an einem Punkt mit ihr schneidet. Obwohl es sich bei der Normallinie der Linie noch um eine andere Linie handelt, kann die Vektorform der Normalen weiter als die gekennzeichnet werden links oder Recht Normal relativ zum Vektor der Linie. Die linke Normale ist der Linienvektor selbst, gedreht um -90 °. Die rechte Normale ist gleich, jedoch um 90 ° gedreht. Denken Sie daran, dass die y-Achse im Flash-Koordinatenraum im Vergleich zu der y-Achse in einem typischen Diagramm invertiert ist - positive Drehung ist also im Uhrzeigersinn und negative Drehung ist entgegen dem Uhrzeigersinn.


Schritt 3: Projektion links normal

Die linke Normale wird in unserem Versuch verwendet, um die senkrechte Länge zwischen dem Kreis und der Linie zu berechnen. Details finden Sie in der folgenden Abbildung. EIN bezieht sich auf einen Vektor, der von zeigt c1 zum Kreis Die senkrechte Länge bezieht sich tatsächlich auf den Vektor A Projektion auf der linken Seite normal. Wir leiten diese Projektion unter Verwendung der Trigonometrie ab: es ist | A | Cosinus (Theta), woher | A | bezieht sich auf die Größe des Vektors EIN.

Der einfachste Ansatz besteht darin, Vektoroperationen zu verwenden, insbesondere das Punktprodukt. Ausgehend von der Gleichung des Punktprodukts ordnen wir die Terme neu an, so dass wir zum zweiten Ausdruck kommen, der unten gezeigt wird. Beachten Sie, dass die rechte Seite der zweiten Gleichung die Projektion ist, die wir berechnen wollten!

Beachten Sie auch, dass die linke und rechte Seite der Gleichung letztlich zum gleichen Ergebnis führen, obwohl sie sich in ihren Ansätzen unterscheiden. Anstatt die rechte Seite der Gleichung zu verwenden, können wir uns also für die linke Seite der Gleichung entscheiden. Um leicht zum Endergebnis zu gelangen, ist es vorteilhaft, die Linke zu verwenden, da Variablen leicht aufgelöst werden können. Wenn wir darauf bestehen, das Recht der Gleichung zu verwenden, müssen wir ActionScript durch strenge mathematische Arbeit bei der Berechnung des Winkels Theta forcieren. Wir schließen mit dem folgenden Diagramm ab.

(* Zusätzlicher Hinweis: Wenn der Kreis unter den Linienvektor fällt, ergibt die aus der Formel im obigen Diagramm berechnete senkrechte Länge einen negativen Wert.)


Schritt 4: Implementieren der Circle-Line-Kollisionserkennung

Nachdem wir den Ansatz nun mathematisch verstanden haben, setzen wir ihn in ActionScript um. Beachten Sie in diesem ersten Abschnitt, dass der Vektor der Linie um -90 ° gedreht wird, um die linke Normale zu bilden.

 // Deklarationskoordinaten x1 = 50; y1 = 100; x2 = 250; y2 = 150; // Zeichnen einer Linie graphics.lineStyle (3); graphics.moveTo (x1, y1); graphics.lineTo (x2, y2) // Linienvektoren bilden line = new Vector2D (x2 - x1, y2 - y1); leftNormal = line.rotate (Math.PI * -0,5);

In diesem zweiten Abschnitt habe ich die erwähnten Berechnungen und die Bedingung für die Prüfung der Kollision zwischen Kreis und Linie hervorgehoben.

 private Funktionsaktualisierung (e: Event): void for (var i: int = 0; i < circles.length; i++)  //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); circles[i].y += 2; //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius) circles[i].y -= 2;   

Für diejenigen, die weiter nachforschen möchten, sind im Folgenden Auszüge aus den in Vektor wie

 / ** * Methode zum Erhalten der Projektion des aktuellen Vektors auf eine bestimmte Achse * @param-Achse Eine Achse, auf die der Vektor auf * @return projiziert wird. Die Projektionslänge des aktuellen Vektors auf einer bestimmten Achse * / public function projectionOn (Achse: Vector2D): Number return this.dotProduct (axis.normalise ())
 / ** * Methode zum Ausführen eines Punktprodukts mit einem anderen Vektor * @param vector2 Ein Vektor zum Ausführen eines Punktprodukts mit dem aktuellen Vektor * @return Eine skalare Zahl eines Punktprodukts * / public function dotProduct (vector2: Vector2D): Number var componentX: Number = this._vecX * vector2.x; var componentY: Number = this._vecY * vector2.y; return KomponenteX + KomponenteY; 
 / ** * Methode zum Erhalten der Vektoreinheit des aktuellen Vektors * @return Eine Kopie des normalisierten Vektors * / public function normalize (): Vector2D new2D zurückgeben (this._vecX / this.getMagnitude (), this._vecY / this. getMagnitude ())
 / ** * Methode zur Ermittlung der aktuellen Größe des Vektors * @return Größe des Typs Number * / public function getMagnitude (): Number return Math.sqrt (_vecX * _vecX + _vecY * _vecY); 

Schritt 5: Das Ergebnis

Drücken Sie die Restart-Taste, um alle Kreise oben auf der Bühne neu zu positionieren. Beachten Sie, dass die Kollision zwischen der ganze Linie (einschließlich des nicht gezeichneten Abschnitts) und der Kreise. Um die Kollision nur auf das Liniensegment zu beschränken, bleiben Sie für den nächsten Quick Tip auf dem Laufenden.

Fazit

Danke fürs Lesen. Bleiben Sie dran für den nächsten Tipp.