2D-AABBs und Auflösen mehrerer Kollisionen

8

Okay, das ist ein Problem, das ich schon seit einiger Zeit herauszufinden versuche. Meins ist ein 2D-Plattformspiel mit einer Welt aus (normalerweise) unbeweglichen Kacheln und mobilen Sprites, die beide AABBs verwenden, um ihre Hitboxen darzustellen. Dieses Spiel ist aufgrund einiger Komplikationen beim Verschieben von Kachelebenen NICHT gitterbasiert.

Ich kann Kollisionen erkennen und die Tiefe der Kollision leicht herausfinden. Ich verwende die "Methode der flachsten Achse", um zu bestimmen, wie eine Kollision zwischen dem Sprite und der Kachel gelöst werden kann. Wenn das Sprite horizontal tiefer als vertikal ist, ist die aufzulösende Richtung entweder oben oder unten. Wenn das Sprite vertikal tiefer als horizontal ist, ist die aufzulösende Richtung entweder links oder rechts.

Diagramm Nr. 1

Das ist einfach genug und funktioniert ziemlich gut. Das heißt, bis ein Sprite mit mehr als einer Kachel kollidiert. Da von Natur aus jede Kollision separat überprüft werden muss, können unterschiedliche Kollisionen unterschiedliche Auflösungsrichtungen haben. Wenn beispielsweise ein Sprite versucht, über eine Reihe von Kacheln zu laufen, schneiden sie für einen Frame die nächste Kachel wie z dass die horizontale Tiefe kürzer als die vertikale Tiefe ist. Wenn die Kollision "links auflösen" lautet, wird sie zurückgeschoben und bleibt an der Ecke hängen.

Diagramm 2

Ich habe über dieses Problem schon seit einiger Zeit nachgedacht, und es sind mehrere Lösungen zu mir gekommen, aber alle haben Mängel. Ich könnte bestimmte Seiten als nicht erreichbar markieren, aber ohne eine gitterbasierte Engine ist die Bestimmung der "Nichterreichbarkeit" bemerkenswert komplex, insbesondere wenn sich bewegende Kachelschichten immer möglich sind.

Eine andere mögliche Methode wäre, Kollisionen vorherzusagen, bevor sie auftreten, und die Bewegung bis zum Punkt der Kollision "zurückzuarbeiten", nehme ich an, aber ich bin mir nicht sicher, wie die Mathematik dafür funktioniert.

Ich habe das Gefühl, dass mir etwas unglaublich Offensichtliches fehlt, zumal Spiele aus den 80ern dieses Problem bereits gelöst haben.

Celarix
quelle
Sie können einfach die Position des Spielers ändern, basierend darauf, welches Plättchen zuerst in Ihrem Scheck kam
Chachmu

Antworten:

6

Das Problem

Das Problem liegt in Ihrer Methode zur Kollisionsauflösung. Ihre Methode lautet wie folgt:

  1. Bewegen Sie den Player.
  2. Auf Kollision prüfen.
  3. Bestimmen Sie die kürzeste Kollisionstiefe.
  4. Kollision lösen.

Das Problem dabei ist, dass es den Spieler leicht in die falsche Richtung bewegen kann. Wie dies passieren kann, sehen Sie im Bild unten:

Kollisionsfehler

Da sich der Spieler nach rechts unten bewegt und sich über dem Boden befindet, würde man erwarten, dass der Spieler auf dem Boden landet (neben dem grünen Kästchen). Stattdessen wird es nach links aus dem Boden geschoben (dargestellt durch das rote Kästchen). Dies kann ein Problem sein, wenn der Spieler versucht, von einer Plattform zur anderen zu springen, da der Spieler aufgrund eines schlechten Kollisionscodes möglicherweise zu Tode fällt.

Die Lösung

Die Lösung für dieses Problem ist eigentlich ziemlich einfach. Anstatt die obige Methode zu verwenden, lösen Sie die Kollision folgendermaßen auf:

  1. Bewegen Sie den Player entlang der X-Achse.
  2. Auf kollidierende Fliesen prüfen.
  3. Lösen Sie die X-Kollision.
  4. Bewegen Sie den Player entlang der Y-Achse.
  5. Auf kollidierende Fliesen prüfen.
  6. Y-Kollision auflösen.

Jetzt hoffe ich, dass Sie Ihren Tiefenprüfcode nicht weggeworfen haben, da Sie ihn für die Schritte 3 und 6 noch benötigen.

Um die Kollision zwischen Kacheln auf einer der beiden Achsen (nach dem Bewegen des Spielers) aufzulösen, erhalten Sie zuerst die Tiefe der Kollision. Sie nehmen dann die Tiefe der Kollision und subtrahieren diese von den Achsen, die Sie gerade auf Kollision prüfen. Beachten Sie, dass die Tiefe negativ sein sollte, wenn Sie sich nach links bewegen, damit sich der Spieler in die richtige Richtung bewegt.

Mit dieser Methode müssen Sie sich nicht nur nicht um Kollisionsfehler wie im Szenario im obigen Bild kümmern, sondern diese Kollision kann auch mit Kollisionen mit mehreren Kacheln umgehen.

Beispielcode:

void move(velocity)
{
    top = player.y / TILE_HEIGHT;
    bottom = top + (player.height / TILE_HEIGHT);
    left = player.x / TILE_WIDTH;
    right = left + (player.width / TILE_WIDTH);

    // Check X

    player.x += velocity.x;
    player.updateAABB();
    for(int tx = left - 1; tx <= right + 1; tx++)
    {
        for(int ty = top - 1; ty <= bottom + 1; ty++)
        {
            aabb = world.getTileAABB(tx, ty);
            if(aabb.collidesWith(player.aabb))
            {
                depth = player.aabb.getXDepth(aabb);
                player.x -= depth;
            }
        }
    }

    // Now check Y

    player.y += velocity.y;
    player.updateAABB();
    for(int tx = left - 1; tx <= right + 1; tx++)
    {
        for(int ty = top - 1; ty <= bottom + 1; ty++)
        {
            aabb = world.getTileAABB(tx, ty);
            if(aabb.collidesWith(player.aabb))
            {
                depth = player.aabb.getYDepth(aabb);
                player.y -= depth;
            }
        }
    }

    player.updateAABB();
}
Lysol
quelle
Faszinierend, aber ich sehe immer noch ein Problem. In meinem zweiten Szenario kollidiert das Sprite mit einer Reihe von Kacheln. Wenn ich zuerst X-Kollisionen überprüfe, wird in diesem Szenario eine falsche Erkennung angezeigt, die weiterhin nicht ordnungsgemäß auf der linken Seite behoben wird.
Celarix
@ Celarix Das zweite Szenario sollte nicht auftreten, da Sie nicht nur zuerst die X-Achse überprüfen, sondern sich zuerst entlang der X-Achse bewegen. Das Sprite würde sich niemals in einer Reihe von Kacheln befinden, da der Y-Kollisionstest aus der vorherigen Bewegung verhindern würde, dass Sie mit einer solchen Reihe von Kacheln kollidieren. Stellen Sie einfach sicher, dass Kollisionen immer richtig gelöst werden. Ich hatte einmal einige Probleme, die durch die Tatsache verursacht wurden, dass ich floats zum Speichern meiner Koordinaten verwendete. Es verursachte also ein Zittern. Die Lösung bestand darin, die Koordinaten abzurunden, wenn ich die Kollision gelöst hatte.
Lysol
Sie haben Recht, und ich denke, dies könnte die Lösung für mein fast zweijähriges Problem sein. (Ich bin ein langsamer Entwickler.) Vielen Dank!
Celarix
Es gibt einige Probleme mit meiner Antwort. Dies funktioniert in den meisten Situationen. Beachten Sie jedoch, dass es unterschiedliche Ergebnisse gibt, je nachdem, ob Sie zuerst die X-Kollision oder zuerst die Y-Kollision überprüfen. Denken Sie auch daran, dass das Tunneln ein Problem ist. Dies schlägt bei Hochgeschwindigkeitsobjekten fehl, da sie Kacheln überspringen.
Lysol
Ich denke, ich bin zuerst mit X gefahren, damit die Pisten richtig funktionieren. Bullet-Through-Paper ist in meinem Plattformer kein wirkliches Problem, da sich nichts fast schnell genug bewegt, um durch Kacheln zu gelangen. Danke für den weiteren Input!
Celarix
0

Sie überdenken das Problem und bringen ein paar Probleme zusammen. Aber das ist okay, denn wie Sie sagten, ist dies ein sehr gelöstes Problem mit vielen tollen Antworten.

Lassen Sie es uns zusammenfassen:

  1. Tilemaps . Ihr erstes Beispiel ist ein Sprite, der über eine Reihe horizontal angelegter Kacheln läuft (oder eine vertikal angelegte Kachelwand hinuntergleitet, sie sind isomorph). Eine sehr elegante Lösung hierfür besteht darin, die Kanten von Kacheln, an die ein Sprite nicht gelangen kann, einfach nicht zu überprüfen, z. B. Kanten, die "unterirdisch" sind, oder Kanten, die an eine andere vollständig feste Kachel grenzen.

    Sie haben Recht, dass das Sprite aufgrund der Schwerkraft abfällt, sich dann seitlich bewegt und dann stecken bleibt ... aber die Antwort ist, sich nicht um den linken oder rechten Rand der unterirdischen Kacheln zu kümmern . Auf diese Weise bewegt Ihre Kollisionsauflösungsroutine das Sprite nur vertikal - und Ihr Sprite kann seinen fröhlichen Weg fortsetzen.

    In den Metanet-Kachel-Tutorials finden Sie eine schrittweise Erklärung. Sie sagen in Ihrer Frage, dass Sie keine herkömmliche Tilemap verwenden, aber das ist auch in Ordnung: Statische Kacheln befinden sich in der Tilemap und werden wie oben aktualisiert, während Plattformen verschoben werden und Updates wie die Nummer 2 unten.

  2. Andere AABBs . Sie werden nur dann auf ein Problem stoßen, wenn sich Ihr Sprite in einem einzigen Frame um eine Strecke bewegen kann, die größer ist als die Breite / Höhe der meisten AABBs in Ihrem Spiel. Wenn dies nicht möglich ist, sind Sie goldrichtig: Lösen Sie die Kollisionen nacheinander, und es funktioniert einwandfrei.

    Wenn sich die AABBs in einem einzelnen Frame sehr schnell bewegen können , sollten Sie die Bewegung bei der Überprüfung auf Kollisionen "fegen": Teilen Sie die Bewegung in kleinere Brüche auf und überprüfen Sie sie bei jedem Schritt auf Kollisionen.

drhayes
quelle