Schnellere 2D-Kollisionserkennung

13

Vor kurzem habe ich an einem rasanten 2D-Shooter gearbeitet und bin auf ein gewaltiges Problem gestoßen. Kollisionserkennung. Sicher, es funktioniert, aber es ist sehr langsam. Mein Ziel ist: Habe viele Feinde auf dem Bildschirm und lasse sie sich nicht gegenseitig berühren. Alle Feinde jagen die Spielereinheit. Die meisten von ihnen haben die gleiche Geschwindigkeit, so dass sie früher oder später alle den gleichen Platz einnehmen, während sie dem Spieler nachjagen. Für den Spieler sieht es so aus, als würden Sie nur von einem Feind verfolgt. Um zu verhindern, dass sie denselben Platz einnehmen, habe ich eine Kollisionserkennung hinzugefügt (eine sehr einfache 2D-Erkennung, die einzige mir bekannte Methode).

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

Das funktioniert gut. Solange ich nur <200 feindliche Wesenheiten habe. Wenn ich mich 300-350 feindlichen Objekten nähere, beginnt meine Bildrate stark zu sinken. Zuerst dachte ich, es wäre schlecht gerendert, also entfernte ich ihren Draw Call. Das hat überhaupt nicht geholfen, und natürlich wurde mir klar, dass es sich um die Aktualisierungsmethode handelte. Der einzige schwere Teil ihrer Aktualisierungsmethode ist dieser Teil, bei dem sich jeder Feind durch jeden Feind schlängelt. Wenn ich mich 300 Gegnern nähere, führt das Spiel eine schrittweise Iteration von 90000 (300 x 300) durch. Mein mein ~

Ich bin mir sicher, dass es einen anderen Weg geben muss, um diese Kollisionserkennung zu erreichen. Obwohl ich keine Ahnung habe wie. Auf den Seiten, die ich finde, geht es darum, wie man die Kollision zwischen zwei Objekten ausführt oder wie man die Kollision zwischen einem Objekt und einer Kachel überprüft. Ich kenne diese beiden Dinge bereits.

tl; dr? Wie nähere ich mich der Kollisionserkennung zwischen LOTS von Entitäten?

Schnelle Bearbeitung: Wenn es um Hilfe geht, verwende ich C # XNA.

eShredder
quelle
Ich frage mich, wie Sie es geschafft haben, zunächst auf 90 km zu kommen. Meine Drosseln bei 20K (ich mache aber eine vollständige SAT MTV Erkennung). Aber ich schleife durch alle Feinde ist das einzige, was möglich scheint. Was Sie jedoch tun müssen, ist zu überprüfen, ob sie bereits überprüft wurden, denn wenn Sie dies so sagen, werden alle zweimal mit allen getestet.
Delusional Logic
3
Dies ist ein mögliches Duplikat von gamedev.stackexchange.com/questions/39931/…
Markus von Broady
Es gibt eine sehr gute Antwort auf die Frage, die @MarkusvonBroady verknüpft hat.
Cypher

Antworten:

11

Sie haben Ihr Problem bereits auf den Kopf getroffen und lassen jede Entität mit jeder anderen Entität abgleichen. Was Sie wollen, ist eine Art 'Detaillierungsgrad'-System (es ist so ziemlich ein sehr einfaches Szenendiagramm, Sie verwenden es nur für andere Zwecke als das Rendern :)), bei dem mögliche Kollisionskandidaten besser ausgewählt werden.

Ich mache im Allgemeinen drei Sammlungen für solche Systeme. Und wenn Sie über die Anzahl der Entitäten sprechen, die Sie haben möchten, müssen Sie möglicherweise sogar ein vollständiges Szenendiagramm dafür erstellen, da die Tracking-Daten (3 Listen pro Entität mit einem Eintrag für jede andere Entität) schnell herauskommen können der Kontrolle.

Grundsätzlich haben Sie drei Listen. Die erste sollte eine sehr kleine Liste von Entitäten sein, die Sie bei jedem Frame mit Interaktionen überprüfen werden. Sie bestimmen dies, weil sie sich innerhalb des X-Bereichs der betreffenden Entität befinden. Wie erwähnt, besteht der Sinn dieser Liste darin, jede Entität zu enthalten, die vernünftigerweise mit einer anderen Entität dieses Rahmens kollidieren kann.

Die nächste Liste ist eine Liste, die sich in einem Pufferbereich befindet, der sich ohne großen Aufwand in den Bereich der Entität bewegen könnte. Dieser Bereich wird nur aus Gründen der Argumentation als X * 1.5 bezeichnet. Dies ist eine zeitlich begrenzte Liste, in der Sie nur eine Handvoll von ihnen pro Frame aktualisieren, aber sicherstellen, dass Sie sie schnell genug durcharbeiten, um den Eindruck zu erwecken, dass die Dinge reibungslos funktionieren.

Die dritte Liste ist die 'Alles andere'-Liste und ein Weg, um zu vermeiden, dass sich dies lohnt (Scannen der gesamten Entitätsliste und eventuell Überprüfen, ob sie in einer der anderen Listen enthalten ist, bevor Sie fortfahren? Abhängig von der Listengröße Dies könnte funktionieren oder die Situation verschlechtern.) Die Objekte in dieser Liste werden am wenigsten überprüft, da es definitiv mehr als ein paar Frames dauern sollte, bis sie in eine der beiden anderen Listen eingefügt werden.

Um dies aufrechtzuerhalten, müssen Sie auch bei den Kollisionstests sicherstellen, dass Sie aktualisieren, in welcher Liste sich die Entitäten befinden. Personen, die sich außerhalb der Reichweite befinden, sollten herabgestuft werden aktivere Checkliste.

Vorausgesetzt, Sie halten die Dinge einfach genug, sollte dies Ihren Bedürfnissen entsprechen. Wenn Sie zusätzliche Informationen zu einem vorhandenen Rendering-Szenendiagramm hinzufügen können (vorausgesetzt, Sie haben eines), können Sie es abfragen, um eine Liste von Objekten zu erhalten, die sich in einem noch besseren Bereich befinden, da dies der gesamte Punkt eines Szenendiagramms ist sowieso (schneller Zugriff auf eine Liste relevanter Daten basierend auf einer Position). Dies würde möglicherweise mehr Arbeit erfordern, und Sie sollten immer überlegen, was Sie tun müssen, im Vergleich zu dem, was Sie praktisch tun sollten.

Hoffe das hilft.

James
quelle
1
Dies ist eine vage Antwort. Und können wir akzeptieren, einige Kollisionen zu verpassen? Viel einfacher ist es, eine Datenstruktur zu verwenden, die die Oberflächenpartitionierung für Sie übernimmt, wie z. B. den Quad-Baum, über den ich hier spreche. Sogar ein Quad-Baum muss ein wenig feinabgestimmt werden, um Overhead zu vermeiden. Daher kann ich mir die Komplexität der von Ihnen angesprochenen "Lösung" nicht vorstellen. Grundlegende Programmierregel: Verwenden Sie einfach die richtige Datenstruktur.
GameAlchemist
@VincentPiel Ein Szenendiagramm ist nicht komplexer als ein Quad-Baum.
Cypher
@ James: Offensichtlich ist es komplexer. Wenn es Ihnen nichts ausmacht, die volle Geschwindigkeit des QuadTree zu nutzen, können Sie eine QuadTree-Bibliothek im Internet herunterladen und sie in ein paar Stunden perfekt nutzen. Keine Frage wie: Was stelle ich in die erste Liste, das zweite, das dritte, wie entscheide ich mich, eine Entität in eine andere Liste zu setzen ... und keine Kollision verpasst. Warum ein Fahrrad benutzen, wenn Sie ein Auto haben können?
GameAlchemist
@VincentPiel Ich denke, Sie wollten hier @ Ihren Kommentar an Cypher anstatt an mich richten. Jeder Quad-Baum ist nur eine Art Szenendiagramm, und Sie müssen sich daran erinnern, dass Sie mit X Bildern pro Sekunde arbeiten. Wenn Sie verpasste Kollisionen bemerken, müssen Sie Ihre Reichweitenschwellen anpassen, um die Situation besser auszugleichen. Meine Lösung ist nur ein sehr einfacher Ansatz, bei dem Sie sicherstellen, dass Sie nur alle Elemente überprüfen, bei denen die Gefahr besteht, dass sie kollidieren, und anschließend Hintergrund- / eingeschränkte Aktualisierungen durchführen, um festzustellen, ob sie sich für eine höhere Priorität qualifizieren.
James
6

Sie müssen mit Kollisionen mit einer sortierten Datenstruktur umgehen, damit Sie statt des schrecklichen n ^ 2 n * log (n) -mal haben können. Und n * log (n) ist, wie Sie vielleicht wissen, fast linear. Ein (klassisches) Beispiel ist ein Quadtree. Hier finden Sie ein recht einfaches und gut geschriebenes Tutorial mit Grafiken und Code (Java):

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq: Es ist ziemlich einfach, eine Implementierung für QuadTrees in einer beliebigen Sprache zu finden. Trotzdem müssen Sie über die richtige Granularität für den Baum nachdenken. Je größer der Baum, desto mehr Entitäten passen nicht in einen Knoten.
Rq 2: Da Ihre Raumaufteilung nur für die Kollisionserkennung erfolgt, haben Sie die vollkommene Freiheit, den Raum nach Ihren Wünschen aufzuteilen. Zum Beispiel würde ich mich nicht in vier Teile aufteilen, sondern das Baricenter der Entitäten auf der aktuellen Ebene als Zentrum für die neue Teilung verwenden. 1) Der Algorithmus ist immer noch n * log (n), 2) Sie verlieren die Möglichkeit, die Szene aus dem Baum 'neu aufzubauen' - aber das ist Ihnen egal- und 3) Sie haben einen viel ausgeglicheneren Baum, weniger Overhead .
Rq3: Sobald Sie Ihren Baum haben, gibt Ihnen eine "Kollision" zwischen dem Bildschirm und den Entitäten ... die sichtbaren Entitäten! In einer Zeit wie log (n), warum also nicht, wenn n groß ist? (Der schlimmste Fall ist offensichtlich eine Zeit in n für diesen Ansatz.)

GameAlchemist
quelle
Ja, ein Quad-Baum ist eigentlich nur eine Art Szenendiagramm. Ich gehe einfach immer davon aus, dass die Leute, die hier sind, Dinge selbst schreiben wollen, nicht die Bibliothek eines anderen benutzen. In diesem Fall, warum an einem Quad-Baum anhalten, einfach eine komplette Kollisionsbibliothek finden.
James
0

Binary Space Partition Tree, Quadtree, Octree (für 3D) sind mögliche Bäume, die Sie bei jedem Aktualisierungsaufruf für jedes Objekt, für das eine Kollision gelten soll, generieren (oder pflegen, wenn Sie ehrgeizig sind) können.

kchoi
quelle
3
Das ist passender, um ein Kommentar zu sein. Erwägen Sie, Ihrer Antwort mehr hinzuzufügen.
0

Ich bin ziemlich naiv, wenn es um Quad oder Oct Tree geht. Aber ich denke, dass diese Methode tun sollte:

Sie müssen die Spielerstruktur / -klasse ändern. Füge ein Array / einen Vektor von Zeigern zu einer anderen Spielerstruktur hinzu.

Jeder zweite Check Abstand zwischen jeweils zwei Spielern. Wenn es so niedrig ist, dass es innerhalb von 1 Sekunde erreicht werden kann, füge den Zeiger dieses Spielers zum Kollisionsfeld des aktuellen Spielers hinzu.

Überprüfen Sie jetzt nur die Kollision zwischen den Spielern in der jeweils anderen Liste.

user3042253
quelle