Faire un vecteur Neon Shooter avec jME effets de particules

Nous avons codé le gameplay, l'audio et l'interface utilisateur de notre jeu inspiré de Geometry Wars basé sur jMonkeyEngine. Nous pouvons maintenant nous tourner vers des effets graphiques et du polissage soignés. Dans cette partie en particulier, nous allons nous concentrer sur les effets de particules (y compris des explosions très colorées).


Vue d'ensemble

Voici ce à quoi nous travaillons dans toute la série:


… Et voici une vidéo qui montre les effets de particules que nous ajoutons dans cette partie:


Il y aura différents types de particules ainsi que différents émetteurs:

  • Lorsque les ennemis sont touchés, ils meurent dans une explosion colorée.
  • Lorsque le joueur meurt, son navire explose dans une énorme explosion dorée.
  • Le moteur du joueur émet un simple effet de feu de particules.
  • Les balles qui ont frappé la frontière de l'écran explosent.
  • Les trous noirs émettent en permanence des particules pourpres (ce qui leur donne un aspect plus froid).
  • Lorsqu'un trou noir perd des points de vie, il émet une explosion de particules colorées..

En plus du dernier type de particules, toutes les particules sont affectées par la gravité et sont aspirées dans des trous noirs. Ainsi, lorsqu'un trou noir aspire plusieurs particules à la fois, il commence à briller à cause de toutes les particules - ce qui est plutôt cool.

Un autre effet que nous ajouterons est de rendre nos particules plus grosses et donc plus brillantes plus vite. Cela signifie qu'une explosion a l'air très brillante et brillante au début, mais qu'elle perd rapidement de sa luminosité une fois que les particules ont ralenti..

Pour atteindre nos objectifs, nous devrons ajouter deux nouvelles classes:

  • ParticleManager: Cette classe de gestionnaires s'occupera des attributs pour chaque type d'explosion.
  • Contrôle de particules: Je pense que vous pouvez déjà deviner que cette classe, encore une fois, contrôle le comportement de nos particules.

Commençons par l'effet le plus remarquable: l'explosion d'ennemis.


Explosions ennemies

La première classe que nous devons mettre en œuvre est la ParticleManager classe. Comme il est responsable de la formation de particules, il a besoin de certaines variables, telles que la guiNode, la particuleNode et le standardParticle.

Nous allons le cloner à chaque fois que nous en avons besoin, mais jetons un coup d'œil au code de base:

 Classe publique ParticleManager private Node guiNode; Spatial StandardParticule privée, glowParticle; nœud privé particleNode; Random Rand privé; public ParticleManager (Node guiNode, Spatial standardParticle, Spatial glowParticle) this.guiNode = guiNode; this.standardParticle = standardParticle; this.glowParticle = glowParticle; particleNode = new Node ("particules"); guiNode.attachChild (particleNode); rand = new Random (); 

Intégrer le manager dans MonkeyBlasterMain Ce n'est pas grave. Nous venons de le déclarer au début et d'appeler le constructeur simpleInitApp ():

 particleManager = new ParticleManager (guiNode, getSpatial ("Laser"), getSpatial ("Glow"));

Pour faire réellement exploser un ennemi, nous devons avoir la bonne méthode pour le faire dans le ParticleManager:

 public void ennemisExplosion (position Vector3f) // couleurs d'init float hue1 = rand.nextFloat () * 6; float hue2 = (rand.nextFloat () * 2)% 6f; ColorRGBA color1 = hsvToColor (teinte1, 0.5f, 1f); ColorRGBA color2 = hsvToColor (teinte2, 0.5f, 1f); // crée 120 particules pour (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);  

Cette méthode est courte, mais elle en fait beaucoup, nous allons donc la parcourir étape par étape..

Coloration des particules

Afin de rendre nos particules plus intéressantes, nous leur attribuons des couleurs aléatoires.

Une méthode pour produire des couleurs aléatoires consiste à choisir les composants rouge, bleu et vert de manière aléatoire, mais cela produira beaucoup de couleurs ternes et nous aimerions que nos particules aient un aspect "néon"..

Nous pouvons avoir plus de contrôle sur nos couleurs en les spécifiant dans le HSV (teinte, saturation et valeur) espace de couleur. Nous aimerions choisir des couleurs avec une teinte aléatoire, mais avec une saturation et une valeur fixes, afin de les rendre toutes brillantes. Nous avons donc besoin d'une fonction d'assistance capable de produire une couleur à partir de valeurs HSV..

 public ColorRGBA hsvToColor (float h, float s, float v) if (h == 0 && s == 0) retourne le nouveau ColorRGBA (v, v, v, 1);  float c = s * v; float x = c * (1 - Math.abs (h% 2 - 1)); float m = v - c; si (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); 

Pointe: Ne t'inquiète pas trop pour Comment cette fonction fonctionne; Comprenez simplement qu’il peut générer une couleur RGBA à partir de la valeur HSV. La méthode dépasse le cadre de ce tutoriel..

Pourquoi avons-nous besoin de deux couleurs?

Revenons maintenant à notre méthode d'explosion. Regardez les lignes en surbrillance:

 public void ennemisExplosion (position Vector3f) // couleurs d'init float hue1 = rand.nextFloat () * 6; float hue2 = (rand.nextFloat () * 2)% 6f; ColorRGBA color1 = hsvToColor (teinte1, 0.5f, 1f); ColorRGBA color2 = hsvToColor (teinte2, 0.5f, 1f); // crée 120 particules pour (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);  

Afin de rendre l'explosion plus colorée, nous calculons deux couleurs aléatoires et interpolons la couleur finale des particules de manière aléatoire pour chaque particule..

Faire bouger les particules

La prochaine chose que nous faisons est de calculer la vitesse pour chaque particule. Nous traitons cela avec une méthode supplémentaire parce que nous voulons que la direction soit aléatoire, mais pas la vitesse:

 private Vector3f getRandomVelocity (float max) // génère Vector3f avec une direction aléatoire Vector3f vélocité = new Vector3f (rand.nextFloat () - 0.5f, rand.nextFloat () - 0.5f, 0) .normalizeLocal (); // applique une vitesse de particule semi-aléatoire float random = rand.nextFloat () * 5 + 1; float particleSpeed ​​= max * (1f - 0.6f / random); velocity.multLocal (particleSpeed); vitesse de retour; 

Tout d'abord, nous générons un vecteur de vitesse aléatoire et le normalisons. Ensuite, nous calculons une vitesse aléatoire comprise entre 40% et 90% de max.

Revenons maintenant à la ennemiExplosion () méthode. Voici la partie dont nous n'avons pas encore discuté:

 Particule spatiale = standardParticle.clone (); particule.setLocalTranslation (position); ColorRGBA color = new ColorRGBA (); color.interpolate (color1, color2, rand.nextFloat () * 0.5f); particle.addControl (nouveau ParticleControl (vélocité, 3100, couleur)); particleNode.attachChild (particule);

Nous clonons le standardParticle et mis sa traduction à l'origine de l'explosion. Après cela, nous interpolons la couleur des particules entre les deux aléatoires (comme mentionné ci-dessus). Comme vous pouvez le constater, nous ajoutons également un Contrôle de particules qui contrôlera le comportement de la particule. Enfin, nous devons ajouter la particule au nœud pour l’afficher..

Contrôler les particules

Maintenant que notre ParticleManager est terminé, nous devons mettre en œuvre le Contrôle de particules. Certaines parties du code vous sembleront familières:

 Classe publique ParticleControl étend AbstractControl private Vector3f velocity; durée de vie des flotteurs privés; privé long spawnTime; couleur privée ColorRGBA; public ParticleControl (vitesse Vector3f, durée de vie du flotteur, couleur ColorRGBA) this.velocity = vélocité; this.lifespan = durée de vie; this.color = couleur; spawnTime = System.currentTimeMillis ();  @Override protected void controlUpdate (float tpf) // mouvement spatial.move (velocity.mult (tpf * 3f)); velocity.multLocal (1-3f * tpf); if (Math.abs (velocity.x) + Math.abs (velocity.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 > durée de vie) spatial.removeFromParent ();  @Override protected void controlRender (RenderManager, vP ViewPort)  private float lesserValue (float a, float b) retourne 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);  

En haut de la classe, nous déclarons et initialisons quelques variables; leurs noms devraient maintenant être explicites. Si vous regardez controlUpdate () vous trouverez un code familier: nous déplaçons la particule en fonction de sa vitesse, la ralentissons un peu et la tournons dans le sens de la vitesse.
Si la particule est très lente, nous fixons sa vitesse à Vector3f.ZERO. Il est beaucoup plus rapide de faire des calculs avec zéro qu'un très petit nombre, et la différence n'est de toute façon pas visible.

Pour faire exploser une explosion boom, nous allons rendre la particule plus grosse quand elle se déplace rapidement, ce qui est généralement juste après l'explosion. De la même manière, nous rendons la particule plus petite et même transparente lorsqu'elle se déplace très lentement ou atteint la fin de sa vie. Pour rendre cela plus transparent, nous appelons une méthode d'assistance., setAlpha (float alpha).

Pointe: Si vous ne savez pas comment obtenir des spatiales pour les enfants et définir leur matériel, vous pouvez simplement copier-coller la méthode ou consulter SeekerControl ou WandererControl du deuxième chapitre; c'est expliqué là.

Maintenant que nous avons fini le Contrôle de particules, vous pouvez commencer le jeu et voir… rien.
Savez-vous ce que nous avons oublié?

Mettre ensemble

Lorsqu'un ennemi meurt, nous devons appeler ennemiExplosion () dans le ParticleManager, sinon rien ne se passera! Jeter un coup d'œil à MonkeyBlasterMain et chercher la méthode handleCollisions (), c'est là que les ennemis meurent. Insérez maintenant l'appel dans la ligne droite:

 //… else if (ennemiNode.getChild (i) .getName (). Égale ("Wanderer")) hud.addPoints (1);  particleManager.enemyExplosion (ennemiNode.getChild (i) .getLocalTranslation ()); ennemiNode.detachChildAt (i); bulletNode.detachChildAt (j); son.explosion (); Pause; //… 

Et vous ne devez pas oublier qu'il existe un deuxième moyen pour les ennemis de mourir: lorsqu'ils sont aspirés dans des trous noirs. Insérez simplement la (presque) même ligne quelques lignes plus loin lorsque nous vérifions les collisions avec le trou noir:

 if (checkCollision (ennemiNode.getChild (j), blackHole)) particuleManager.enemyExplosion (ennemiNode.getChild (j) .getLocalTranslation ()); ennemiNode.detachChildAt (j); 

Maintenant, vous pouvez enfin commencer le jeu et jouer un peu. Ces particules ajoutent vraiment à l'atmosphère, vous ne pensez pas? Mais ne nous arrêtons pas à un effet; il y en a beaucoup d'autres à venir…


Bullet Explosions

Quand une balle frappe le bord de l'écran, nous la ferons exploser aussi.

Jeter un coup d'œil à BulletControl. Il y a déjà du code qui vérifie si la puce est en dehors des limites de l'écran, alors déclenchons l'explosion ici. Pour ce faire, nous devons déclarer le ParticleManager dans BulletControl et passez le dans le constructeur:

 public BulletControl (direction Vector3f, int screenWidth, int screenHeight, ParticleManager particleManager) this.particleManager = particleManager;

N'oubliez pas que vous devez passer le particuleManager dans MonkeyBlasterMain.

Nous allons insérer l'appel ici:

 if (loc.x screenWidth || loc.y> screenHeight) particleManager.bulletExplosion (loc); spatial.removeFromParent (); 

le bulletExplosion (position Vector3f) méthode est très similaire à la ennemisExplosion (position Vector3f) méthode. La seule différence est que nous ne produirons pas les particules aussi rapidement et que nous utiliserons une couleur fixe (un bleu vif). En outre, nous diminuons la durée de vie des particules.

 bullet public void bulletExplosion (position Vector3f) pour (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);  

Comme nous avons tous les codes nécessaires en place, il est facile d’ajouter de nouvelles explosions, comme vous pouvez le constater. Avant d’ajouter une autre explosion à la mort des joueurs, nous allons ajouter une nouvelle fonctionnalité à la Contrôle de particules.


Repousser les particules à partir des bordures de l'écran

Lorsqu'une balle frappe la bordure de l'écran, environ la moitié des particules sont inutiles. Ces particules n'apparaissent jamais à l'écran car elles s'envolent. Changeons ça.

Nous allons maintenant activer la vitesse de chaque particule qui quitte l’écran pour qu’elle soit «repoussée» par les limites..

 Vector3f loc = spatial.getLocalTranslation (); si (loc.x < 0)  velocity.x = Math.abs(velocity.x);  else if (loc.x > screenWidth) velocity.x = -Math.abs (velocity.x);  if (loc.z < 0)  velocity.y = Math.abs(velocity.y);  else if (loc.y > screenHeight) velocity.y = -Math.abs (velocity.y); 

Nous n'inversons pas le vecteur entier, seulement le X ou y variable (en fonction de la frontière touchée). Il en résulte un effet repoussant approprié, tel qu’un miroir réfléchissant la lumière.

Pointe: Vous ne devez pas oublier de passer largeur d'écran et screenHeight de MonkeyBlasterMain à ParticleManager et de là à chaque Contrôle de particules. Si vous ne vous souciez pas du code propre, vous pourrait faire deux variables statiques dans MonkeyBlasterMain et travailler avec eux.

Commencez le jeu et vous remarquerez que les explosions par balles sont beaucoup plus brillantes maintenant. Les particules provenant d'explosions ennemies sont également repoussées.


Explosion de joueur

Quand le joueur meurt, nous voulons un vraiment grande explosion qui couvre tout l'écran. Nous appelons la méthode, encore une fois, dans killPlayer () dans MonkeyBlasterMain.

 particleManager.playerExplosion (player.getLocalTranslation ());

Le code pour playerExplosion est à peu près la même chose qu'avant. Cependant, cette fois, nous utilisons deux couleurs, le blanc et le jaune, et nous interpolons entre elles. Nous réglons la vitesse à 1000 et la durée de vie à 2800 millisecondes.

 public void playerExplosion (position Vector3f) ColorRGBA color1 = ColorRGBA.White; ColorRGBA color2 = ColorRGBA.Yellow; pour (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);  

Aspiration de particules dans des trous noirs

Maintenant que nous avons quelques effets de particules, ajoutons-leur de la gravité. Chaque fois qu'ils s'approchent suffisamment d'un trou noir, ils devraient être aspirés, mais ce n'est pas le cas pour toutes les particules. Plus tard, nous voudrons avoir un type de particule qui soit aspiré et un type qui ne l’est pas. Par conséquent, nous devons ajouter un attribut à nos particules:

 particle.setUserData ("affectéeByGravity", true);

Tous les types de particules que nous avons créés jusqu'à présent doivent être aspirés par des trous noirs. Vous pouvez donc ajouter cette ligne à toutes les méthodes générant des particules..

Passons maintenant à la manipulation de la gravité. Aller à handleGravity () dans MonkeyBlasterMain -c'est là que nous avons mis en œuvre la gravité dans la troisième partie de la série.

Cette fois, nous ne vérifierons pas si une particule se trouve à la portée du trou noir, nous appliquerons simplement la gravité à toutes les particules. Si une particule spécifique est éloignée, l'effet gravitationnel ne sera de toute façon pas très puissant.

Nous vérifions si la particule est affectée par la gravité et, si c'est le cas, nous l'appliquons:

 // vérifier les particules pour (int j = 0; j 

Maintenant, nous aurons besoin d'étendre applyGravity () ainsi que:

 //… else if (target.getName (). Equals ("Laser") || target.getName (). Equals ("Glow")) target.getControl (ParticleControl.class) .applyGravity (gravity.mult ( 15000), distance); 

Nous devons vérifier le nom de la cible pour les deux Laser et lueur, parce que ce sont deux types de particules qui auront le même comportement.

Une autre chose à noter est que nous ne transmettons pas seulement le vecteur de gravité modifié, mais aussi la distance au trou noir. Ceci est important dans le calcul de la force en applyGravity () dans Contrôle de particules:

 Vector3f additionalVelocity = gravity.mult (1000f / (distance * distance + 10000f)); velocity.addLocal (additionalVelocity); si (distance < 400)  additionalVelocity = new Vector3f(gravity.y, -gravity.x, 0).mult(3f / (distance + 100)); velocity.addLocal(additionalVelocity); 

Ici, la gravité est le vecteur unitaire pointant vers le trou noir. La force d'attraction est une version modifiée de la fonction carrée inverse.

La première modification est que le dénominateur est (distance * distance) + 10000-c'est-à-dire qu'il contient un terme distance-carré. Cela force la force d'attraction à s'approcher d'une valeur maximale au lieu de tendre vers l'infini car la distance devient très petite.

Lorsque la distance devient supérieure à 100 pixels, (distance * distance) devient rapidement bien supérieur à 10 000. Par conséquent, en ajoutant 10 000 à (distance * distance) a un très petit effet, et la fonction se rapproche d'une fonction carrée inverse normale.

Toutefois, lorsque la distance est beaucoup plus petite que 100 pixels, la distance a un faible effet sur la valeur du dénominateur et l'équation devient approximativement égale à:

 vel + = n;

La deuxième modification que nous avons apportée consiste à ajouter une composante latérale à la vitesse lorsque les particules se rapprochent suffisamment du trou noir. Cela sert à deux choses: premièrement, les particules tournent en spirale dans le sens des aiguilles d’une montre vers le trou noir; deuxièmement, lorsque les particules se rapprochent suffisamment, elles atteignent l’équilibre et forment un cercle rougeoyant autour du trou noir.

Pointe: Faire pivoter un vecteur, v, 90 ° dans le sens des aiguilles d'une montre, prenez (v.y, -v.x). De même, pour faire pivoter de 90 ° dans le sens anti-horaire, prenez (-v.y, v.x).

Cet effet de particule semble joli lorsque vous démarrez le jeu et que vous le regardez, et cela est particulièrement vrai lorsqu'il y a beaucoup d'explosions et de particules autour. Mais quand il n'y a pas d'explosions, les trous noirs ont un aspect terne. Nous changerons ça bientôt.


Pulvérisation des particules hors des trous noirs

Pour que les trous noirs produisent en permanence des particules, nous devons examiner le controlUpdate (float tpf) méthode en BlackHoleControl. Il y a un si déclaration qui vérifie si le trou noir est actif; si c'est le cas, nous le ferons exécuter ce code:

 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 = spatial.getLocalTranslation (). Add (sprayVel.mult (2f)). AddLocal (randVec); particuleManager.sprayParticle (position, sprayVel.mult (30f));  sprayAngle - = FastMath.PI * tpf / 10f;

Nous avons quelques nouvelles variables ici. Vous devez déclarer et initialiser le long lastSprayTime, la float sprayAngle et le Rand Rand. En outre, vous devez déclarer le particuleManager et le transmettre de la classe principale afin que nous puissions réellement pulvériser les particules.

La méthode fera en sorte que les trous noirs pulvérisent des éclaboussures de particules violettes qui formeront un anneau rougeoyant qui gravite autour du trou noir.

L'actuel sprayParticule () la méthode n'a rien de spécial. Nous créons une particule, appliquons une couleur pourpre, ajoutons un contrôle et ainsi de suite:

 sprayPartic vide public (position Vector3f, Vector3f sprayVel) Particule spatiale = standardParticle.clone (); particule.setLocalTranslation (position); ColorRGBA color = new ColorRGBA (0.8f, 0.4f, 0.8f, 1f); particle.addControl (nouveau ParticleControl (sprayVel, 3500, color, screenWidth, screenHeight)); particle.setUserData ("affectéeByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particule); 

Démarrer le jeu et voir à quoi il ressemble.

Pointe: Si vous souhaitez modifier le comportement indirect des particules, n'hésitez pas à jouer avec les valeurs de applyGravity () dans Contrôle de particules.

Cela améliore l'aspect général des trous noirs, mais ce n'est pas encore assez bon! Il y a un autre effet que nous pouvons ajouter à cela…


Explosions de trous noirs

Maintenant, nous ne ferons pas exploser les trous noirs quand ils mourront. Au lieu de cela, nous allons déclencher une explosion de particules chaque fois qu'un trou noir est touché.

Ajoutez la méthode suivante à ParticleManager:

 public void blackHoleExplosion (position Vector3f) float hue = ((System.currentTimeMillis () - spawnTime) * 0.003f)% 6f; int numParticules = 150; CouleurRGBA couleur = hsvToColor (teinte, 0.25f, 1); float startOffset = rand.nextFloat () * FastMath.PI * 2 / numParticles; pour (int i = 0; i 

Cela fonctionne généralement de la même manière que les autres explosions de particules. Une différence est que nous sélectionnons la teinte de la couleur en fonction du temps total écoulé. Si vous tirez plusieurs fois de suite dans le trou noir, vous constaterez une rotation progressive de la teinte des explosions. Cela semble moins compliqué que d'utiliser des couleurs aléatoires tout en permettant la variation.


Incendie des navires

Comme le dictent les lois de la physique géométrique et du néon, le vaisseau du joueur se propulse en projetant un flot de particules de feu sur son tuyau d'échappement. Avec notre moteur de particules en place, cet effet est facile à créer et ajoute une touche visuelle au mouvement du navire..

Au fur et à mesure que le navire se déplace, nous créons trois flux de particules: un flux central qui tire directement à l'arrière du navire et deux flux latéraux dont les angles pivotent d'avant en arrière par rapport au navire. Les deux flux latéraux pivotent dans des directions opposées pour créer un motif entrecroisé et ont une couleur plus rouge tandis que le flux central a une couleur plus chaude, jaune-blanc..

Pour que le feu brille plus fort que lors de la seule floraison, le navire émettra des particules supplémentaires ressemblant à ceci:


Une seule particule luminescente.

Ces particules seront teintées et mélangées aux particules régulières. Le code de l’effet complet est présenté ci-dessous:

 vide public makeExhaustFire (position Vector3f, rotation flottante) ColorRGBA midColor = nouveau ColorRGBA (1f, 0.73f, 0.12f, 0.7f); ColorRGBA sideColor = nouveau ColorRGBA (0.78f, 0.15f, 0.04f, 0.7f); Direction Vector3f = MonkeyBlasterMain.getVectorFromAngle (rotation); float t = (System.currentTimeMillis () - spawnTime) / 1000f; Vector3f baseVel = direction.mult (-45f); Vector3f perpVel = nouveau Vector3f (baseVel.y, -baseVel.x, 0) .multLocal (2f * FastMath.sin (t * 10f)); Vector3f pos = position.add (MonkeyBlasterMain.getVectorFromAngle (rotation) .multLocal (-25f)); // flux moyen Vector3f randVec = MonkeyBlasterMain.getVectorFromAngle (new Random (). nextFloat () * FastMath.PI * 2); Vector3f velMid = baseVel.add (randVec.mult (7.5f)); Particule spatialeMid = standardParticle.clone (); particuleMid.setLocalTranslation (pos); particleMid.addControl (nouveau ParticleControl (velMid, 800, midColor, screenWidth, screenHeight)); particleMid.setUserData ("AffectéByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particleMid); Particule spatialeMidGlow = glowParticle.clone (); particuleMidGlow.setLocalTranslation (pos); particleMidGlow.addControl (nouveau ParticleControl (velMid, 800, midColor, screenWidth, screenHeight)); particleMidGlow.setUserData ("affectsByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particleMidGlow); // flux parallèles 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)). SoustractLocal (perpVel); Particule spatiale1 = standardParticle.clone (); particleSide1.setLocalTranslation (pos); particleSide1.addControl (nouveau ParticleControl (velSide1, 800, sideColor, screenWidth, screenHeight)); particleSide1.setUserData ("affectsByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particleSide1); Particule SpatialSide2 = standardParticle.clone (); particuleSide2.setLocalTranslation (pos); particleSide2.addControl (nouveau ParticleControl (velSide2, 800, sideColor, screenWidth, screenHeight)); particleSide2.setUserData ("affectsByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particleSide2); Particule spatialeSide1Glow = glowParticle.clone (); particleSide1Glow.setLocalTranslation (pos); particleSide1Glow.addControl (nouveau ParticleControl (velSide1, 800, sideColor, screenWidth, screenHeight)); particleSide1Glow.setUserData ("affectsByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particleSide1Glow); Particule spatialeSide2Glow = glowParticle.clone (); particleSide2Glow.setLocalTranslation (pos); particleSide2Glow.addControl (nouveau ParticleControl (velSide2, 800, sideColor, screenWidth, screenHeight)); particleSide2Glow.setUserData ("affectéeByGravity", true); ((Node) guiNode.getChild ("particules")). AttachChild (particleSide2Glow); 

Il n'y a rien de sournois dans ce code. Nous utilisons une fonction sinus pour produire l’effet de pivotement dans les courants latéraux en faisant varier leur vitesse latérale dans le temps. Pour chaque flux, nous créons deux particules superposées par image: une particule standard et une particule luminescente derrière celle-ci..

Insérer ce morceau de code dans PlayerControl, au bout du controlUpdate (float tpf):

 if (haut || bas || gauche || droite) particleManager.makeExhaustFire (spatial.getLocalTranslation (), rotation); 

Bien sûr, vous ne devez pas oublier de passer le particuleManager de MonkeyBlasterMain.


Conclusion

Avec tous ces effets de particules, Shape Blaster commence à avoir l'air cool. Dans la dernière partie de cette série, nous ajouterons un autre effet impressionnant: la grille de fond de déformation