Wir haben das Gameplay, das Audio und die Benutzeroberfläche für unser von jMonkeyEngine angetriebenes, von Geometry Wars inspiriertes Spiel programmiert, und jetzt können wir uns mit ein paar hübschen Grafikeffekten und Politur beschäftigen. In diesem Teil konzentrieren wir uns speziell auf Partikeleffekte (einschließlich einiger sehr farbenfroher Explosionen)..
Wir arbeiten in der gesamten Serie daran:
… Und hier ist ein Video, das die Partikeleffekte zeigt, die wir in diesem Teil hinzufügen:
Es wird verschiedene Arten von Partikeln sowie verschiedene Emitter geben:
Neben dem letzten Partikeltyp werden alle Partikel von der Schwerkraft beeinflusst und in schwarze Löcher gesaugt. Wenn also ein schwarzes Loch viele Partikel gleichzeitig ansaugt, beginnt es wegen all der Partikel zu leuchten - was ziemlich cool aussieht.
Ein weiterer Effekt, den wir hinzufügen, besteht darin, unsere Partikel größer und daher heller zu machen, je schneller sie sind. Dies bedeutet, dass eine Explosion auf den ersten Blick sehr hell und glänzend aussieht, jedoch schnell ihre Helligkeit verliert, wenn die Partikel langsamer werden.
Um unsere Ziele zu erreichen, müssen wir zwei neue Klassen hinzufügen:
ParticleManager
Diese Manager-Klasse kümmert sich um die Attribute für jede Art von Explosion.ParticleControl
: Ich denke, man kann schon ahnen, dass diese Klasse das Verhalten unserer Teilchen noch einmal kontrolliert.Beginnen wir mit dem bemerkenswertesten Effekt: Explodieren von Feinden.
Die erste Klasse, die wir implementieren müssen, ist die ParticleManager
Klasse. Da es für das Laichen von Partikeln verantwortlich ist, benötigt es einige Variablen, wie z guiNode
, das ParticleNode
und das standardParticle
.
Wir klonen das, wann immer wir es brauchen, aber schauen Sie sich den grundlegenden Code an:
öffentliche Klasse ParticleManager privater Knoten guiNode; private Räumliche NormPartikel, GlühenPartikel; privater KnotenpartikelNode; private Random Rand; public ParticleManager (Node guiNode, Spatial StandardParticle, Spatial GlowParticle) this.guiNode = guiNode; this.standardParticle = standardParticle; this.glowParticle = glowParticle; ParticleNode = neuer Knoten ("Partikel"); guiNode.attachChild (particleNode); rand = new Random ();
Einbindung des Managers in MonkeyBlasterMain
ist keine große Sache. Wir deklarieren es einfach am Anfang und rufen den Konstruktor in auf simpleInitApp ()
:
ParticleManager = neuer ParticleManager (guiNode, getSpatial ("Laser"), getSpatial ("Glow"));
Um einen Feind tatsächlich zum Explodieren zu bringen, müssen wir die richtige Methode haben, um dies zu tun ParticleManager
:
public void enemyExplosion (Position Vector3f) // init-Farben float hue1 = rand.nextFloat () * 6; float hue2 = (rand.nextFloat () * 2)% 6f; ColorRGBA color1 = hsvToColor (Farbton1, 0,5f, 1f); ColorRGBA color2 = hsvToColor (Farbton2, 0,5f, 1f); // Erzeuge 120 Partikel für (int i = 0; i<120; i++) Vector3f velocity = getRandomVelocity(250); Spatial particle = standardParticle.clone(); particle.setLocalTranslation(position); ColorRGBA color = new ColorRGBA(); color.interpolate(color1, color2, rand.nextFloat()*0.5f); particle.addControl(new ParticleControl(velocity,true,3100,color)); particleNode.attachChild(particle);
Diese Methode ist kurz, macht aber eine Menge, also gehen wir sie Schritt für Schritt durch.
Um unsere Partikel interessanter zu gestalten, weisen wir ihnen zufällige Farben zu.
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" -Auftritt haben.
Wir können mehr Kontrolle über unsere Farben erhalten, indem wir sie in der Farbe angeben HSV (Farbton, Sättigung und Wert) Farbraum. Wir möchten Farben mit einem zufälligen Farbton, aber mit fester Sättigung und festem Wert auswählen, damit alle hell und glänzend aussehen. Daher benötigen wir eine Hilfsfunktion, die aus den HSV-Werten eine Farbe erzeugt.
public ColorRGBA hsvToColor (float h, float s, float v) if (h == 0 && s == 0) return new ColorRGBA (v, v, v, 1); float c = s * v; Float x = c * (1 - Math.abs (h% 2 - 1)); Float m = v - c; wenn (h < 1) return new ColorRGBA(c + m, x + m, m, 1); else if (h < 2) return new ColorRGBA(x + m, c + m, m, 1); else if (h < 3) return new ColorRGBA(m, c + m, x + m, 1); else if (h < 4) return new ColorRGBA(m, x + m, c + m, 1); else if (h < 5) return new ColorRGBA(x + m, m, c + m, 1); else return new ColorRGBA(c + m, m, x + m, 1);
Spitze: Machen Sie sich nicht zu viele Sorgen Wie diese Funktion funktioniert; Verstehen Sie einfach, dass es eine RGBA-Farbe aus dem HSV-Wert erzeugen kann. Die Methode geht über den Umfang und den Fokus dieses Tutorials hinaus.
Nun zurück zu unserer Explosionsmethode. Schauen Sie sich die hervorgehobenen Linien an:
public void enemyExplosion (Position Vector3f) // init-Farben float hue1 = rand.nextFloat () * 6; float hue2 = (rand.nextFloat () * 2)% 6f; ColorRGBA color1 = hsvToColor (Farbton1, 0,5f, 1f); ColorRGBA color2 = hsvToColor (Farbton2, 0,5f, 1f); // Erzeuge 120 Partikel für (int i = 0; i<120; i++) Vector3f velocity = getRandomVelocity(250); Spatial particle = standardParticle.clone(); particle.setLocalTranslation(position); ColorRGBA color = new ColorRGBA(); color.interpolate(color1, color2, rand.nextFloat()*0.5f); particle.addControl(new ParticleControl(velocity,true,3100,color)); particleNode.attachChild(particle);
Um die Explosion farbiger zu gestalten, berechnen wir zwei zufällige Farben und interpolieren die endgültige Partikelfarbe für jedes Partikel zufällig.
Als nächstes berechnen wir die Geschwindigkeit für jedes Teilchen. Wir behandeln das in einer zusätzlichen Methode, weil die Richtung willkürlich sein soll, aber nicht die Geschwindigkeit:
private Vector3f getRandomVelocity (float max) // Vector3f mit zufälliger Richtung erzeugen Vector3f Velocity = new Vector3f (rand.nextFloat () - 0.5f, rand.nextFloat () - 0.5f, 0) .normalizeLocal (); // wende halb-zufällige Partikelgeschwindigkeit an Float random = rand.nextFloat () * 5 + 1; Schwebeteilchengeschwindigkeit = max * (1f - 0,6f / zufällig); Velocity.MultLocal (ParticleSpeed); Rücklaufgeschwindigkeit;
Zuerst erzeugen wir einen zufälligen Geschwindigkeitsvektor und normieren ihn. Als Nächstes berechnen wir eine Zufallsgeschwindigkeit im Bereich zwischen 40% und 90% von max
.
Nun zurück zum enemyExplosion ()
Methode. Hier ist der Teil, über den wir noch nicht gesprochen haben:
Raumpartikel = standardParticle.clone (); Particle.setLocalTranslation (Position); ColorRGBA-Farbe = neue ColorRGBA (); color.interpolate (color1, color2, rand.nextFloat () * 0.5f); Particle.addControl (neue ParticleControl (Geschwindigkeit, 3100, Farbe)); ParticleNode.attachChild (Particle);
Wir klonen das standardParticle
und setzt seine Übersetzung auf den Ursprung der Explosion. Danach interpolieren wir die Partikelfarbe zwischen den beiden zufälligen (wie oben erwähnt). Wie Sie sehen, fügen wir auch eine ParticleControl
das wird das Verhalten des Teilchens steuern. Schließlich müssen wir das Partikel dem Knoten hinzufügen, damit es angezeigt wird.
Nun das unser ParticleManager
fertig ist, müssen wir das implementieren ParticleControl
. Teile des Codes werden Ihnen bekannt vorkommen:
public class ParticleControl erweitert AbstractControl private Vector3f Velocity; Lebensdauer des privaten Schwimmers; private long spawnTime; private ColorRGBA-Farbe; public ParticleControl (Vector3f Geschwindigkeit, Floatlebensdauer, ColorRGBA-Farbe) this.velocity = Geschwindigkeit; this.lifespan = Lebensdauer; this.color = Farbe; spawnTime = System.currentTimeMillis (); @Override protected void controlUpdate (Float-Tpf) // Bewegung von Raumbewegungen (Velocity.Mult (Tpf * 3f)); Velocity.MultLocal (1-3f * tpf); if (Math.abs (Geschwindigkeit.x) + Math.abs (Geschwindigkeit.y) < 0.001f) velocity = Vector3f.ZERO; // rotation if (velocity != Vector3f.ZERO) spatial.rotateUpTo(velocity.normalize()); spatial.rotate(0,0,FastMath.PI/2f); // scaling and alpha float speed = velocity.length(); long difTime = System.currentTimeMillis() - spawnTime; float percentLife = 1- difTime / lifespan; float alpha = lesserValue(1.5f,lesserValue(percentLife*2,speed)); alpha *= alpha; setAlpha(alpha); spatial.setLocalScale(0.3f+lesserValue(lesserValue(1.5f,0.02f*speed+0.1f),alpha)); spatial.scale(0.65f); // is particle expired? if (difTime > Lebensdauer) spac.removeFromParent (); @Override protected void controlRender (RenderManager rm, ViewPort vp) private float lesserValue (float a, float b) return a < b ? a : b; private void setAlpha(float alpha) color.set(color.r,color.g,color.b,alpha); Node spatialNode = (Node) spatial; Picture pic = (Picture) spatialNode.getChild(spatialNode.getName()); pic.getMaterial().setColor("Color",color);
An der Spitze der Klasse deklarieren und initialisieren wir einige Variablen. Ihre Namen sollten inzwischen selbsterklärend sein. Wenn Sie einen Blick darauf werfen controlUpdate ()
Sie finden vertrauten Code: Wir bewegen das Teilchen durch seine Geschwindigkeit, verlangsamen es etwas und drehen es in Richtung der Geschwindigkeit.
Wenn das Teilchen sehr langsam ist, setzen wir seine Geschwindigkeit auf Vector3f.ZERO
. Berechnungen mit Null sind viel schneller als mit einer sehr kleinen Zahl, und der Unterschied ist sowieso nicht sichtbar.
Um wirklich eine Explosion zu machen, gehe wirklich Boom, Wir werden das Teilchen größer machen, wenn es sich schnell bewegt, was normalerweise direkt nach der Explosion geschieht. Auf dieselbe Weise machen wir das Teilchen kleiner und sogar transparent, wenn es sich sehr langsam bewegt oder das Ende seiner Lebensdauer erreicht. Um es transparenter zu machen, nennen wir eine Hilfsmethode, setAlpha (Float Alpha)
.
Spitze: Wenn Sie nicht wissen, wie man Kinderspachteln erhält und das Material einstellt, können Sie die Methode entweder kopieren oder einfügen oder einen Blick darauf werfen SeekerControl
oder WandererControl
aus dem zweiten Kapitel; es wird dort erklärt.
Nun, da wir das fertig haben ParticleControl
, Sie können das Spiel starten und… nichts sehen.
Wissen Sie, was wir vergessen haben??
Wenn ein Feind stirbt, müssen wir anrufen enemyExplosion ()
in dem ParticleManager
, sonst wird nichts passieren! Schaut mal rein MonkeyBlasterMain
und suchen Sie nach der Methode handleCollisions ()
, Hier sterben Feinde. Fügen Sie nun einfach den Anruf in die rechte Zeile ein:
//… else if (enemyNode.getChild (i) .getName (). Equals ("Wanderer")) hud.addPoints (1); particleManager.enemyExplosion (enemyNode.getChild (i) .getLocalTranslation ()); enemyNode.detachChildAt (i); bulletNode.detachChildAt (j); sound.explosion (); brechen; //…
Und Sie dürfen nicht vergessen, dass es einen zweiten Weg gibt, wie Feinde sterben können: wenn sie in schwarze Löcher gesaugt werden. Fügen Sie einfach die (fast) gleiche Zeile ein paar Zeilen weiter nach unten ein, wenn Sie auf Kollisionen mit dem schwarzen Loch prüfen:
if (checkCollision (enemyNode.getChild (j), blackHole)) particleManager.enemyExplosion (enemyNode.getChild (j) .getLocalTranslation ()); enemyNode.detachChildAt (j);
Jetzt können Sie endlich das Spiel starten und ein wenig spielen. Diese Partikel tragen wirklich zur Atmosphäre bei, finden Sie nicht? Aber lasst uns nicht bei einem Effekt aufhören; es gibt noch viel mehr…
Wenn eine Kugel den Rand des Bildschirms trifft, wird sie ebenfalls explodieren.
Schaut mal rein BulletControl
. Es gibt bereits einen Code, der prüft, ob sich das Geschoss außerhalb der Bildschirmgrenzen befindet, also lösen wir die Explosion dort aus. Dazu müssen wir die ParticleManager
im BulletControl
und übergeben Sie es im Konstruktor:
public BulletControl (Vector3f-Richtung, int screenWidth, int screenHeight, ParticleManager particleManager) this.particleManager = particleManager;
Vergessen Sie nicht, dass Sie das bestehen müssen ParticleManager
im MonkeyBlasterMain
.
Wir werden den Aufruf hier einfügen:
if (loc.x screenWidth || loc.y> screenHeight) particleManager.bulletExplosion (loc); spac.removeFromParent ();
Das bulletExplosion (Vector3f-Position)
Methode ist der sehr ähnlich enemyExplosion (Vector3f-Position)
Methode. Der einzige Unterschied ist, dass wir die Partikel nicht so schnell machen und dass wir eine feste Farbe (ein helles Blau) verwenden. Außerdem verringern wir die Lebensdauer der Partikel.
public void bulletExplosion (Position Vector3f) für (int i = 0; i<30; i++) Vector3f velocity = getRandomVelocity(175); Spatial particle = standardParticle.clone(); particle.setLocalTranslation(position); ColorRGBA color = new ColorRGBA(0.676f,0.844f,0.898f,1); particle.addControl(new ParticleControl(velocity, 1000, color)); particleNode.attachChild(particle);
Da wir über den erforderlichen Code verfügen, können Sie leicht neue Explosionen hinzufügen, wie Sie sehen. Bevor wir eine weitere Explosion für den Tod des Spielers hinzufügen, fügen wir eine neue Funktionalität hinzu ParticleControl
.
Wenn eine Kugel den Rand des Bildschirms trifft, ist etwa die Hälfte der Partikel unbrauchbar. Diese Partikel erscheinen nie wirklich auf dem Bildschirm, weil sie davon weg fliegen. Lass uns das ändern.
Wir werden nun die Geschwindigkeit jedes Partikels, das den Bildschirm verlässt, drehen, so dass sie von den Grenzen "abgestoßen" werden.
Vector3f loc = räumlich.getLocalTranslation (); if (loc.x < 0) velocity.x = Math.abs(velocity.x); else if (loc.x > screenWidth) Geschwindigkeit.x = -Math.abs (Geschwindigkeit.x); if (loc.z < 0) velocity.y = Math.abs(velocity.y); else if (loc.y > screenHeight) Geschwindigkeit.y = -Math.abs (Geschwindigkeit.y);
Wir invertieren nicht den ganzen Vektor, nur den x
oder y
variabel (abhängig von der getroffenen Grenze). Dies führt zu einer richtigen Abstoßung, wie ein Spiegel, der Licht reflektiert.
Spitze: Du darfst nicht vergessen zu passen Bildschirmbreite
und screenHeight
von MonkeyBlasterMain
zu ParticleManager
und von dort zu jedem ParticleControl
. Wenn Ihnen sauberer Code nicht so wichtig ist könnte machen Sie zwei statische Variablen in MonkeyBlasterMain
und mit ihnen arbeiten.
Starten Sie das Spiel, und Sie werden feststellen, dass Kugelexplosionen jetzt viel heller aussehen. Partikel von feindlichen Explosionen werden ebenfalls abgestoßen.
Wenn der Spieler stirbt, wollen wir eine Ja wirklich große Explosion, die den gesamten Bildschirm bedeckt. Wir nennen die Methode noch einmal in killPlayer ()
im MonkeyBlasterMain
.
particleManager.playerExplosion (player.getLocalTranslation ());
Der Code für SpielerExplosion
ist so ziemlich wie vorher. Dieses Mal verwenden wir jedoch zwei Farben, Weiß und Gelb, und interpolieren zwischen ihnen. Wir setzen die Geschwindigkeit auf 1000
und die Lebensdauer bis 2800
Millisekunden.
public void playerExplosion (Position Vector3f) ColorRGBA color1 = ColorRGBA.White; ColorRGBA color2 = ColorRGBA.Yellow; für (int i = 0; i<1200; i++) Vector3f velocity = getRandomVelocity(1000); Spatial particle = standardParticle.clone(); particle.setLocalTranslation(position); ColorRGBA color = new ColorRGBA(); color.interpolate(color1, color2, rand.nextFloat()); particle.addControl(new ParticleControl(velocity, 2800, color, screenWidth, screenHeight)); particleNode.attachChild(particle);
Nun, da wir einige Partikeleffekte haben, fügen wir ihnen die Schwerkraft hinzu. Wann immer sie nahe genug an ein schwarzes Loch kommen, sollten sie eingesaugt werden - dies gilt jedoch nicht für jedes Teilchen. Später wollen wir einen Partikel-Typ haben, der eingesaugt wird, und einen Typ, der dies nicht tut. Daher müssen wir unseren Teilchen ein Attribut hinzufügen:
Particle.setUserData ("protectedByGravity", true);
Alle Partikeltypen, die wir bisher erstellt haben, sollten von schwarzen Löchern eingesaugt werden, sodass Sie diese Zeile zu jeder Methode hinzufügen können, in der wir Partikel erzeugen.
Nun zum Umgang mit der Schwerkraft. Gehe zu handleGravity ()
im MonkeyBlasterMain
-Hier haben wir die Schwerkraft im dritten Teil der Serie umgesetzt.
Dieses Mal prüfen wir nicht, ob sich ein Teilchen in Reichweite des Schwarzen Lochs befindet. Wir werden einfach die Schwerkraft auf alle anwenden. Wenn ein bestimmtes Teilchen weit entfernt ist, ist der Effekt der Schwerkraft sowieso nicht sehr stark.
Wir prüfen, ob das Partikel von der Schwerkraft beeinflusst wird, und wenn ja, wenden wir es an:
// check Particles auf (int j = 0; jJetzt müssen wir uns erweitern
applyGravity ()
auch://… else if (target.getName (). Equals ("Laser") || target.getName (). Equals ("Glow")) target.getControl (ParticleControl.class) .applyGravity (gravity.mult ( 15000), Entfernung);Wir müssen den Namen des Ziels für beide prüfen Laser und Glühen, denn dies sind zwei verschiedene Arten von Teilchen, die dasselbe Verhalten haben.
Zu beachten ist auch, dass wir nicht nur den modifizierten Gravitationsvektor weitergeben, sondern auch den Abstand zum Schwarzen Loch. Dies ist wichtig bei der Berechnung der Kraft in
applyGravity ()
imParticleControl
:Vector3f additionalVelocity = Schwerkraftmulti (1000f / (Abstand * Abstand + 10000f)); Velocity.addLocal (zusätzliche Geschwindigkeit); wenn (Entfernung) < 400) additionalVelocity = new Vector3f(gravity.y, -gravity.x, 0).mult(3f / (distance + 100)); velocity.addLocal(additionalVelocity);Hier,
Schwere
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 ist
(Abstand * Abstand) + 10000
-das heißt, es enthält einen Abstand-Quadrat-Begriff. Dies bewirkt, dass sich die Anziehungskraft einem maximalen Wert annähert, anstatt sich gegen unendlich zu neigen, da der Abstand sehr klein wird.Wenn der Abstand größer als 100 Pixel wird,
(Entfernung * Entfernung)
wird schnell viel größer als 10.000. Daher 10.000 zu hinzufügen(Entfernung * Entfernung)
hat einen sehr kleinen 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, die wir vorgenommen haben, besteht darin, der Geschwindigkeit eine seitliche Komponente hinzuzufügen, wenn sich die Partikel nahe genug an das Schwarze Loch befinden. Dies dient zwei Zwecken: erstens werden die Partikel im Uhrzeigersinn in Richtung des Schwarzen Lochs spiralförmig; Zweitens erreichen die Partikel, wenn sie nahe genug sind, das Gleichgewicht und bilden einen leuchtenden Kreis um das Schwarze Loch.
Spitze: Einen Vektor drehen,v
, 90 ° im Uhrzeigersinn nehmen(v.y, -v.x)
. Um 90 ° gegen den Uhrzeigersinn zu drehen, nehmen Sie ebenfalls(-v.y, v.x)
.Dieser Partikeleffekt erscheint hübsch, wenn Sie das Spiel starten und betrachten. Dies gilt insbesondere, wenn viele Explosionen und Partikel vorhanden sind. Wenn es keine Explosionen gibt, wirken schwarze Löcher irgendwie langweilig. Wir werden das bald ändern.
Partikel aus schwarzen Löchern sprühen
Damit aus schwarzen Löchern kontinuierlich Partikel entstehen, müssen wir uns das ansehen
controlUpdate (float tpf)
Methode inBlackHoleControl
. Da ist einob
Anweisung, dass geprüft wird, ob das Schwarze Loch aktiv ist; Wenn dies der Fall ist, führen wir diesen Code aus:long sprayDif = System.currentTimeMillis () - lastSprayTime; if ((System.currentTimeMillis () / 250)% 2 == 0 && sprayDif> 20) lastSprayTime = System.currentTimeMillis (); Vector3f sprayVel = MonkeyBlasterMain.getVectorFromAngle (sprayAngle) .mult (rand.nextFloat () * 3 +6); Vector3f randVec = MonkeyBlasterMain.getVectorFromAngle (rand.nextFloat () * FastMath.PI * 2); randVec.multLocal (4 + rand.nextFloat () * 4); Vector3f position = räumlich.getLocalTranslation (). Add (sprayVel.mult (2f)). AddLocal (randVec); ParticleManager.sprayParticle (Position, sprayVel.mult (30f)); sprayAngle - = FastMath.PI * tpf / 10f;Wir haben hier ein paar neue Variablen. Sie müssen das deklarieren und initialisieren
long lastSprayTime
, dasSchwimmer sprayAngle
und dasZufälliger Rand
. Sie müssen auch das angebenParticleManager
und übergeben Sie es von der Hauptklasse, damit wir die Partikel tatsächlich besprühen können.Bei dieser Methode spritzen die schwarzen Löcher violette Partikel, die einen kühlen, glühenden Ring bilden, der um das schwarze Loch kreist
Die tatsächliche
sprayParticle ()
Methode ist nichts Besonderes. Wir erstellen ein Partikel, wenden eine violette Farbe an, fügen ein Steuerelement hinzu und so weiter:public void sprayParticle (Position Vector3f, Vector3f sprayVel) Räumliche Teilchen = standardParticle.clone (); Particle.setLocalTranslation (Position); ColorRGBA-Farbe = new ColorRGBA (0,8f, 0,4f, 0,8f, 1f); Particle.addControl (neue ParticleControl (sprayVel, 3500, color, screenWidth, screenHeight)); Particle.setUserData ("protectedByGravity", true); ((Knoten) guiNode.getChild ("Partikel")). AttachChild (Partikel);Starten Sie das Spiel und sehen Sie, wie es aussieht.
Spitze: Wenn Sie das Kreisverhalten der Partikel ändern möchten, können Sie mit den Werten in herumspielen
applyGravity ()
imParticleControl
.Dies verbessert das allgemeine Aussehen der Schwarzen Löcher, ist aber noch nicht gut genug! Es gibt noch einen weiteren Effekt, den wir hinzufügen können…
Black Hole Explosionen
Jetzt werden wir die schwarzen Löcher nicht explodieren lassen, wenn sie sterben. Wir werden stattdessen jedes Mal eine Partikelexplosion auslösen, wenn ein schwarzes Loch getroffen wird.
Fügen Sie die folgende Methode zu hinzu
ParticleManager
:public void blackHoleExplosion (Vector3f-Position) float hue = ((System.currentTimeMillis () - spawnTime) * 0.003f)% 6f; int Anzahl Partikel = 150; ColorRGBA-Farbe = hsvToColor (Farbton, 0,25f, 1); float startOffset = rand.nextFloat () * FastMath.PI * 2 / numParticles; für (int i = 0; iDies 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.
Schiff Auspuff Feuer
Gemäß den Gesetzen der geometrisch-neonischen Physik treibt das Schiff des Spielers sich selbst an, indem es einen Strom feuriger Teilchen aus seinem Auspuff stößt. 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 zentralen Strom, 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 sich kreuzendes Muster zu erzeugen, und haben eine rötere Farbe, während der Mittelstrom eine heißere gelb-weiße Farbe hat.
Damit das Feuer heller leuchtet, als wenn es alleine blühen würde, wird das Schiff zusätzliche Partikel aussenden, die folgendermaßen aussehen:
Ein einzelnes Glutpartikel.Diese Partikel werden gefärbt und mit den regulären Partikeln gemischt. Der Code für den gesamten Effekt wird unten gezeigt:
public void makeExhaustFire (Vector3f-Position, Float-Rotation) ColorRGBA midColor = new ColorRGBA (1f, 0.73f, 0.12f, 0.7f); ColorRGBA-SideColor = neuer ColorRGBA (0,78f, 0,15f, 0,04f, 0,7f); Vector3f direction = MonkeyBlasterMain.getVectorFromAngle (Drehung); float t = (System.currentTimeMillis () - spawnTime) / 1000f; Vector3f baseVel = direction.mult (-45f); Vector3f perpVel = new Vector3f (baseVel.y, -baseVel.x, 0) .multLocal (2f * FastMath.sin (t * 10f)); Vector3f pos = position.add (MonkeyBlasterMain.getVectorFromAngle (Drehung) .multLocal (-25f)); // mittlerer Strom Vector3f randVec = MonkeyBlasterMain.getVectorFromAngle (new Random (). nextFloat () * FastMath.PI * 2); Vector3f velMid = baseVel.add (randVec.mult (7.5f)); Spatial particleMid = standardParticle.clone (); ParticleMid.setLocalTranslation (pos); ParticleMid.addControl (neue ParticleControl (velMid, 800, midColor, screenWidth, screenHeight)); ParticleMid.setUserData ("betroffenByGravity", true); ((Knoten) guiNode.getChild ("particle")). AttachChild (particleMid); Spatial particleMidGlow = glowParticle.clone (); particleMidGlow.setLocalTranslation (pos); particleMidGlow.addControl (neue ParticleControl (velMid, 800, midColor, screenWidth, screenHeight)); particleMidGlow.setUserData ("protectedByGravity", true); ((Knoten) guiNode.getChild ("particle")). AttachChild (particleMidGlow); // side streams Vector3f randVec1 = MonkeyBlasterMain.getVectorFromAngle (new Random (). nextFloat () * FastMath.PI * 2); Vector3f randVec2 = MonkeyBlasterMain.getVectorFromAngle (new Random (). NextFloat () * FastMath.PI * 2); Vector3f velSide1 = baseVel.add (randVec1.mult (2.4f)). AddLocal (perpVel); Vector3f velSide2 = baseVel.add (randVec2.mult (2.4f)). SubtractLocal (perpVel); Spatial particleSide1 = standardParticle.clone (); particleSide1.setLocalTranslation (pos); ParticleSide1.addControl (neue ParticleControl (velSide1, 800, sideColor, screenWidth, screenHeight)); ParticleSide1.setUserData ("betroffenesByGravity", true); ((Knoten) guiNode.getChild ("particle")). AttachChild (particleSide1); Spatial particleSide2 = standardParticle.clone (); particleSide2.setLocalTranslation (pos); particleSide2.addControl (neue ParticleControl (velSide2, 800, sideColor, screenWidth, screenHeight)); ParticleSide2.setUserData ("betroffenesByGravity", true); ((Knoten) guiNode.getChild ("Partikel")). AttachChild (particleSide2); Spatial particleSide1Glow = glowParticle.clone (); ParticleSide1Glow.setLocalTranslation (pos); ParticleSide1Glow.addControl (neue ParticleControl (velSide1, 800, sideColor, screenWidth, screenHeight)); ParticleSide1Glow.setUserData ("betroffenesByGravity", true); ((Knoten) guiNode.getChild ("Partikel")). AttachChild (particleSide1Glow); Spatial particleSide2Glow = glowParticle.clone (); particleSide2Glow.setLocalTranslation (pos); particleSide2Glow.addControl (neue ParticleControl (velSide2, 800, sideColor, screenWidth, screenHeight)); ParticleSide2Glow.setUserData ("betroffenesByGravity", true); ((Knoten) guiNode.getChild ("Partikel")). AttachChild (particleSide2Glow);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 Strom erzeugen wir zwei überlappende Partikel pro Frame: ein Standardpartikel und ein Glow-Partikel dahinter.
Fügen Sie diesen Code ein
PlayerControl
, am Ende voncontrolUpdate (float tpf)
:if (aufwärts || abwärts || links || rechts) particleManager.makeExhaustFire (räumlich.getLocalTranslation (), Drehung);Natürlich darfst du nicht vergessen, das zu bestehen
ParticleManager
vonMonkeyBlasterMain
.
Fazit
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