Cyber Monday Sale Save up to 40% off unlimited courses, tutorials and creative assets. Cyber Monday Sale! Save Now
Advertisement
  1. Game Development
  2. Programming

Bringen Sie Ihr Spiel mit Partikeleffekten und Quadtrees zum Platzen

by
Difficulty:IntermediateLength:LongLanguages:

German (Deutsch) translation by Katharina Nevolina (you can also view the original English article)

Sie wollen also Explosionen, Feuer, Kugeln oder Zaubersprüche in deinem Spiel? Partikelsysteme sorgen für einfache grafische Effekte, um Ihr Spiel ein wenig aufzupeppen. Sie können den Spieler noch mehr begeistern, indem Sie Partikel mit Ihrer Welt interagieren lassen und von der Umgebung und anderen Spielern abprallen. In diesem Tutorial werden wir einige einfache Partikeleffekte implementieren und von hier aus die Partikel von der Welt um sie herum abprallen lassen.

Wir werden die Dinge auch optimieren, indem wir eine Datenstruktur implementieren, die als Quadtree bezeichnet wird. Mit Quadtrees können Sie viel schneller als ohne Kollisionen nach Kollisionen suchen. Sie sind einfach zu implementieren und zu verstehen.

Hinweis: Obwohl dieses Tutorial mit HTML5 und JavaScript geschrieben wurde, sollten Sie in fast jeder Spieleentwicklungsumgebung dieselben Techniken und Konzepte verwenden können.

Lesen Sie diesen Artikel in Chrome, Firefox, IE 9 oder einem anderen Browser, der HTML5 und Canvas unterstützt, um die Demos im Artikel anzuzeigen.

Beachten Sie, wie die Partikel beim Fallen ihre Farbe ändern und wie sie von den Formen abprallen.

Was ist ein Partikelsystem?

Ein Partikelsystem ist eine einfache Möglichkeit, Effekte wie Feuer, Rauch und Explosionen zu erzeugen.

Sie erstellen einen Partikelemitter, der kleine "Partikel" startet, die Sie als Pixel, Kästchen oder kleine Bitmaps anzeigen können. Sie folgen der einfachen Newtonschen Physik und ändern ihre Farbe, wenn sie sich bewegen, was zu dynamischen, anpassbaren, grafischen Effekten führt.


Der Start eines Partikelsystems

Unser Partikelsystem wird einige einstellbare Parameter haben:

  • Wie viele Partikel spuckt es pro Sekunde aus?
  • Wie lange kann ein Teilchen "leben"?
  • Die Farben, durch die jedes Partikel geht.
  • Die Position und der Winkel, aus dem die Partikel erscheinen.
  • Wie schnell die Partikel gehen, wenn sie laichen.
  • Wie viel Schwerkraft sollte Partikel beeinflussen.

Wenn jedes Partikel genau das gleiche hervorbringen würde, hätten wir nur einen Partikelstrom, keinen Partikeleffekt. Lassen Sie uns also auch konfigurierbare Variabilität zulassen. Dies gibt uns einige weitere Parameter für unser System:

  • Wie stark kann ihr Startwinkel variieren?
  • Wie stark kann ihre Anfangsgeschwindigkeit variieren?
  • Wie sehr kann ihre Lebensdauer variieren?

Wir erhalten eine Partikelsystemklasse, die wie folgt beginnt:


Das System zum Fließen bringen

In jedem Frame müssen wir drei Dinge tun: neue Partikel erstellen, vorhandene Partikel verschieben und die Partikel zeichnen.

Partikel erstellen

Das Erstellen von Partikeln ist ziemlich einfach. Wenn wir 300 Partikel pro Sekunde erstellen und seit dem letzten Bild 0,05 Sekunden vergangen sind, erstellen wir 15 Partikel für das Bild (durchschnittlich 300 pro Sekunde).

Wir sollten eine einfache Schleife haben, die so aussieht:

Unsere spawnParticle()-Funktion erstellt ein neues Partikel basierend auf den Parametern unseres Systems:

Wir wählen unsere Anfangsgeschwindigkeit aus einem zufälligen Winkel und einer zufälligen Geschwindigkeit. Wir verwenden dann die fromPolar()-Methode, um einen kartesischen Geschwindigkeitsvektor aus der Winkel/Geschwindigkeitskombination zu erstellen.

Die grundlegende Trigonometrie liefert die fromPolar-Methode:

Wenn Sie die Trigonometrie ein wenig auffrischen müssen, wird die gesamte von uns verwendete Trigonometrie aus dem Einheitskreis (Unit Circle) abgeleitet.

Partikelbewegung

Die Bewegung der Teilchen folgt den Newtonschen Grundgesetzen. Alle Partikel haben eine Geschwindigkeit und Position. Unsere Geschwindigkeit wird durch die Schwerkraft beeinflusst und unsere Position ändert sich proportional zur Schwerkraft. Schließlich müssen wir das Leben jedes Partikels im Auge behalten, sonst würden Partikel niemals sterben, wir würden zu viele haben und das System würde zum Stillstand kommen. Alle diese Aktionen erfolgen proportional zur Zeit zwischen den Frames.

Partikel zeichnen

Schließlich müssen wir unsere Partikel zeichnen. Wie Sie dies in Ihrem Spiel implementieren, ist von Plattform zu Plattform sehr unterschiedlich und wie fortgeschritten das Rendering sein soll. Das kann so einfach sein wie das Platzieren eines einzelnen farbigen Pixels oder das Verschieben eines Dreieckspaares für jedes Partikel, das von einem komplexen GPU-Shader gezeichnet wird.

In unserem Fall nutzen wir die Canvas-API, um ein kleines Rechteck für das Partikel zu zeichnen.

Die Farbinterpolation hängt davon ab, ob die von Ihnen verwendete Plattform eine Farbklasse (oder ein Darstellungsformat) bereitstellt, ob sie einen Interpolator für Sie bereitstellt und wie Sie das gesamte Problem angehen möchten. Ich habe eine kleine Farbverlaufsklasse geschrieben, die eine einfache Interpolation zwischen mehreren Farben ermöglicht, und eine kleine Farbklasse, die die Funktionalität zum Interpolieren zwischen zwei beliebigen Farben bietet.


Hier ist unser Partikelsystem in Aktion!

Bouncing Partikel

Wie Sie in der obigen Demo sehen können, haben wir jetzt einige grundlegende Partikeleffekte. Sie haben jedoch keine Interaktion mit der Umgebung. Um diese Effekte zu einem Teil unserer Spielwelt zu machen, werden sie von den Wänden um sie herum abprallen.

Zu Beginn nimmt das Partikelsystem nun einen Collider als Parameter. Es ist die Aufgabe des Colliders, einem Partikel mitzuteilen, ob es gegen irgendetwas gekracht ist. Die step()-Methode eines Partikels sieht nun folgendermaßen aus:

Jedes Mal, wenn sich das Teilchen bewegt, fragen wir den Kollider, ob sein Bewegungspfad über die getIntersection()-Methode "kollidiert" ist. Wenn ja, setzen wir seine Position zurück (so dass es nicht innerhalb dessen liegt, was es schneidet) und spiegeln die Geschwindigkeit wider.

Eine grundlegende "Collider"-Implementierung könnte folgendermaßen aussehen:

Bemerken Sie ein Problem? Jedes Partikel muss collider.getIntersection() aufrufen, und dann muss jeder getIntersection-Aufruf gegen jede "Wand" auf der Welt prüfen. Wenn Sie 300 Partikel (eine geringe Anzahl) und 200 Wände in Ihrer Welt haben (auch nicht unangemessen), führen Sie 60.000 Linienkreuzungstests durch! Dies könnte Ihr Spiel zum Stillstand bringen, insbesondere bei mehr Partikeln (oder komplexeren Welten).


Schnellere Kollisionserkennung mit Quadtrees

Das Problem mit unserem einfachen Collider ist, dass er jede Wand auf jedes Partikel überprüft. Befindet sich unser Partikel im oberen rechten Quadranten des Bildschirms, sollten wir keine Zeit damit verschwenden, zu überprüfen, ob es gegen Wände stößt, die sich nur unten oder links auf dem Bildschirm befinden. Im Idealfall möchten wir also alle Überprüfungen auf Schnittpunkte außerhalb des oberen rechten Quadranten ausschließen:

Particle effects and quadtrees
Wir prüfen nur auf Kollisionen zwischen dem blauen Punkt und den roten Linien.

Das ist nur ein Viertel der Schecks! Gehen wir jetzt noch weiter: Wenn sich das Partikel im oberen linken Quadranten des oberen rechten Quadranten des Bildschirms befindet, sollten wir nur diese Wände im selben Quadranten überprüfen müssen:

Particle effects and quadtrees

Mit Quadtrees können Sie genau das tun! Anstatt gegen alle Wände zu testen, teilen Sie die Wände in die Quadranten und Subquadranten auf, die sie belegen, sodass Sie nur einige Quadranten überprüfen müssen. Sie können problemlos von 200 Schecks pro Partikel auf nur 5 oder 6 wechseln.

Die Schritte zum Erstellen eines Quadtree sind wie folgt:

  1. Beginnen Sie mit einem Rechteck, das den gesamten Bildschirm ausfüllt.
  2. Nehmen Sie das aktuelle Rechteck und zählen Sie, wie viele "Wände" darin fallen.
  3. Wenn Sie mehr als drei Linien haben (Sie können eine andere Zahl wählen), teilen Sie das Rechteck in vier gleiche Quadranten. Wiederholen Sie Schritt 2 mit jedem Quadranten.
  4. Nachdem Sie die Schritte 2 und 3 wiederholt haben, erhalten Sie einen "Baum" von Rechtecken, wobei keines der kleinsten Rechtecke mehr als drei Zeilen enthält (oder was auch immer Sie ausgewählt haben).
Particle effects and quadtrees
Einen Quadtree bauen. Die Zahlen geben die Anzahl der Linien innerhalb des Quadranten an, wobei Rot zu hoch ist und unterteilt werden muss.

Um unseren Quadtree zu erstellen, nehmen wir eine Reihe von "Wänden" (Liniensegmenten) als Parameter. Wenn zu viele in unserem Rechteck enthalten sind, unterteilen wir uns in kleinere Rechtecke, und der Vorgang wird wiederholt.

Sie können die vollständige QuadTree-Klasse hier sehen:

Das Testen auf Schnittpunkte gegen ein Liniensegment wird auf ähnliche Weise durchgeführt. Für jedes Rechteck machen wir Folgendes:

  1. Beginnen Sie mit dem größten Rechteck im Quadtree.
  2. Überprüfen Sie, ob sich das Liniensegment schneidet oder innerhalb des aktuellen Rechtecks befindet. Wenn dies nicht der Fall ist, machen Sie keine weiteren Tests auf diesem Weg.
  3. Wenn das Liniensegment in das aktuelle Rechteck fällt oder es schneidet, prüfen Sie, ob das aktuelle Rechteck untergeordnete Rechtecke enthält. Wenn dies der Fall ist, kehren Sie zu Schritt 2 zurück, verwenden Sie jedoch jedes der untergeordneten Rechtecke.
  4. Wenn das aktuelle Rechteck keine untergeordneten Rechtecke enthält, es sich jedoch um einen Blattknoten handelt (dh nur Liniensegmente als untergeordnete Elemente), testen Sie das Zielliniensegment anhand dieser Liniensegmente. Wenn es sich um eine Kreuzung handelt, geben Sie die Kreuzung zurück. Wir sind fertig!
Particle effects and quadtrees
Suche nach einem Quadtree. Wir beginnen beim größten Rechteck und suchen immer kleinere, bis wir schließlich einzelne Liniensegmente testen. Mit dem Quadtree führen wir nur vier Rechteck- und zwei Linientests durch, anstatt alle 21 Liniensegmente zu testen. Der Unterschied wird nur bei größeren Datenmengen dramatischer.

Sobald wir ein QuadTree-Objekt als "Collider" an unser Partikelsystem übergeben, erhalten wir blitzschnelle Suchvorgänge. Schauen Sie sich die interaktive Demo unten an - verwenden Sie Ihre Maus, um zu sehen, gegen welche Liniensegmente der Quadtree testen müsste!


Bewegen Sie den Mauszeiger über einen (Unter-) Quadranten, um zu sehen, welche Liniensegmente darin enthalten sind.

Stoff zum Nachdenken

Das in diesem Artikel vorgestellte Partikelsystem und der Quadtree sind rudimentäre Lehrsysteme. Einige andere Ideen, die Sie möglicherweise berücksichtigen sollten, wenn Sie diese selbst implementieren:

  • Möglicherweise möchten Sie Objekte neben Liniensegmenten im Quadtree halten. Wie würden Sie es um Kreise erweitern? Quadrate?
  • Möglicherweise möchten Sie einzelne Objekte abrufen (um sie darüber zu informieren, dass sie von einem Partikel getroffen wurden) und gleichzeitig reflektierbare Segmente abrufen.
  • Die physikalischen Gleichungen leiden unter Diskrepanzen, die Euler-Gleichungen im Laufe der Zeit mit instabilen Bildraten aufbauen. Während dies für ein Partikelsystem im Allgemeinen keine Rolle spielt, sollten Sie sich über fortgeschrittenere Bewegungsgleichungen informieren. (Schauen Sie sich zum Beispiel dieses Tutorial an.)
  • Es gibt viele Möglichkeiten, die Liste der Partikel im Speicher zu speichern. Eine Anordnung ist am einfachsten, aber möglicherweise nicht die beste Wahl, da Partikel häufig aus dem System entfernt und häufig neue eingefügt werden. Eine verknüpfte Liste passt möglicherweise besser, weist jedoch eine schlechte Cache-Lokalität auf. Die beste Darstellung für Partikel hängt möglicherweise vom verwendeten Framework oder der verwendeten Sprache ab.










Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.