Wie bestimme ich die Kollisionsrichtung zwischen zwei Rechtecken?

7

Ich versuche herauszufinden, wie man die Richtung bestimmt, in der eine Kollision zwischen zwei Rechtecken auftritt.

Ein Rechteck bewegt sich nicht. Das andere Rechteck hat eine Geschwindigkeit in jede Richtung. Wenn eine Kollision auftritt, möchte ich die Position des sich bewegenden Rechtecks ​​auf den Aufprallpunkt einstellen können.

Ich bin offenbar nicht sicher, aus welcher Richtung der Aufprall erfolgt. Wenn ich mich streng vertikal oder horizontal bewege, kann ich sehr gut erkennen. Aber wenn man sich gleichzeitig in beide Richtungen bewegt, passieren seltsame Dinge.

Wie lässt sich am besten bestimmen, in welche Richtung eine Kollision zwischen zwei Rechtecken auftritt?

jgallant
quelle
1
Wie erkennen Sie derzeit eine Kollision?
MichaelHouse
3
Es hört sich so an, als würden Sie versuchen, den Aufprallpunkt zu bestimmen. Wenn ein Rechteck stationär ist, würden Sie denken, dass das Umkehren des Bewegungsvektors des sich bewegenden Rechtecks ​​Ihnen die "Kollisionsrichtung" geben würde
John McDonald

Antworten:

9

Ich bin offenbar nicht sicher, aus welcher Richtung der Aufprall erfolgt. Wenn ich mich streng vertikal oder horizontal bewege, kann ich sehr gut erkennen. Aber wenn man sich gleichzeitig in beide Richtungen bewegt, passieren seltsame Dinge.

tl; dr Die Lösung besteht darin, sich um jeweils eine Achse zu bewegen und auf Kollisionen zu prüfen .

Ich hatte genau das gleiche Problem. Ich wette, dass die Update-Phase Ihrer Spieleschleife ungefähr so ​​aussieht:

  • object.x + = object.vx
  • object.y + = object.vy
  • auf Kollisionen prüfen
  • auf Kollisionen reagieren

Der Trick dabei ist, sich um jeweils eine Achse zu bewegen und auf Kollisionen zu prüfen. Wie Sie sagten: "Wenn ich mich streng vertikal oder horizontal bewege, schaffe ich eine großartige Erkennung." Sie haben also bereits 99% des Problems gelöst. Ändern Sie einfach Ihre Logik so, dass sie so aussieht:

  • object.x + = object.vx
  • Kollisionen überprüfen / beantworten
  • object.y + = object.vy
  • Kollisionen überprüfen / beantworten

In einfachen Fällen spielt es keine Rolle, welche Achse Sie zuerst ausführen. Wenn Sie sich nicht wohl fühlen, wenn Sie die eine oder andere willkürlich auswählen, ist es sinnvoll, zuerst die Achse zu überprüfen, auf der die absolute Geschwindigkeit des Objekts am größten ist.

Larsbutler
quelle
9

Nach der Antwort von larsbutler spielt es in einfachen Fällen keine Rolle, ob Sie zuerst nach x- oder y-Kollisionen suchen. Dies kann jedoch später schnell zu Ungenauigkeiten führen (insbesondere bei komplexeren Formen, höheren Geschwindigkeiten und mehr Objekten).

Wenn jemand an der Implementierung eines ausgefeilteren Kollisionserkennungsalgorithmus interessiert ist, finden Sie hier eine Übersicht über die erforderlichen Funktionen:

  1. Zunächst führt der Algorithmus einen Sweep durch und beschneidet die Anzahl der zu überprüfenden Objekte. Wenn Sie jedes Objekt mit jedem anderen Objekt vergleichen, kann dies rechenintensiv sein. Grundsätzlich sagen Sie voraus, ob ein Objekt in Zukunft wahrscheinlich kollidieren wird. Wenn es nicht sehr wahrscheinlich ist, führen Sie die Berechnungen nicht durch.
  2. Nach dem Beschneiden führen Sie einen vorläufigen Kollisionstest durch. Jedes Objekt hat ein begrenzendes Rechteck oder einen begrenzten Kreis (etwas, das leicht zu berechnen ist). Das Erkennen, ob zwei Kreise / Rechtecke kollidieren, ist recht einfach und kann unnötige Berechnungen zwischen zwei Objekten auf gegenüberliegenden Seiten des Bildschirms schnell eliminieren.
  3. Wenn eine vorläufige Erkennung durchgeführt wurde, müssen Sie die Kanten jeder Form durchlaufen und Kollisionspunkte erkennen (Schnittpunkt zweier Liniensegmente). In Jons Fall wäre dies der Kollisionspunkt auf der vertikalen und horizontalen Achse.
  4. Sobald Sie eine Liste von Kollisionspunkten haben, müssen Sie den genauen Kollisionspunkt berechnen. Es gibt eine Reihe von Möglichkeiten, wie Sie dies tun können, und alles hängt davon ab, wie genau Sie sein möchten. Eine Möglichkeit ist , auf die Hälfte der Zeitinkrement (Ihres Physik - Integrator ), die Formen Positionen neu zu berechnen, und wiederholen Sie die Kollisionserkennung , bis es ist nur ein Kollisionspunkt. Grundsätzlich nähern Sie sich dem "Moment des Aufpralls" an. Wenn Ihre Simulation nicht sehr viele partielle Differentialkräfte aufweist, können Sie einfach die Geschwindigkeit der vorherigen Integration mit nachfolgenden Zeithalbierungen verwenden.
  5. Die Ergebnisse von Schritt vier geben Ihnen die ungefähren Kollisionspunkte (innerhalb einer oberen / unteren Grenze wie 3px oder so). Wenn es mehr als einen Kollisionspunkt gibt, müssen Sie diese als imaginäre Kante behandeln. Sie können dann Kollisionsauflösungsberechnungen durchführen (Geschwindigkeit, Impuls, Reibung usw.)

Hoffe das hilft jemandem.

Speziell für Jons Frage:

Der Schritt, den Sie beim Kollisionsalgorithmus vermissen, ist Schritt 4. Soweit ich weiß, schneiden sich Ihre Rechtecke diagonal und erhalten zwei Kollisionspunkte (einen horizontal und einen vertikal). Die Bestimmung, welcher Kollisionspunkt zuerst aufgetreten ist, hängt wirklich davon ab, was Sie für die Physikintegration verwenden.

Aus Ihrer Beschreibung geht hervor, dass sich die Rechtecke nicht drehen und Dinge wie partielle Differentialkräfte keine große Rolle spielen. Wenn dies der Fall ist , ist es ziemlich einfach herauszufinden, welche Kante zuerst kollidiert. Hier ist ein Pseudocode:

/*
   Assume Obj1 is stationary
   Assume Obj2's velocity is -x and -y (to bottom left)
   From this, we know the collision edges are:
*/
colEdgesObj1 = [1,0]; //right, top
colEdgesObj2 = [0,1]; //left, bottom
//... where [0=left/1=right, 0=top/1=bottom]

//Calculate distances between Obj1 edges and Obj2 edges
distX = Math.Abs(Obj1[colEdgesObj1[0] ? "right" : "left"] -
                 Obj2[colEdgesObj2[0] ? "right" : "left"]);
distY = Math.Abs(Obj1[colEdgesObj1[1] ? "bottom" : "top"] -
                 Obj2[colEdgesObj2[1] ? "bottom" : "top"]);

//Calculate time object would take to go those distances
//(assuming Obj2 is the only moving object)
timeX = distX/Obj2.VelX;
timeY = distY/Obj2.VelY;

//If time is greater, that axis has been colliding longer
if timeX > timeY
    //collided X axis first
else if timeY > timeX
    //collided Y axis first
else
    //collided at a corner
Azmisov
quelle