Wiederverwendbare Top-Down-Kollisionsklasse

8

Ich habe kürzlich ein Monogame aufgenommen und arbeite an einem einfachen Top-Down-Spiel, um mich anzufangen und die Grundlagen zu lernen.
Ich habe die Bewegung und die Drehung, um der Maus zu folgen, aussortiert, aber ich bin mit den Kollisionen festgefahren.
Was ich im Grunde wissen möchte, sind zwei Dinge:

  1. Was wäre der beste Weg, um mit Kollisionen umzugehen? Ich weiß, dass Rectangle.Intersects(Rectangle1, Rectangle2)das überlappende Rechteck zurückgegeben wird, aber da sich die Bewegung von oben nach unten auf der x / y-Achse befindet, möchte ich wissen, wo die Kollision stattfindet, damit ich eine Art "Wandgleiten" erstellen kann, das der Spieler nicht bekommt an der Wand stecken.
    Ist es wirklich der beste Ansatz, die x / y-Koordinaten des Spielers mit den Koordinaten fester Objekte zu vergleichen und den Spieler dann an seine vorherige Position zu bringen, wenn er die Grenzen eines festen Objekts betritt? Was würdest du vorschlagen?
  2. Was wäre der beste Weg, um Kollisionen auf alle Feststoffe, NPCs usw. anzuwenden? Ich denke gerade darüber nach, eine gameObjectKlasse zu erstellen , von der alle Objekte erben und nur die Kollisionen dort behandeln.

Danke fürs Lesen und hoffe, dass mir jemand ein paar Tipps geben kann.

Eliah John
quelle
Schauen Sie sich diese Antwort zur Spielarchitektur an, um einige Gedanken zu Ihrer zweiten Frage zu erhalten .
Andrew Russell

Antworten:

9

Im Allgemeinen behandeln die meisten Physik-Engines dieses Problem, indem sie die sich überschneidenden Objekte trennen .


Wenn Ihre Objekte also durch Rechtecke dargestellt werden (auch als "Axis Aligned Bounding Boxes" bezeichnet) und auf einem bestimmten Rahmen wie folgt kollidieren:

Kollision


Sie würden dann das Ausmaß der gegenseitigen Durchdringung auf jeder Achse messen. Wählen Sie dann die Achse mit der geringsten Durchdringung aus und trennen Sie die Objekte entlang dieser Achse.

Trennen


Sie würden dies dann als "Kollision" registrieren und die entsprechende Dynamik anwenden.

Wenn Sie beispielsweise entlang der Wand gleiten möchten, setzen Sie die Geschwindigkeit auf der Achse, auf der Sie getrennt haben (die X-Achse in der obigen Abbildung), auf Null und lassen die Geschwindigkeit auf der anderen Achse allein.

Sie können aber auch Reibung anwenden oder die Objekte auseinander springen lassen.


Hier ist ein exzellentes, interaktives Tutorial , das viel detaillierter zeigt, wie das geht.

Wenn Sie diesen Weg weit gehen möchten (mehr als nur einfache AABB-Kollisionen), sollten Sie eine vorhandene Engine wie Farseer Physics verwenden .


Zum Schluss noch ein Hinweis zur Implementierung (wenn Sie nicht den Farseer-Weg gehen): RectangleVerwendet intWerte, die in den meisten Fällen für die Physik nicht wirklich geeignet sind. Erwägen Sie, eine eigene AABBKlasse zu erstellen, die floatstattdessen verwendet.

Ihre zweite Frage wird durch meine alte Antwort zur Spielarchitektur hier ziemlich gut beantwortet , daher werde ich sie hier nicht wiederholen.

Andrew Russell
quelle
Vielleicht gibt es etwas, das ich nicht verstehe, aber ist dieser Ansatz nicht fehlerhaft? Ich habe das Problem hier veranschaulicht: jmp.sh/jEW2lvR Es würde manchmal zu einem seltsamen Verhalten führen.
BjarkeCK
@BjarkeCK: Ja, Sie müssen zusätzliche Arbeit leisten, um solche Fälle zu behandeln. Ich bin nicht gut genug versiert, um zu erklären, wie man richtig damit umgeht (ich benutze nur Farseer und nenne es einen Tag). Schauen Sie sich möglicherweise "Abschnitt 5" dieses Links an .
Andrew Russell
1

1: Ich habe auch an einem relativ einfachen Top-Down-Actionspiel gearbeitet und nach einer Woche (-s?) Kämpfen habe ich eine Art schrittweisen Ansatz zur Erkennung und Reaktion von Kollisionen verwendet. Der Hauptgrund dafür ist, dass die Verwendung der kürzesten Durchdringung in einigen Fällen zu einer "Teleportation" an eine neue Position führen würde, an der sich das sich bewegende Objekt zuvor nicht befand.

Wenn sich ein Objekt bewegen möchte,

  1. Ich erstelle einen Begrenzungsrahmen des Objekts an der Position des Objekts + moveAmount-Vektor und erstelle eine Art Zielbegrenzungsrahmen
  2. Dann überprüfe ich diesen Zielbegrenzungsrahmen auf Schnittpunkte mit den Spielobjekten, Kacheln usw., falls vorhanden, füge ich sie einer neuen Liste hinzu, die alle möglichen Kollisionen für den aktuellen Frame enthält
  3. Wenn keine Schnittpunkte vorhanden sind, bewegt sich das Objekt. aber wenn es eine Kreuzung gibt,
  4. Ich habe die gewünschte Bewegung in "Schritte" aufgeteilt. dann führe ich eine Schleife für die Anzahl der Schritte aus, die ich habe. Jeder Schritt bewegt das Objekt nur um 1 Pixel in x- und y-Richtung.
  5. Für jeden Schritt überprüfe ich jede neue projizierte Position auf Kollisionen. Wenn nichts, füge ich den Bewegungsvektor des Schritts zum endgültigen Bewegungsvektor hinzu.
  6. Wenn es eine Kollision gibt (intersects gibt true zurück), vergleiche ich die vorherige Position (Position im vorherigen Schritt) des sich bewegenden Objekts mit dem Objekt, mit dem es kollidiert.
  7. Abhängig von dieser vorherigen Position stoppe ich die Bewegung entlang der Konfliktachse (z. B. wenn das sich bewegende Objekt von oben auf das kollidierende Objekt trifft, setze ich den y-Wert des Bewegungsvektors auf 0 usw.).
  8. Ich wiederhole dies für jeden aufeinanderfolgenden Schritt und addiere die angepassten Schrittvektoren zu einem endgültigen angepassten moveAmount-Vektor, den ich sicher zum Verschieben des Objekts verwenden kann, ohne dass Kollisionen auftreten.

Dieser Ansatz stellt sowohl sicher, dass das Objekt zurückspringt, um die vorherige Position zu korrigieren, als auch, dass es gegen die Wände, Objekte usw. gleiten kann.

2: Ich selbst verwende eine statische Kollisionsklasse, die von allem verwendet werden kann. Es enthält Methoden zur Kollisionserkennung und Vektoranpassung, die von so ziemlich allem aufgerufen werden können. Ob diese Methoden von einer "Master" -Spielklasse oder von einer Objektunterklasse aufgerufen werden, spielt in meinem Fall keine Rolle, da die Kollisionsklasse in jedem Frame für alle Rechtecke, mit denen sich das sich bewegende Objekt schneidet, eine neue Liste erstellt. Diese Rechtecke können aus Kacheln, Dekorationen, NPCs stammen, was auch immer Grenzen hat und im Grunde kollidierbar ist. Dies bedeutet, dass die bloße Notwendigkeit für alle Spielobjekte, die kollidierbar sind, darin besteht, ein Begrenzungsrechteck zu haben. Wenn sie das haben, erledigt die Kollisionsklasse den Rest.

hoffe das war verständlich.

EIN V
quelle
0

1: Ich habe erfolgreich eine Technik verwendet, um dieses Problem zu lösen: Mithilfe der Geschwindigkeit und Position können Sie die Kollision ermitteln und zurücklaufen, bis die Position sehr nahe am genauen Kollisionspunkt liegt.

Dies ist nicht Teil der Antwort auf Ihre erste Frage. Wenn Sie jedoch viele Objekte haben, die miteinander kollidieren können, sollten Sie Quadtrees verwenden, um die Leistung zu verbessern. Es gibt ein sehr gutes Tutorial mit vielen Beispielen hier .

2: Ich empfehle immer Entity-Systems .

Filipe Borges
quelle