Wie gehe ich mit Eckenkollisionen in 2D um?

22

Ich schreibe ein Top-Down-2D-XNA-Spiel. Seitdem ich das erste Mal hier bin, versuche ich, das Physik- und Kollisionsmaterial selbst zu schreiben, um es zu lernen.

Immer wenn mein Spieler-Sprite-Charakter versucht, sich in eine Position zu bewegen, in der sich seine Grenzen mit dem Rand einer Wand schneiden, ermittle ich einen Abprallwinkel (Einfallswinkel = Reflexionswinkel) und lasse den Spieler von der Wand abprallen und vermeide die Kollision .

Ich habe Probleme herauszufinden, wie ich mit der Situation umgehen soll, in der sich mein Sprite mit zwei Wandkanten gleichzeitig überschneidet, obwohl es z. B. an eine Ecke stößt.

Eckenkollision

Mein Code sagt mir derzeit, dass zwei Wandkanten geschnitten wurden, aber nicht, welche Kante zuerst getroffen worden wäre und daher welche Kante abprallt.

Was ist der mathematische Test, um herauszufinden, welche Kante abprallt? Es ist klar, wenn ich es mir anschaue, aber ich habe Mühe, den Mathe-Test dafür herauszufinden.

TerryB
quelle
Vielen Dank, Tetrad. Ich habe das gesehen, aber es sah so aus, als würde sich der Ball anders verhalten als mein rechteckiges Problem. In dem oben dargestellten Fall hätte das rechteckige Sprite die Unterkante der Wand getroffen und wäre von dieser abgeprallt. Die Seitenkante der Wand wäre nie in die Gleichung gekommen. Ich weiß nur nicht, wie ich das im Code ausdrücken und diese Entscheidung treffen soll.
TerryB

Antworten:

9

Wenn Sie berechnen , wie die weit in Walldie Player Spritebewegt hat, können Sie es wahrscheinlich auf dem Delta der x- und y - Koordinaten der Ecken der Basis , die sich schneid werden. Ich hoffe, das macht Sinn, ich kann mir keinen besseren Weg vorstellen, es auszudrücken.

So zum Beispiel, wenn Sie sich Ihr Diagramm ansehen. Nimm den xWert der oberen linken Ecke von Player Sprite(nach dem Zug) und subtrahiere den xWert der unteren rechten Ecke von Wall. Machen Sie dasselbe mit den yWerten und sehen Sie dann, welcher größer ist. Der Schlüssel ist, dass, wenn einer größer als der andere ist, sich der Player Spritewahrscheinlich auf dieser Seite schneidet.

Hier ist ein Bildbeispiel (dies ist ein Unterabschnitt Ihres Bildes, dem meine eigenen Zeilen hinzugefügt wurden):

Kreuzungsbeispiel

Jetzt sehen Sie hier, dass die blaue Linie größer als die grüne Linie ist. In diesem Fall befindet sich die blaue Linie auch auf der Seite, von der Player Spriteerwartet wird, dass sie abprallt.

Wenn die beiden Werte gleich sind, treffen sie direkt an der Ecke.

Nun gibt es ein kleines Problem damit. Wenn der Player Spritesehr schnell fährt oder die Kollision sehr nahe an der Ecke ist, ist es möglich, dass der Player Spriteweiter in Walldie falsche Richtung fährt . In diesem Fall müssen Sie wahrscheinlich die Geschwindigkeit des sich bewegenden Objekts überprüfen. (Siehe Nathan Reeds Antwort .)

Hinweis: Ich denke, ich versuche im Wesentlichen, die von @Blau erwähnte SAT-Kollisionserkennung zu beschreiben, aber ich habe viel Zeit damit verbracht, dies zu schreiben, und werde es trotzdem veröffentlichen. Hoffentlich hilft es dir etwas.

Richard Marskell - Drackir
quelle
Danke Drackir! Und ich denke, wenn meine Wand relativ zum Sprite gedreht wird, ist es ein bisschen kniffliger, aber das gleiche Prinzip gilt. Suchen Sie nach dem Verschiebungsvektor mit der minimalen Länge, bei dem das Sprite nicht mit der Wand kollidieren würde. Verwenden Sie dann die Wand, die zu diesem Vektor normal ist, als meine, um abzuprallen.
TerryB
@TerryB - Rotation erhöht die Komplexität. Möglicherweise möchten Sie sich über achsenausgerichtete Begrenzungsrahmen (AABB) informieren. Grundsätzlich verwenden Sie immer noch dasselbe Prinzip wie oben, indem Sie die kleinste Box testen, in die das gedrehte Objekt passt, deren Achsen jedoch an den kartesischen Achsen ausgerichtet sind. Stellen Sie sich vor, Sie hätten ein Quadrat und hätten es um 45 Grad gedreht, um daraus einen Diamanten zu machen. Die Kollision darauf zu berechnen, wäre schwierig und kostspielig. Überprüfen Sie daher zunächst mithilfe des AABB, der ein Quadrat wäre, bei dem jeder Punkt des Diamanten jede Seite in der Mitte berührt, ob sich das Objekt überhaupt in der Nähe befindet.
Richard Marskell - Drackir
Wenn Sie dann wissen, dass es in der Nähe ist, können Sie die teureren Berechnungen durchführen, um festzustellen, ob sie sich in Winkeln schneiden (was wahrscheinlich eine andere Frage insgesamt sein sollte :)).
Richard Marskell - Drackir
1
-1, da die minimale Verschiebung nicht immer die richtige Antwort auf "welche Kante zuerst kollidierte" gibt; Siehe meine Antwort.
Nathan Reed
@ NathanReed - Aus diesem Grund habe ich in meinem Abschnitt "Jetzt gibt es ein kleines Problem, wenn ich das so mache" erwähnt, dass ich die Geschwindigkeit überprüfe.
Richard Marskell - Drackir
15

Die minimale Verschiebung gibt nicht immer die richtige Antwort darauf, welche Kante zuerst getroffen wurde. Betrachten Sie diesen Fall:

Fall, der den Algorithmus der kürzesten Verschiebung bricht

Dies passiert, wenn die Geschwindigkeit hoch genug ist, dass sich der Block während eines Frames ziemlich weit bewegt. Um richtig zu erkennen, welche Kante zuerst getroffen wurde, müssen Sie eine lineare Gleichung aufstellen, um die Zeit der Kollision mit jeder Kante zu lösen. In diesem im OP-Diagramm beschriebenen Fall sind die relevanten Gleichungen:

timeXCollision = (player.left - wall.right) / -player.velocity.x
timeYCollision = (wall.bottom - player.top) / player.velocity.y

(Dies setzt ein X-Rechts-Y-Aufwärts-Koordinatensystem voraus.) Im Allgemeinen müssen Sie die Vorzeichen der X- und Y-Komponenten von player.velocity verwenden, um zu bestimmen, welches Kantenpaar getestet werden muss. Wie auch immer, sobald Sie die Kollisionszeiten berechnet haben, ist die frühere der beiden die Kollision, die Sie behandeln müssen.

Nathan Reed
quelle
1
Können Sie ein Beispiel dafür geben, wie Ihre beiden Variablen implementiert werden könnten?
BjarkeCK
1

Sie benötigen die SAT-Kollisionserkennung

Grundsätzlich müssen Sie nach dem minimalen Verschiebungsvektor suchen, der zu einem der Objekte subtrahiert, damit sich diese nicht schneiden.

In Ihrem Bild ist die minimale Verschiebung das orangefarbene Segment.

Bildbeschreibung hier eingeben

Blau
quelle
4
-1, da die minimale Verschiebung nicht immer die richtige Antwort auf "welche Kante zuerst kollidierte" gibt; Siehe meine Antwort.
Nathan Reed
wer fragt das
Blau
Die Frage stellt sich das. "Mein Code sagt mir derzeit, dass zwei Wandkanten geschnitten wurden, aber nicht, welche Kante zuerst getroffen worden wäre und daher welche Kante abprallt."
Nathan Reed
zuerst? Das Problem ist nicht, was das erste ist, es kollidiert gleichzeitig mit den beiden Kanten. Die Frage ist, welche Kante abprallt. Sie haben eine Methode gewählt, die gut für Sie ist Gut zu mir, beide sind gültig
Blau
1
Wenn Sie eine Entwurfsentscheidung treffen möchten, um Objekte so aneinander vorbeiziehen zu lassen, als ob sie an den Ecken abgerundet oder abgeschrägt wären, ist dies Ihre Entscheidung und möglicherweise die richtige für Ihr Gameplay. Aber ich glaube nicht, dass die Frage nach einer Designentscheidung lautet. Es wird mathematisch gefragt, wie man achsenausgerichtete Rechtecke voneinander abprallt. Dies ist keine Frage der Interpretation; Dieses mathematische Problem hat eine klare und korrekte Antwort auf die Kante, die abprallen soll.
Nathan Reed
0

Beantwortete eine ähnliche Frage hier

Vielleicht möchten Sie die vorherigen Positionen überprüfen -

Beispiel: Wenn sich Ihre linke Seite zuvor rechts von der rechten Seite befand und Sie kollidieren, ist eine Kollision mit der rechten Hand aufgetreten.

Wenn Sie dies tun, lösen Sie einfach Kollisionen auf der y-Achse, prüfen Sie, ob Sie mit etwas kollidieren, und lösen Sie dann Kollisionen auf der x-Achse.

ultifinitus
quelle