In dieser Serie von Tutorials zeige ich Ihnen, wie Sie einen Neon-Twin-Shooter wie Geometry Wars in XNA erstellen. Das Ziel dieser Tutorials ist es nicht, Ihnen eine exakte Nachbildung von Geometry Wars zu geben, sondern die notwendigen Elemente durchzugehen, mit denen Sie eine qualitativ hochwertige Variante erstellen können.
In der bisherigen Serie haben wir das Gameplay eingerichtet und Bloom hinzugefügt. Als nächstes fügen wir Partikeleffekte hinzu.
Warnung: Laut!Partikeleffekte werden durch das Herstellen einer großen Anzahl kleiner Partikel erzeugt. Sie sind sehr vielseitig und können verwendet werden, um fast jedem Spiel mehr Flair zu verleihen. In Shape Blaster werden wir mit Partikeleffekten Explosionen machen. Wir werden auch Partikeleffekte verwenden, um ein Auspufffeuer für das Schiff des Spielers zu erzeugen und den Schwarzen Löchern ein optisches Flair zu verleihen. Außerdem werden wir untersuchen, wie Partikel aus den schwarzen Löchern mit der Schwerkraft interagieren können.
ParticleManager
KlasseWir beginnen mit der Erstellung einer ParticleManager
Klasse, die alle Partikel speichert, aktualisiert und zeichnet. Wir machen diese Klasse so allgemein, dass sie problemlos in anderen Projekten verwendet werden kann. Um das zu behalten ParticleManager
Im Allgemeinen ist es nicht dafür verantwortlich, wie die Partikel aussehen oder sich bewegen; Wir werden das anderswo erledigen.
Partikel neigen dazu, schnell und in großer Zahl erzeugt und zerstört zu werden. Wir werden eine verwenden Objektpool um zu vermeiden, dass große Mengen Müll entstehen. Das bedeutet, dass wir eine große Anzahl von Partikeln im Voraus zuweisen und diese Partikel dann wiederverwenden werden. Wir werden auch machen ParticleManager
haben eine feste Kapazität. Dies vereinfacht es und hilft sicherzustellen, dass wir unsere Leistungs- oder Speicherbeschränkungen nicht überschreiten, indem zu viele Partikel erzeugt werden. Wenn die maximale Anzahl an Partikeln überschritten wird, werden wir die ältesten durch neue ersetzen.
Wir machen das ParticleManager
eine generische Klasse. Dies ermöglicht es uns, benutzerdefinierte Zustandsinformationen für die Partikel zu speichern, ohne sie fest in die Partikel einzugeben ParticleManager
selbst. Wir erstellen auch ein verschachteltes Partikel
Klasse.
öffentliche Klasse ParticleManagerpublic class Partikel public Texture2D Texture; öffentliche Vector2-Position; public float Orientierung; öffentliche Vector2-Skala = Vector2.One; öffentliche Farbe Farbe; öffentlicher Float Dauer; public float PercentLife = 1f; öffentlicher T-Staat;
Das Partikel
Die Klasse verfügt über alle Informationen, die zur Anzeige eines Partikels und zum Verwalten seiner Lebensdauer erforderlich sind. Der generische Parameter, T Zustand
, Gibt es zusätzliche Daten, die wir für unsere Partikel benötigen? Welche Daten benötigt werden, hängt von den gewünschten Partikeleffekten ab. Es kann verwendet werden, um Geschwindigkeit, Beschleunigung, Rotationsgeschwindigkeit oder anderes zu speichern.
Um die Partikel besser verwalten zu können, benötigen wir eine Klasse, die als kreisförmige Anordnung, Das bedeutet, dass Indizes, die normalerweise außerhalb des zulässigen Bereichs liegen, sich am Anfang des Arrays befinden. Dies macht es leicht, die ältesten Partikel zuerst zu ersetzen, wenn der Platz für neue Partikel in unserem Array zur Neige geht. Wir fügen Folgendes als verschachtelte Klasse in hinzu ParticleManager
.
private Klasse CircularParticleArray private int start; public int Start get Rückkehr zurück; set start = value% list.Length; public int Count get; einstellen; public int Capacity get return list.Length; private Particle [] Liste; public CircularParticleArray (int capacity) list = new Particle [Kapazität]; public Particle this [int i] get return list [(start + i)% list.Length]; set list [(start + i)% list.Length] = value;
Wir können das einstellen Start
Eigenschaft, wo der Index Null in unserem CircularParticleArray
entspricht dem zugrunde liegenden Array und Anzahl
wird verwendet, um zu ermitteln, wie viele aktive Partikel in der Liste enthalten sind. Wir sorgen dafür, dass das Teilchen am Index Null immer das älteste Teilchen ist. Wenn wir das älteste Teilchen durch ein neues ersetzen, erhöhen wir es einfach Start
, was im Wesentlichen die kreisförmige Anordnung dreht.
Nun, da wir unsere Helfer-Klassen haben, können wir damit beginnen, die ParticleManager
Klasse. Wir benötigen einige Member-Variablen und einen Konstruktor.
// Dieser Delegat wird für jedes Partikel aufgerufen. private AktionupdateParticle; private CircularParticleArray-Partikelliste; Öffentlicher ParticleManager (int Capacity, Aktion updateParticle) this.updateParticle = updateParticle; ParticleList = new CircularParticleArray (Kapazität); // Füllen Sie die Liste mit leeren Partikelobjekten zur Wiederverwendung auf. für (int i = 0; i < capacity; i++) particleList[i] = new Particle();
Die erste deklarierte Variable, updateParticle
, wird eine benutzerdefinierte Methode sein, die die Partikel entsprechend dem gewünschten Effekt aktualisiert. Ein Spiel kann mehrere haben ParticleManagers
das Update ggf. anders. Wir erstellen auch eine CircularParticleList
und füllen Sie es mit leeren Partikeln. Der Konstruktor ist der einzige Ort der ParticleManager
weist Speicher zu.
Als nächstes fügen wir die CreateParticle ()
Diese Methode erstellt ein neues Partikel, indem das nächste nicht verwendete Partikel im Pool verwendet wird, oder das älteste Partikel, wenn keine nicht verwendeten Partikel vorhanden sind.
public void CreateParticle (Textur2D-Textur, Vector2-Position, Farbton, Float-Dauer, Vector2-Skala, T-Zustand, Float-Theta = 0) Particle Particle; if (ParticleList.Count == ParticleList.Capacity) // Wenn die Liste voll ist, überschreiben Sie das älteste Partikel und drehen Sie die zirkuläre Liste. Particle = ParticleList [0]; ParticleList.Start ++; else Partikel = Partikelliste [Partikelliste.Zahl]; ParticleList.Count ++; // Erstellen Sie das Teilchenpartikel.Texture = Textur; partikel.position = position; Partikel.Tint = Farbton; partikel.Dauer = dauer; Particle.PercentLife = 1f; Particle.Scale = Skala; Partikel.Orientation = Theta; Partikel.Zustand = Zustand;
Partikel können jederzeit zerstört werden. Wir müssen diese Partikel entfernen und dabei sicherstellen, dass die anderen Partikel in derselben Reihenfolge bleiben. Wir können dies tun, indem wir die Liste der Partikel durchlaufen und dabei nachverfolgen, wie viele davon zerstört wurden. Auf dem Weg bewegen wir jedes aktive Teilchen vor den zerstörten Teilchen, indem wir es mit dem ersten zerstörten Teilchen tauschen. Sobald alle zerstörten Partikel am Ende der Liste sind, deaktivieren wir sie, indem Sie die Liste setzen Anzahl
variabel auf die Anzahl der aktiven Teilchen. Zerstörte Partikel verbleiben im darunter liegenden Array, werden jedoch nicht aktualisiert oder gezeichnet.
ParticleManager.Update ()
übernimmt die Aktualisierung aller Partikel und das Entfernen der zerstörten Partikel aus der Liste.
public void Update () int removeCount = 0; für (int i = 0; i < particleList.Count; i++) var particle = particleList[i]; updateParticle(particle); particle.PercentLife -= 1f / particle.Duration; // sift deleted particles to the end of the list Swap(particleList, i - removalCount, i); // if the particle has expired, delete this particle if (particle.PercentLife < 0) removalCount++; particleList.Count -= removalCount; private static void Swap(CircularParticleArray list, int index1, int index2) var temp = list[index1]; list[index1] = list[index2]; list[index2] = temp;
Die letzte Sache, die in implementiert werden soll ParticleManager
zieht die Partikel.
public void Draw (SpriteBatch SpriteBatch) für (int i = 0; i < particleList.Count; i++) var particle = particleList[i]; Vector2 origin = new Vector2(particle.Texture.Width / 2, particle.Texture.Height / 2); spriteBatch.Draw(particle.Texture, particle.Position, null, particle.Color, particle.Orientation, origin, particle.Scale, 0, 0);
ParticleState
StrukturAls Nächstes erstellen Sie eine benutzerdefinierte Klasse oder Struktur, um das Aussehen der Partikel in Shape Blaster anzupassen. Es gibt verschiedene Arten von Partikeln in Shape Blaster, die sich ein wenig anders verhalten, also erstellen wir zunächst eine enum
für den Partikeltyp. Wir benötigen auch Variablen für die Geschwindigkeit und die Anfangslänge des Partikels.
public enum ParticleType Keine, Feind, Aufzählungszeichen, IgnoreGravity public struct ParticleState public Vector2 Velocity; public ParticleType Type; public float LengthMultiplier;
Jetzt können wir die Aktualisierungsmethode des Teilchens schreiben. Es ist eine gute Idee, diese Methode schnell zu machen, da sie möglicherweise für eine große Anzahl von Partikeln aufgerufen werden muss.
Wir fangen einfach an. Fügen Sie die folgende Methode zu hinzu ParticleState
.
public static void UpdateParticle (ParticleManager.Particle Partikel) var vel = Partikel.State.Velocity; Partikel.Position + = vel; partikel.Orientation = vel.ToAngle (); // denormalisierte Floats verursachen erhebliche Leistungsprobleme, wenn (Math.Abs (vel.X) + Math.Abs (Vel.Y) < 0.00000000001f) vel = Vector2.Zero; vel *= 0.97f; // particles gradually slow down x.State.Velocity = vel;
Wir werden in Kürze zurückkommen und diese Methode verbessern. Lassen Sie uns zunächst einige Partikeleffekte erstellen, um unsere Änderungen tatsächlich testen zu können. Im GameRoot
, ein neues deklarieren ParticleManager
und nenne es Aktualisieren()
und Zeichnen()
Methoden.
// in GameRoot public static ParticleManager ParticleManager get; privates Set; // in GameRoot.Initialize () ParticleManager = new ParticleManager (1024 * 20, ParticleState.UpdateParticle); // in GameRoot.Update () ParticleManager.Update (); // in GameRoot.Draw () spriteBatch.Begin (SpriteSortMode.Deferred, BlendState.Additive); ParticleManager.Draw (); spriteBatch.End ();
Deklarieren Sie auch ein neues Textur2D
namens LineParticle
für die Textur des Teilchens im Kunst
klasse und lade die Textur wie wir es für die anderen Sprites getan haben.
Lassen Sie uns Feinde explodieren lassen. Modifiziere den Feind.WasShot ()
Methode wie folgt.
public void WasShot () IsExpired = true; für (int i = 0; i < 120; i++) float speed = 18f * (1f - 1 / rand.NextFloat(1f, 10f)); var state = new ParticleState() Velocity = rand.NextVector2(speed, speed), Type = ParticleType.Enemy, LengthMultiplier = 1f ; GameRoot.ParticleManager.CreateParticle(Art.LineParticle, Position, Color.LightGreen, 190, 1.5f, state);
Dadurch entstehen 120 Partikel, die mit unterschiedlichen Geschwindigkeiten in alle Richtungen nach außen schießen. Die Zufallsgeschwindigkeit wird so gewichtet, dass sich die Partikel wahrscheinlicher in der Nähe der Höchstgeschwindigkeit bewegen. Dadurch werden sich mehr Partikel am Rand der Explosion befinden, wenn sie sich ausdehnt. Die Partikel halten 190 Frames oder etwas mehr als drei Sekunden.
Sie können jetzt das Spiel ausführen und zusehen, wie Gegner explodieren. Bei den Partikeleffekten müssen jedoch noch einige Verbesserungen vorgenommen werden.
Das erste Problem ist, dass die Partikel abrupt verschwinden, wenn ihre Dauer abgelaufen ist. Es wäre schöner, wenn sie problemlos ausgeblendet werden könnten. Aber gehen wir noch ein bisschen weiter und lassen die Partikel heller leuchten, wenn sie sich schnell bewegen. Es sieht auch gut aus, wenn wir schnell bewegte Teilchen verlängern und langsam bewegende Teilchen verkürzen.
Modifiziere den ParticleState.UpdateParticle ()
Methode wie folgt (Änderungen werden hervorgehoben).
public static void UpdateParticle (ParticleManager.Particle Partikel) var vel = Partikel.State.Velocity; Partikel.Position + = vel; partikel.Orientation = vel.ToAngle (); Schwimmgeschwindigkeit = vel.Length (); Float Alpha = Math.Min (1, Math.Min (Partikel.PercentLife * 2, Geschwindigkeit * 1f)); alpha * = alpha; Partikel.Farbe.A = (Byte) (255 * alpha); Particle.Scale.X = Partikel.State.LengthMultiplier * Math.Min (Math.Min (1f, 0.2f * Geschwindigkeit + 0.1f), alpha); if (Math.Abs (vel.X) + Math.Abs (vel.Y) < 0.00000000001f) // denormalized floats cause significant performance issues vel = Vector2.Zero; vel *= 0.97f; // particles gradually slow down x.State.Velocity = vel;
Die Explosionen sehen jetzt viel besser aus, aber sie haben alle dieselbe Farbe. Wir können ihnen mehr Auswahl geben, indem Sie zufällige Farben wählen. Eine Möglichkeit, zufällige Farben zu erzeugen, ist die zufällige Auswahl der roten, blauen und grünen Komponenten. Dies führt jedoch zu vielen stumpfen Farben, und wir möchten, dass unsere Partikel ein Neonlicht-Erscheinungsbild haben. Wir können mehr Kontrolle über unsere Farben haben, indem wir sie im HSV-Farbraum angeben. HSV steht für Farbton, Sättigung und Wert. Wir möchten Farben mit einem zufälligen Farbton auswählen, aber mit einer festen Sättigung und einem festen Wert. Wir brauchen eine Hilfsfunktion, die aus HSV-Werten eine Farbe erzeugen kann.
statische Klasse ColorUtil public static Color HSVToColor (float h, float s, float v) if (h == 0 && s == 0) liefert eine neue Farbe (v, v, v); float c = s * v; Float x = c * (1 - Math.Abs (h% 2 - 1)); Float m = v - c; wenn (h < 1) return new Color(c + m, x + m, m); else if (h < 2) return new Color(x + m, c + m, m); else if (h < 3) return new Color(m, c + m, x + m); else if (h < 4) return new Color(m, x + m, c + m); else if (h < 5) return new Color(x + m, m, c + m); else return new Color(c + m, m, x + m);
Jetzt können wir modifizieren Feind.WasShot ()
zufällige Farben verwenden. Um die Explosionsfarbe weniger eintönig zu machen, wählen wir zwei nahegelegene Schlüsselfarben für jede Explosion aus und interpolieren sie linear um einen zufälligen Betrag für jedes Teilchen.
public void WasShot () IsExpired = true; float hue1 = rand.NextFloat (0, 6); float hue2 = (hue1 + rand.NextFloat (0, 2))% 6f; Color color1 = ColorUtil.HSVToColor (Farbton1, 0,5f, 1); Color color2 = ColorUtil.HSVToColor (Farbton2, 0,5f, 1); für (int i = 0; i < 120; i++) float speed = 18f * (1f - 1 / rand.NextFloat(1f, 10f)); var state = new ParticleState() Velocity = rand.NextVector2(speed, speed), Type = ParticleType.Enemy, LengthMultiplier = 1 ; Color color = Color.Lerp(color1, color2, rand.NextFloat(0, 1)); GameRoot.ParticleManager.CreateParticle(Art.LineParticle, Position, color, 190, 1.5f, state);
Die Explosionen sollten wie die Animation unten aussehen.
Sie können mit der Farbgenerierung nach Ihren Wünschen herumspielen. Eine alternative Technik, die gut funktioniert, besteht darin, eine Anzahl von Farbmustern für Explosionen von Hand auszuwählen und nach dem Zufallsprinzip aus Ihren vorgewählten Farbschemata auszuwählen.
Wir können die Kugeln auch explodieren lassen, wenn sie den Bildschirmrand erreichen. Wir werden im Wesentlichen dasselbe tun, wie wir es für feindliche Explosionen gemacht haben.
Statik hinzufügen Zufällig
Mitglied der Kugel
Klasse.
privater statischer Zufall rand = new Random ();
Dann ändern Bullet.Update ()
wie folgt.
// Löschen von Aufzählungszeichen, die außerhalb des Bildschirms erscheinen if (! GameRoot.Viewport.Bounds.Contains (Position.ToPoint ())) IsExpired = true; für (int i = 0; i < 30; i++) GameRoot.ParticleManager.CreateParticle(Art.LineParticle, Position, Color.LightBlue, 50, 1, new ParticleState() Velocity = rand.NextVector2(0, 9), Type = ParticleType.Bullet, LengthMultiplier = 1 );
Sie stellen möglicherweise fest, dass das Verschieben der Partikel in eine zufällige Richtung verschwenderisch ist, da mindestens die Hälfte der Partikel sofort vom Bildschirm abspringt (mehr, wenn die Kugel in einer Ecke explodiert). Wir könnten zusätzliche Arbeit verrichten, um sicherzustellen, dass den Partikeln nur Geschwindigkeiten gegeben werden, die der Wand gegenüberliegen. Stattdessen nehmen wir ein Stichwort von Geometry Wars und lassen alle Partikel von den Wänden springen. Alle Partikel, die vom Bildschirm abgehen, werden zurückgeworfen.
Fügen Sie folgende Zeilen hinzu ParticleState.UpdateParticle ()
irgendwo zwischen der ersten und letzten Zeile.
var pos = x.Position; int width = (int) GameRoot.ScreenSize.X; int height = (int) GameRoot.ScreenSize.Y; // mit den Rändern des Bildschirms kollidieren, wenn (pos.X < 0) vel.X = Math.Abs(vel.X); else if (pos.X > width) vel.X = -Math.Abs (vel.X); wenn (pos.Y < 0) vel.Y = Math.Abs(vel.Y); else if (pos.Y > Höhe) vel.Y = -Math.Abs (vel.Y);
Wir werden eine große Explosion machen, wenn der Spieler getötet wird. Ändern PlayerShip.Kill ()
wie so:
public void Kill () framesUntilRespawn = 60; Farbe gelb = neue Farbe (0,8f, 0,8f, 0,4f); für (int i = 0; i < 1200; i++) float speed = 18f * (1f - 1 / rand.NextFloat(1f, 10f)); Color color = Color.Lerp(Color.White, yellow, rand.NextFloat(0, 1)); var state = new ParticleState() Velocity = rand.NextVector2(speed, speed), Type = ParticleType.None, LengthMultiplier = 1 ; GameRoot.ParticleManager.CreateParticle(Art.LineParticle, Position, color, 190, 1.5f, state);
Dies ist ähnlich wie bei den feindlichen Explosionen, aber wir verwenden mehr Partikel und verwenden immer das gleiche Farbschema. Der Partikeltyp ist ebenfalls auf eingestellt ParticleType.None
.
In der Demo verlangsamen sich Partikel aus feindlichen Explosionen schneller als Partikel aus dem Schiff des Spielers, das explodiert. Dadurch dauert die Explosion des Spielers etwas länger und wirkt etwas epischer.
Jetzt, da wir Partikeleffekte haben, lassen Sie uns die Schwarzen Löcher noch einmal besuchen und sie mit Partikeln interagieren lassen.
Schwarze Löcher sollten Partikel zusätzlich zu anderen Entitäten beeinflussen, daher müssen wir sie ändern ParticleState.UpdateParticle ()
. Fügen Sie die folgenden Zeilen hinzu.
if (x.State.Type! = ParticleType.IgnoreGravity) foreach (var blackHole in EntityManager.BlackHoles) var dPos = blackHole.Position - pos; Floatdistanz = dPos.Length (); var n = dPos / Abstand; vel + = 10000 * n / (Abstand * Abstand + 10000); // füge tangentiale Beschleunigung für in der Nähe befindliche Partikel hinzu (Abstand < 400) vel += 45 * new Vector2(n.Y, -n.X) / (distance + 100);
Hier, n
ist der Einheitsvektor, der auf das Schwarze Loch zeigt. Die Anziehungskraft ist eine modifizierte Version der inversen Quadratfunktion. Die erste Modifikation ist, dass der Nenner \ (Abstand ^ 2 + 10.000 \) ist. Dies führt dazu, dass sich die Anziehungskraft einem maximalen Wert nähert, anstatt sich gegen unendlich zu neigen, da der Abstand sehr klein wird. Wenn der Abstand viel größer als 100 Pixel ist, wird \ (Abstand ^ 2 \) viel größer als 10.000. Das Hinzufügen von 10.000 zu \ (Abstand ^ 2 \) hat daher einen sehr geringen Effekt und die Funktion nähert sich einer normalen inversen Quadratfunktion an. Wenn der Abstand jedoch viel kleiner als 100 Pixel ist, hat der Abstand einen geringen Einfluss auf den Wert des Nenners, und die Gleichung wird ungefähr gleich:
vel + = n;
Die zweite Modifikation besteht darin, der Geschwindigkeit eine Seitenkomponente hinzuzufügen, wenn sich die Partikel dem Schwarzen Loch nahe genug nähern. Dies dient zwei Zwecken. Zunächst werden die Partikel im Uhrzeigersinn in Richtung des schwarzen Lochs spiralförmig. Zweitens erreichen die Teilchen, wenn sie nahe genug sind, das Gleichgewicht und bilden einen leuchtenden Kreis um das Schwarze Loch.
Spitze: Um einen Vektor um 90 ° im Uhrzeigersinn zu drehen, nehmen Sie(V. Y, -V.X)
. Um 90 ° gegen den Uhrzeigersinn zu drehen, nehmen Sie ebenfalls (-V.Y, V.X)
. Schwarze Löcher erzeugen zwei Arten von Partikeln. Erstens sprühen sie regelmäßig Partikel aus, die sich um sie herum bewegen. Zweitens, wenn ein schwarzes Loch geschossen wird, werden spezielle Partikel gesprüht, die nicht von der Schwerkraft beeinflusst werden.
Fügen Sie dem folgenden Code hinzu BlackHole.WasShot ()
Methode.
float hue = (float) ((3 * GameRoot.GameTime.TotalGameTime.TotalSeconds)% 6); Farbfarbe = ColorUtil.HSVToColor (Farbton, 0,25f, 1); const int numParticles = 150; float startOffset = rand.NextFloat (0, MathHelper.TwoPi / numParticles); für (int i = 0; i < numParticles; i++) Vector2 sprayVel = MathUtil.FromPolar(MathHelper.TwoPi * i / numParticles + startOffset, rand.NextFloat(8, 16)); Vector2 pos = Position + 2f * sprayVel; var state = new ParticleState() Velocity = sprayVel, LengthMultiplier = 1, Type = ParticleType.IgnoreGravity ; GameRoot.ParticleManager.CreateParticle(Art.LineParticle, pos, color, 90, 1.5f, state);
Dies funktioniert meistens genauso wie bei den anderen Partikelexplosionen. Ein Unterschied besteht darin, dass wir den Farbton der Farbe basierend auf der gesamten verstrichenen Spielzeit auswählen. Wenn Sie das Schwarze Loch mehrmals in schneller Folge abschießen, wird der Farbton der Explosionen allmählich rotieren. Dies sieht weniger unordentlich aus als die Verwendung von zufälligen Farben und lässt dennoch Variationen zu.
Für das umlaufende Partikelspray müssen wir eine Variable hinzufügen Schwarzes Loch
Klasse, um die Richtung zu verfolgen, in die wir derzeit Partikel sprühen.
privater Schwimmer sprayAngle = 0;
Fügen Sie nun Folgendes zu dem hinzu BlackHole.Update ()
Methode.
// Die schwarzen Löcher sprühen umlaufende Partikel. Das Spray schaltet sich jede Viertelsekunde ein und aus. if ((GameRoot.GameTime.TotalGameTime.Milliseconds / 250)% 2 == 0) Vector2 sprayVel = MathUtil.FromPolar (sprayAngle, rand.NextFloat (12, 15)); Farbfarbe = ColorUtil.HSVToColor (5, 0.5f, 0.8f); // hellviolett Vector2 pos = Position + 2f * neuer Vector2 (sprayVel.Y, -sprayVel.X) + rand.NextVector2 (4, 8); var state = new ParticleState () Velocity = sprayVel, LengthMultiplier = 1, Type = ParticleType.Enemy; GameRoot.ParticleManager.CreateParticle (Art.LineParticle, pos, color, 190, 1.5f, state); // Sprührichtung drehen sprayAngle - = MathHelper.TwoPi / 50f;
Dies bewirkt, dass die schwarzen Löcher violette Partikel sprühen, die einen kühlen, glühenden Ring bilden, der sich wie folgt um das Schwarze Loch kreist:
Wie von den Gesetzen der geometrischen Neonphysik vorgegeben, treibt das Schiff des Spielers sich selbst an, indem es einen Strom feuriger Teilchen aus seinem Auspuff rauswirft. Mit unserer Particle Engine ist dieser Effekt einfach zu erstellen und verleiht der Schiffsbewegung ein optisches Flair.
Während sich das Schiff bewegt, erzeugen wir drei Teilchenströme: einen Mittelstrom, der direkt aus dem Schiff herausschießt, und zwei Seitenströme, deren Winkel relativ zum Schiff hin und her schwenken. Die beiden Seitenströme schwenken in entgegengesetzte Richtungen, um ein Kreuzmuster zu bilden. Die Seitenströme haben eine rötere Farbe, während der mittlere Strom eine heißere gelb-weiße Farbe hat. Die Animation unten zeigt den Effekt.
Damit das Feuer heller leuchtet, als wenn es alleine blühen würde, wird das Schiff zusätzliche Partikel aussenden, die folgendermaßen aussehen:
Diese Partikel werden gefärbt und mit den regulären Partikeln gemischt. Der Code für den gesamten Effekt wird unten gezeigt.
private void MakeExhaustFire () if (Velocity.LengthSquared ()> 0.1f) // einige Variablen einrichten Orientation = Velocity.ToAngle (); Quaternion rot = Quaternion.CreateFromYawPitchRoll (0f, 0f, Orientierung); double t = GameRoot.GameTime.TotalGameTime.TotalSeconds; // Die Primärgeschwindigkeit der Partikel beträgt 3 Pixel / Bild in der Richtung, in die das Schiff fährt. Vector2 baseVel = Velocity.ScaleTo (-3); // Berechne die Seitengeschwindigkeit für die beiden Seitenströme. Die Richtung ist senkrecht zur Schiffsgeschwindigkeit und die Größe variiert sinusförmig. Vector2 perpVel = new Vector2 (baseVel.Y, -baseVel.X) * (0,6f * (Float) Math.Sin (t * 10)); Color sideColor = neue Farbe (200, 38, 9); // tiefrote Farbe midColor = neue Farbe (255, 187, 30); // orange-gelbes Vector2 pos = Position + Vector2.Transform (neuer Vector2 (-25, 0), rot); // Position des Auspuffrohrs des Schiffes. const float alpha = 0.7f; // mittlerer Teilchenstrom Vector2 velMid = baseVel + rand.NextVector2 (0, 1); GameRoot.ParticleManager.CreateParticle (Art.LineParticle, pos, Color.White * alpha, 60f, neuer Vector2 (0.5f, 1), neuer ParticleState (velMid, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.Glow, pos, midColor * alpha, 60f, neuer Vector2 (0.5f, 1), neuer ParticleState (velMid, ParticleType.Enemy)); // seitliche Partikelströme Vector2 vel1 = baseVel + perpVel + rand.NextVector2 (0, 0.3f); Vector2 vel2 = baseVel - perpVel + rand.NextVector2 (0, 0.3f); GameRoot.ParticleManager.CreateParticle (Art.LineParticle, pos, Color.White * alpha, 60f, neuer Vector2 (0.5f, 1), neuer ParticleState (vel1, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.LineParticle, pos, Color.White * alpha, 60f, neuer Vector2 (0.5f, 1), neuer ParticleState (vel2, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.Glow, pos, sideColor * alpha, 60f, neuer Vector2 (0.5f, 1), neuer ParticleState (vel1, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.Glow, pos, sideColor * alpha, 60f, neuer Vector2 (0.5f, 1), neuer ParticleState (vel2, ParticleType.Enemy));
In diesem Code läuft nichts Schleichendes. Wir verwenden eine Sinusfunktion, um den Schwenkeffekt in den Seitenströmen zu erzeugen, indem sie ihre Seitengeschwindigkeit über die Zeit variieren. Für jeden Stream erstellen wir zwei überlappende Partikel pro Frame: ein semitransparent-white LineParticle
und ein farbiges Glimmpartikel dahinter. Anruf MakeExhaustFire ()
am Ende von PlayerShip.Update ()
, unmittelbar vor dem Setzen der Schiffsgeschwindigkeit auf Null.
Mit all diesen Partikeleffekten sieht Shape Blaster ziemlich cool aus. Im letzten Teil dieser Serie werden wir einen weiteren Effekt hinzufügen: das Warping-Hintergrundraster.