Am codificat gameplay-ul, sunetul și interfața utilizator pentru jocul inspirat de jocul Geometry Wars bazat pe jMonkeyEngine, iar acum putem să ne întoarcem la câteva efecte grafice grafice și poloneză. În această parte, în mod specific, ne vom concentra pe efectele particulelor (inclusiv unele explozii foarte colorate).
Iată la ce lucrăm în întreaga serie:
... și iată un videoclip care arată efectele particulelor pe care le adăugăm în această parte:
Vor fi diferite tipuri de particule, precum și diferiți emițători:
Pe lângă ultimul tip de particule, toate particulele sunt afectate de gravitate și sunt absorbite în găuri negre. Deci, atunci când o gaură neagră suge în mai multe particule la un moment dat, începe să strălucească din cauza tuturor particulelor - care arată foarte bine.
Un alt efect pe care îl vom adăuga este ca particulele noastre să devină mai mari și, prin urmare, mai strălucitoare, cu cât sunt mai repede. Acest lucru va însemna că o explozie pare la început foarte strălucitoare și strălucitoare, dar își pierde rapid strălucirea odată ce particulele încetinesc.
Pentru a ne atinge obiectivele, va trebui să adăugăm două clase noi:
ParticleManager
: Această clasă de manager va avea grijă de atributele pentru fiecare tip de explozie.ParticleControl
: Cred că deja puteți ghici că această clasă, încă o dată, controlează comportamentul particulelor noastre.Să începem cu efectul cel mai vizibil: explozii inamice.
Prima clasă pe care trebuie să o implementăm este ParticleManager
clasă. Din moment ce este responsabil pentru particulele de reproducere, este nevoie de câteva variabile, cum ar fi guiNode
, particleNode
si standardParticle
.
Vom clona acest lucru ori de câte ori avem nevoie de el, dar aruncăm o privire la codul de bază:
clasa publica ParticleManager nod privat guiNode; Particulară spațială parțială, glowParticle; Nodul privat particleNode; privat Random rand; ParticleManager public (Node guiNode, Partea standard spațială, GlowParticle spațial) this.guiNode = guiNode; acest standardParticular = standardParticle; this.glowParticle = glowParticle; particleNode = nod nou ("particule"); guiNode.attachChild (particleNode); rand = new Random ();
Integrarea managerului în MonkeyBlasterMain
nu este mare lucru. Vom declara doar la început și vom apela constructorul simpleInitApp ()
:
particleManager = ParticleManager nou (guiNode, getSpatial ("Laser"), getSpatial ("Glow"));
Pentru a face ca un inamic să explodeze, trebuie să avem metoda potrivită pentru a face acest lucru în ParticleManager
:
public void enemyExplosion (pozitia Vector3f) // culori init float hue1 = rand.nextFloat () * 6; float hue2 = (rand.nextFloat () * 2)% 6f; ColorRGBA color1 = hsvToColor (hue1, 0.5f, 1f); ColorRGBA color2 = hsvToColor (hue2, 0.5f, 1f); // creați 120 de particule pentru (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);
Această metodă este scurtă, dar face multe, așa că vom trece prin ea pas cu pas.
Pentru a face particulele noastre mai interesante, le vom aloca culori aleatorii.
O metodă de a produce culori aleatorii este alegerea aleatorie a componentelor roșii, albastre și verzi, dar acest lucru va produce o mulțime de culori plictisitoare și ne-ar plăcea ca particulele noastre să aibă un aspect "neon de lumină".
Putem obține mai mult control asupra culorilor noastre prin specificarea lor în HSV (nuanță, saturație și valoare) spațiu de culoare. Am dori să alegem culori cu o nuanță aleatorie, dar o saturație și o valoare fixă, pentru a le face să pară strălucitoare și strălucitoare, deci avem nevoie de o funcție de ajutor care să producă o culoare din valorile HSV.
(h, 0, && s == 0) returnarea noului ColorRGBA (v, v, v, 1); float c = s * v; float x = c * (1 - Math.abs (h% 2 - 1)); float m = v - c; dacă (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);
Bacsis: Nu vă faceți griji prea mult Cum această funcție funcționează; înțelegeți doar că poate genera o culoare RGBA din valoarea HSV. Metoda este dincolo de domeniul de aplicare și de centrul acestui tutorial.
Acum înapoi la metoda noastră de explozie. Aruncați o privire la liniile evidențiate:
public void enemyExplosion (pozitia Vector3f) // culori init float hue1 = rand.nextFloat () * 6; float hue2 = (rand.nextFloat () * 2)% 6f; ColorRGBA color1 = hsvToColor (hue1, 0.5f, 1f); ColorRGBA color2 = hsvToColor (hue2, 0.5f, 1f); // creați 120 de particule pentru (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);
Pentru a face explozia mai colorată, se calculează două culori aleatorii și se interpolează culoarea finală a particulelor la întâmplare pentru fiecare particulă.
Următorul lucru pe care îl facem este de a calcula viteza pentru fiecare particulă. Ne ocupăm de aceasta într-o metodă suplimentară, deoarece vrem ca direcția să fie aleatoare, dar nu viteza:
privat Vector3f getRandomVelocity (float max) // genera Vector3f cu directia aleatorie Vector3f velocity = new Vector3f (rand.nextFloat () - 0.5f, rand.nextFloat () - 0.5f, 0) .normalizeLocal (); / / aplica semănătoare ale vitezei particulelor float random = rand.nextFloat () * 5 + 1; float particleSpeed = max * (1f - 0.6f / aleatoriu); velocity.multLocal (particleSpeed); viteza de retur;
Mai întâi, generăm un vector de viteză aleatorie și îl normalizăm. Apoi, se calculează o viteză aleatorie în intervalul între 40% și 90% din max
.
Acum, înapoi la enemyExplosion ()
metodă. Iată partea pe care nu am discutat încă:
Particule particulare = standardParticle.clone (); particle.setLocalTranslation (poziție); Culoare ColorRGBA = ColorRGBA () nou; color.interpolate (color1, color2, rand.nextFloat () * 0.5f); particle.addControl (nou ParticleControl (viteza, 3100, culoare)); particleNode.attachChild (particule);
Clonăm standardParticle
și a stabilit traducerea sa la originea exploziei. Apoi, interpolăm culoarea particulelor între cele două aleatoare (așa cum am menționat mai sus). După cum puteți vedea, adăugăm și a ParticleControl
care va controla comportamentul particulei. În cele din urmă, trebuie să adăugăm particula în nod pentru a fi afișată.
Acum asta ParticleManager
este terminat, trebuie să punem în aplicare ParticleControl
. Părțile din cod vă vor arăta familiare:
clasa publică ParticleControl extinde AbstractControl viteza privată Vector3f; viata privata a flotorului; private long spawnTime; culoarea privată ColorRGBA; ParticleControl public (viteza Vector3f, durata de viață a flotorului, culoarea ColorRGBA) this.velocity = viteza; this.lifespan = durata de viata; this.color = culoare; spawnTime = System.currentTimeMillis (); @Override protejat void controlUpdate (float tpf) // mișcare spatial.move (viteza.mult (tpf * 3f)); velocity.multLocal (1-3F * TPF); dacă (Math.abs (velocity.x) + Math.abs (viteza.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 > durata de viață) spatial.removeFromParent (); @Override protejat void controlRender (RenderManager rm, ViewPort vp) float private lesserValue (float a, float b) returnați 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);
În partea de sus a clasei, declarăm și inițializăm câteva variabile; numele lor ar trebui să fie auto-explicative până acum. Dacă te uiți la controlUpdate ()
veți găsi un cod familiar: mutăm particula cu viteza ei, o încetinim puțin și o rotim în direcția vitezei.
Dacă particula este foarte lentă, ne-am stabilit viteza Vector3f.ZERO
. Este mult mai rapid să faci calcule cu zero decât un număr foarte mic, iar diferența nu este vizibilă oricum.
Pentru a face o explozie într-adevăr merge bum, vom face particula mai mare atunci când se mișcă repede, care este, de obicei, imediat după explozie. În același mod, facem particula mai mică și chiar transparentă atunci când se mișcă foarte încet sau atinge sfârșitul duratei de viață. Pentru ao face mai transparent, numim o metodă de ajutor, setAlpha (float alfa)
.
Bacsis: Dacă nu știți cum să obțineți spațiul copiilor și să vă stabiliți materialul, puteți copia-copiați metoda sau aruncați o privire la SeekerControl
sau WandererControl
din al doilea capitol; este explicat acolo.
Acum că am terminat ParticleControl
, poți începe jocul și vezi ... nimic.
Știți ce am uitat?
Când un dușman moare, trebuie să sunăm enemyExplosion ()
în ParticleManager
, altfel nimic nu se va întâmpla! Aruncăm o privire la MonkeyBlasterMain
și căutați metoda handleCollisions ()
, acesta este locul unde muri inamicii. Acum, trebuie doar să introduceți apelul pe linia dreaptă:
// ... altfel dacă (enemyNode.getChild (i) .getName () este egal ("Wanderer")) hud.addPoints (1); particleManager.enemyExplosiune (enemyNode.getChild (i) .getLocalTranslation ()); enemyNode.detachChildAt (i); bulletNode.detachChildAt (j); sound.explosion (); pauză; // ...
Și nu trebuie să uitați că există un al doilea mod în care dușmanii pot muri: când se suge în găuri negre. Doar introduceți linia (aproape) aceeași cu câteva linii mai jos când verificăm coliziuni cu gaura neagră:
dacă (checkCollision (enemyNode.getChild (j), blackHole)) particleManager.enemyExplosion (enemyNode.getChild (j) .getLocalTranslation ()); enemyNode.detachChildAt (j);
Acum puteți începe jocul și puteți juca puțin. Aceste particule chiar adaugă atmosfera, nu crezi? Dar să nu ne oprim la un singur efect; mai sunt multe altele ...
Când un glonț lovește marginea ecranului, vom face să explodeze și el.
Aruncăm o privire la BulletControl
. Există deja un cod care verifică dacă glonțul este în afara marginilor ecranului, așa că declanșăm explozia acolo. Pentru a face acest lucru, trebuie să declarăm ParticleManager
în BulletControl
și treceți-l în constructor:
public BulletControl (direcția Vector3f, int screenWidth, int screenHeight, ParticleManager particleManager) this.particleManager = particleManager;
Nu uitați că trebuie să treceți particleManager
în MonkeyBlasterMain
.
Vom introduce aici apelul:
dacă (loc.x screenWidth || loc.y> screenHeight) particleManager.bulletExplosion (loc); spatial.removeFromParent ();
bullet Explozie (poziția Vector3f)
metoda este foarte asemănătoare cu inamicExplosiune (pozitia Vector3f)
metodă. Singurele diferențe sunt că nu vom face particulele la fel de repede și că vom folosi o culoare fixă (un albastru strălucitor). De asemenea, diminuăm durata de viață a particulelor.
public void bullet Explozie (poziția Vector3f) pentru (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);
Deoarece avem toate codurile necesare, este ușor să adăugați noi explozii, după cum puteți vedea. Înainte de a adăuga o altă explozie pentru moartea jucătorilor, vom adăuga o nouă funcție ParticleControl
.
Când un glonț atinge marginea ecranului, aproximativ jumătate din particule sunt inutile. Aceste particule nu apar niciodată pe ecran pentru că zboară departe de ele. Să schimbăm asta.
Vom transforma acum viteza fiecărei particule care iese de pe ecran, astfel încât acestea să fie "respinse" de limitele.
Vector3f loc = spatial.getLocalTranslation (); dacă (loc.x < 0) velocity.x = Math.abs(velocity.x); else if (loc.x > ecranWidth) velocity.x = -Math.abs (viteza.x); dacă (loc.z < 0) velocity.y = Math.abs(velocity.y); else if (loc.y > screenHeight) velocity.y = -Math.abs (viteza.y);
Nu inversăm întreg vectorul, ci doar X
sau y
variabilă (în funcție de limita care a fost lovită). Acest lucru are ca rezultat un efect de respingere corespunzător, ca o oglindă care reflectă lumina.
Bacsis: Nu trebuie să uitați să treceți screenWidth
și screenHeight
din MonkeyBlasterMain
la ParticleManager
și de acolo la fiecare ParticleControl
. Dacă nu vă pasă de codul curat atât de mult ar putea efectuați două variabile statice în MonkeyBlasterMain
și să lucreze cu ei.
Începeți jocul și veți observa că exploziile bulletului arată mult mai strălucitoare acum. Particulele de la explozii inamice devin respinse, de asemenea.
Când jucătorul moare, vrem a într-adevăr explozie mare care acoperă întreg ecranul. Noi numim metoda încă o dată în killPlayer ()
în MonkeyBlasterMain
.
particleManager.playerExplosion (player.getLocalTranslation ());
Codul pentru playerExplosion
este cam la fel ca înainte. Cu toate acestea, de data aceasta folosim două culori, alb și galben, și interpolează între ele. Am stabilit viteza 1000
și durata de viață 2800
milisecunde.
public void playerExplosion (Poziția Vector3f) ColorRGBA color1 = ColorRGBA.White; ColorRGBA color2 = ColorRGBA.Yellow; pentru (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);
Acum, că avem foarte puține efecte particulare, să le adăugăm gravitatea. Ori de câte ori se apropie destul de mult de o gaură neagră, ar trebui să fie aspirați - dar acest lucru nu este valabil pentru fiecare particulă. Mai târziu, vom dori să avem un tip de particule care să fie aspirat și un tip care să nu fie supus. Prin urmare, trebuie să adăugăm un atribut particulelor noastre:
particle.setUserData ("affectedByGravity", adevărat);
Toate tipurile de particule pe care le-am creat până acum ar trebui să fie absorbite de gauri negre, astfel încât să puteți adăuga această linie la fiecare metodă în care am spawn particule.
Acum, la manipularea gravitației. Mergi la handleGravity ()
în MonkeyBlasterMain
-aici am implementat gravitatea în a treia parte a seriei.
De data aceasta, nu vom verifica dacă o particulă este la îndemâna gaurii negre, vom aplica gravitatea tuturor. Dacă o anumită particulă este departe, efectul gravitațional nu va fi oricum foarte puternic.
Verificăm dacă particula este afectată de gravitate și, dacă este, o aplicăm:
// verificați particule pentru (int j = 0; jAcum, va trebui să ne extindem
applyGravity ()
de asemenea:// target.getName () este egal ("Laser") || target.getName () este egal ("Glow")) target.getControl (ParticleControl.class) .applyGravity (gravity.mult ( 15000), distanță);Trebuie să verificăm numele țintă pentru ambele Laser și Strălucire, deoarece acestea sunt două tipuri diferite de particule care vor avea același comportament.
Un alt lucru pe care trebuie să-l observăm este că nu numai că transmitem vectorul gravitațional modificat, dar și distanța față de gaura neagră. Acest lucru este important în calculul forței în
applyGravity ()
înParticleControl
:Vector3f additionalVelocity = gravitate.mult (1000f / (distanță * distanță + 10000f)); velocity.addLocal (additionalVelocity); dacă (distanța < 400) additionalVelocity = new Vector3f(gravity.y, -gravity.x, 0).mult(3f / (distance + 100)); velocity.addLocal(additionalVelocity);Aici,
gravitatie
este vectorul unității care indică spre gaura neagră. Forța atractivă este o versiune modificată a funcției pătrat invers.Prima modificare este că numitorul este
(distanță * distanță) + 10000
-adică, acesta conține un termen pe distanță de pătrat. Acest lucru determină forța atractivă să se apropie de o valoare maximă, în loc să se tindă spre infinit, deoarece distanța devine foarte mică.Atunci când distanța devine mai mare de 100 de pixeli,
(distanță * distanță)
devine rapid mult mai mare decât 10.000. Prin urmare, adăugând 10.000 la(distanță * distanță)
are un efect foarte mic, iar funcția aproximează o funcție pătrată inversă normală.Cu toate acestea, atunci când distanța este mult mai mică de 100 de pixeli, distanța are un efect mic asupra valorii numitorului, iar ecuația devine aproximativ egală cu:
vel + = n;A doua modificare pe care am făcut-o este adăugarea unei componente laterale la viteză atunci când particulele se apropie suficient de gaura neagră. Aceasta are două scopuri: în primul rând, face ca particulele să fie spiralizate în sens orar spre gaura neagră; în al doilea rând, atunci când particulele se apropie destul de mult, vor ajunge la echilibru și vor forma un cerc stralucitor în jurul gaurii negre.
Bacsis: Pentru a roti un vector,v
, 90 ° în sensul acelor de ceasornic, luați(v.y, -v.x)
. În mod similar, pentru a roti 90 ° în sens invers acelor de ceasornic, luați(-v.y, v.x)
.Acest efect de particule pare destul de bun atunci când începeți jocul și priviți-l, și acest lucru este valabil mai ales atunci când există multe explozii și particule în jur. Dar când nu există explozii, găurile negre arata cam plictisitoare. Vom schimba asta în curând.
Pulverizarea particulelor din găurile negre
Pentru a face găurile negre să producă în mod continuu particule, trebuie să aruncăm o privire asupra
controlUpdate (float tpf)
metoda înBlackHoleControl
. Este odacă
declarație care verifică dacă gaura neagră este activă; dacă este, o vom face să execute acest cod:lung sprayDif = System.currentTimeMillis () - lastSprayTime; dacă ((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 = spațial.getLocalTranslation () adăugați (sprayVel.mult (2f)) addLocal (randVec); particleManager.sprayParticle (poziție, sprayVel.mult (30F)); sprayAngle - = FastMath.PI * tpf / 10f;Avem aici câteva variabile noi. Trebuie să declarați și să inițializați
long lastSprayTime
,float spray Angle
siRandal rand
. De asemenea, trebuie să declarațiparticleManager
și o dați jos din clasa principală, astfel încât să putem pulveriza particulele.Metoda va determina gaurile negre să pulverizeze spurturi de particule violete care vor forma un inel stralucitor răcoros care orbitează în jurul găurii negre
Actualul
sprayParticle ()
metoda nu este nimic special. Creați o particulă, aplicați o culoare purpurie, adăugați un control și așa mai departe:public void sprayParticle (Vector3f pozitie, Vector3f sprayVel) Spatial particle = standardParticle.clone (); particle.setLocalTranslation (poziție); Culoare ColorRGBA = ColorRGBA nou (0.8f, 0.4f, 0.8f, 1f); particle.addControl (noul ParticleControl (sprayVel, 3500, culoare, ecran, lățime ecran, ecran de vârf)); particle.setUserData ("affectedByGravity", adevărat); (Nodul) guiNode.getChild ("particule")) attachChild (particule);Porniți jocul și vedeți cum arată.
Bacsis: Dacă doriți să schimbați comportamentul circular al particulelor, nu ezitați să jucați cu valorile din
applyGravity ()
înParticleControl
.Acest lucru îmbunătățește aspectul general al găurilor negre, dar nu este încă destul de bun! Există un alt efect pe care îl putem adăuga la ele ...
Exploziile cu gauri negre
Acum, nu vom face ca găurile negre să explodeze când mor. În schimb, vom declanșa o explozie de particule de fiecare dată când se lovește o gaură neagră.
Adăugați următoarea metodă la
ParticleManager
:public void blackHoleExplosiune (poziția Vector3f) float hue = ((System.currentTimeMillis () - spawnTime) * 0.003f)% 6f; int numParticles = 150; ColorRGBA culoare = hsvToColor (nuanță, 0,25f, 1); flotare startOffset = rand.nextFloat () * FastMath.PI * 2 / numParticles; pentru (int i = 0; iAceasta funcționează în cea mai mare parte în același mod ca și celelalte explozii de particule. O diferență este că alegem nuanța culorii pe baza duratei totale de joc scurs. Dacă trageți gaura neagră de mai multe ori în succesiune rapidă, veți vedea că nuanța exploziilor se rotește treptat. Acest lucru pare mai puțin murdar decât utilizarea culorilor aleatorii, permițând în același timp o variație.
Foc de evacuare a navei
Așa cum este impus de legile fizicii geometrice-neon, nava jucătorului se propulsează prin jettarea unui flux de particule de foc din țeava de eșapament. Cu motorul nostru cu particule în loc, acest efect este ușor de realizat și adaugă fler vizual la mișcarea navei.
Pe măsură ce se deplasează nava, creează trei fluxuri de particule: un curent central care se declanșează direct pe spatele navei și două fluxuri laterale ale căror unghiuri se rotesc înapoi și în raport cu nava. Cele două fluxuri laterale se rotesc în direcții opuse pentru a realiza un model de traversare și au o culoare mai roșie, în timp ce fluxul central are o culoare mai caldă, galben-albă.
Pentru a face ca focul sa straluceasca mai mult decat ar fi de la inflorire, vom avea nava care emite particule suplimentare care arata astfel:
O singură particulă strălucitoare.Aceste particule vor fi colorate și amestecate cu particulele obișnuite. Codul pentru întregul efect este prezentat mai jos:
void public makeExhaustFire (poziția Vector3f, rotație plutitoare) ColorRGBA midColor = noul ColorRGBA (1f, 0.73f, 0.12f, 0.7f); ColorRGBA sideColor = ColorRGBA nou (0,78f, 0,15f, 0,04f, 0,7f); Vector3f direcție = MonkeyBlasterMain.getVectorFromAngle (rotație); flotare t = (System.currentTimeMillis () - spawnTime) / 1000f; Vector3f baseVel = direcție.mult (-45f); Vector3f perpVel = nou Vector3f (baseVel.y, -baseVel.x, 0) .multLocal (2f * FastMath.sin (t * 10f)); Vector3f pos = poziție.add (MonkeyBlasterMain.getVectorFromAngle (rotație) .multLocal (-25f)); // fluxul de mijloc Vector3f randVec = MonkeyBlasterMain.getVectorFromAngle (nou Random (). nextFloat () * FastMath.PI * 2); Vector3f velMid = baseVel.add (randVec.mult (7.5f)); Spațial particulăMid = standardParticle.clone (); particleMid.setLocalTranslation (poz); particleMid.addControl (noul ParticleControl (velMid, 800, midColor, ecranWidth, screenHeight)); particleMid.setUserData ("affectedByGravity", adevărat); (Nodul) guiNode.getChild ("particule")) attachChild (particleMid); Spațial particleMidGlow = glowParticle.clone (); particleMidGlow.setLocalTranslation (poz); particleMidGlow.addControl (noul ParticleControl (velMid, 800, midColor, ecranWidth, screenHeight)); particleMidGlow.setUserData ("affectedByGravity", adevărat); (Nodul) guiNode.getChild ("particule")) attachChild (particleMidGlow); // fluxuri secundare Vector3f randVec1 = MonkeyBlasterMain.getVectorFromAngle (new Random (). nextFloat () * FastMath.PI * 2); Vector3f randVec2 = MonkeyBlasterMain.getVectorFromAngle (nou Random (). NextFloat () * FastMath.PI * 2); Vector3f velSide1 = bazăVel.add (randVec1.mult (2.4f)). AddLocal (perpVel); Vector3f velSide2 = baseVel.add (randVec2.mult (2.4f)) subtractLocal (perpVel); Spatial particleSide1 = standardParticle.clone (); particleSide1.setLocalTranslation (poz); particleSide1.addControl (noul ParticleControl (velSide1, 800, sideColor, lățimea ecranului, screenHeight)); particleSide1.setUserData ("affectedByGravity", true); (Nodul) guiNode.getChild ("particule")) attachChild (particleSide1); Spatial particleSide2 = standardParticle.clone (); particleSide2.setLocalTranslation (poz); particleSide2.addControl (nou ParticleControl (velSide2, 800, sideColor, lățimea ecranului, screenHeight)); particleSide2.setUserData ("affectedByGravity", adevărat); (Nodul) guiNode.getChild ("particule")) attachChild (particleSide2); Spatial particleSide1Glow = glowParticle.clone (); particleSide1Glow.setLocalTranslation (poz); particleSide1Glow.addControl (noul ParticleControl (velSide1, 800, sideColor, lățimea ecranului, screenHeight)); particleSide1Glow.setUserData ("affectedByGravity", adevărat); (Nodul) guiNode.getChild ("particule")) attachChild (particleSide1Glow); Spatial particleSide2Glow = glowParticle.clone (); particleSide2Glow.setLocalTranslation (poz); particleSide2Glow.addControl (noul ParticleControl (velSide2, 800, sideColor, lățimea ecranului, screenHeight)); particleSide2Glow.setUserData ("affectedByGravity", adevărat); (Nodul) guiNode.getChild ("particule")) attachChild (particleSide2Glow);Nu se întâmplă nimic în acest cod. Utilizăm o funcție sinusoidală pentru a produce efectul pivotant în fluxurile laterale prin modificarea vitezei lor lateral în timp. Pentru fiecare flux, se creează două particule suprapuse pe cadru: o particulă standard și o particulă strălucitoare în spatele ei.
Introduceți acest bit de cod în
PlayerControl
, la sfârșitulcontrolUpdate (float tpf)
:dacă (sus || jos || stânga || dreapta) particleManager.makeExhaustFire (spatial.getLocalTranslation (), rotație);Desigur, nu trebuie să uitați să treceți
particleManager
dinMonkeyBlasterMain
.
Concluzie
Cu toate aceste efecte de particule, Shape Blaster începe să arate destul de rece. În partea finală a acestei serii, vom adăuga încă un efect extraordinar: grila de fond de bază