I denne serien av opplæringsprogrammer, viser jeg deg hvordan du lager en neon tvillingpinne shooter, som Geometry Wars, i XNA. Målet med disse opplæringsprogrammene er ikke å forlate deg med en nøyaktig kopi av Geometry Wars, men heller å gå over de nødvendige elementene som vil tillate deg å lage din egen variant av høy kvalitet.
I serien så langt har vi satt opp spillingen og lagt til blomstring. Deretter legger vi til partikkeleffekter.
Advarsel: Høyt!Partikkeleffekter opprettes ved å lage et stort antall små partikler. De er svært allsidige og kan brukes til å legge til flair til nesten hvilket som helst spill. I Shape Blaster vil vi lage eksplosjoner ved hjelp av partikkeleffekter. Vi vil også bruke partikkeleffekter til å skape avgassbrann for spillers skip, og for å legge til visuell flair til de svarte hullene. I tillegg vil vi se på hvordan partikler samhandler med tyngdekraften fra de svarte hullene.
ParticleManager
KlasseVi starter med å opprette en ParticleManager
klasse som vil lagre, oppdatere og tegne alle partiklene. Vi gjør denne klassen generell nok til at den lett kan gjenbrukes i andre prosjekter. Å beholde ParticleManager
Generelt, det vil ikke være ansvarlig for hvordan partiklene ser ut eller beveger seg; Vi håndterer det andre steder.
Partikler har en tendens til å bli skapt og ødelagt raskt og i store mengder. Vi vil bruke en objekt bassenget for å unngå å skape store mengder søppel. Dette betyr at vi vil tildele et stort antall partikler oppe foran, og deretter fortsette å bruke de samme partiklene. Vi vil også gjøre ParticleManager
ha en fast kapasitet. Dette vil forenkle det og bidra til at vi ikke overskrider ytelses- eller minnebegrensninger ved å lage for mange partikler. Når maksimalt antall partikler overskrides, begynner vi å erstatte de eldste partiklene med nye.
Vi skal lage ParticleManager
en generisk klasse. Dette vil tillate oss å lagre egendefinert tilstandsinformasjon for partiklene uten å kode det hardt inn i ParticleManager
seg selv. Vi lager også en nestet partikkel~~POS=TRUNC
klasse.
offentlig klasse ParticleManageroffentlig klasse Partikkel offentlig Texture2D Texture; offentlig Vector2 posisjon; offentlig float Orientering; offentlig Vector2 Scale = Vector2.One; offentlig fargefarge; offentlig flyte Duration; offentlig float PercentLife = 1f; offentlig T-stat;
De partikkel~~POS=TRUNC
Klassen har all den informasjonen som kreves for å vise en partikkel og forvalte levetiden. Den generiske parameteren, T-stat
, er det å holde noen ytterligere data vi kan trenge for våre partikler. Hvilke data som trengs vil variere avhengig av ønskede partikkeleffekter; det kan brukes til å lagre hastighet, akselerasjon, rotasjonshastighet eller alt annet du trenger.
For å hjelpe med å håndtere partiklene trenger vi en klasse som fungerer som en sirkulær matrise, noe som betyr at indekser som normalt vil være utenom grensene, vil i stedet vikle rundt til begynnelsen av arrayet. Dette vil gjøre det enkelt å erstatte de eldste partiklene først hvis vi går tom for plass til nye partikler i vårt utvalg. Vi legger til følgende som en nestet klasse i ParticleManager
.
privat klasse CircularParticleArray private int start; offentlig int Start get return start; sett start = verdi% list.Length; public int Count get; sett; offentlig int Kapasitet get return list.Length; privat partikkel [] liste; offentlig CircularParticleArray (int kapasitet) list = new Particle [capacity]; offentlig Partikkel dette [int i] get returliste [(start + i)% list.Length]; sett liste [(start + i)% list.Length] = verdi;
Vi kan sette Start
egenskap for å justere hvor indeks null i vår CircularParticleArray
tilsvarer i den underliggende gruppen, og Telle
vil bli brukt til å spore hvor mange aktive partikler som er i listen. Vi vil sikre at partikkelen ved indeks null er alltid den eldste partikkelen. Hvis vi erstatter den eldste partikkelen med en ny, vil vi bare øke Start
, som i det vesentlige roterer den sirkulære gruppen.
Nå som vi har våre hjelperklasser, kan vi begynne å fylle ut ParticleManager
klasse. Vi trenger noen medlemsvariabler og en konstruktør.
// Denne delegaten vil bli kalt for hver partikkel. privat handlingupdateParticle; privat CircularParticleArray partikkelliste; offentlig ParticleManager (int kapasitet, Handling updateParticle) this.updateParticle = updateParticle; particleList = ny CircularParticleArray (kapasitet); // Fyll listen med tomme partikkelobjekter, for gjenbruk. for (int i = 0; i < capacity; i++) particleList[i] = new Particle();
Den første variabelen erklært, updateParticle
, vil være en tilpasset metode som oppdaterer partiklene på riktig måte for ønsket effekt. Et spill kan ha flere ParticleManagers
som oppdateres annerledes hvis det er nødvendig. Vi lager også en CircularParticleList
og fyll den med tomme partikler. Konstruktøren er det eneste stedet ParticleManager
tildeler minne.
Neste legger vi til CreateParticle ()
metode som skaper en ny partikkel ved hjelp av neste ubrukt partikkel i bassenget, eller den eldste partikkelen hvis det ikke er ubrukte partikler.
offentlig tomrom CreateParticle (Texture2D tekstur, Vector2 posisjon, Fargetone, flytevarighet, Vector2 skala, T tilstand, float theta = 0) Partikkelpartikkel; hvis (particleList.Count == particleList.Capacity) // hvis listen er full, overskrive den eldste partikkelen, og roter den sirkulære listen partikkel = partikkelliste [0]; particleList.Start ++; else particle = particleList [particleList.Count]; particleList.Count ++; // Lag partikkelpartikkelen. Tekstil = tekstur; partikkel.Posisjon = posisjon; particle.Tint = tint; partikkel.Durasjon = varighet; particle.PercentLife = 1f; partikkel.Skala = skala; partikkel.Orientasjon = theta; particle.State = state;
Partikler kan ødelegges når som helst. Vi må fjerne disse partiklene samtidig som de andre partiklene forblir i samme rekkefølge. Vi kan gjøre dette ved å iterere gjennom listen over partikler mens vi holder styr på hvor mange er blitt ødelagt. Når vi går, beveger vi hver aktiv partikkel foran alle de ødelagte partiklene ved å bytte den med den første ødelagte partikkelen. Når alle ødelagte partiklene er på slutten av listen, deaktiverer vi dem ved å sette listen Telle
variabel til antall aktive partikler. Ødelagte partikler forblir i den underliggende gruppen, men vil ikke bli oppdatert eller tegnet.
ParticleManager.Update ()
håndterer oppdatering av hver partikkel og fjerning av ødelagte partikler fra listen.
offentlig ugyldig oppdatering () int removalCount = 0; for (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;
Den siste tingen å implementere i ParticleManager
tegner partiklene.
offentlig ugyldig tegning (SpriteBatch spriteBatch) for (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
structDen neste tingen å gjøre er å lage en tilpasset klasse eller struktur for å tilpasse hvordan partiklene vil se i Shape Blaster. Det vil være flere forskjellige typer partikler i Shape Blaster som oppfører seg litt annerledes, så vi begynner med å lage en enum
for partikkeltypen. Vi trenger også variabler for partikkelens hastighet og innledende lengde.
offentlig enum ParticleType None, Enemy, Bullet, IgnoreGravity offentlig struktur ParticleState public Vector2 Velocity; offentlig ParticleType Type; offentlig float LengthMultiplier;
Nå er vi klare til å skrive partikkelens oppdateringsmetode. Det er en god ide å gjøre denne metoden rask siden det kan bli kalt for et stort antall partikler.
Vi begynner enkelt. Legg til følgende metode for ParticleState
.
offentlig statisk tomrom UpdateParticle (ParticleManager.Particle particle) var vel = particle.State.Velocity; partikkel.Posisjon + = vel; particle.Orientation = vel.ToAngle (); // denormaliserte flyter forårsaker betydelige ytelsesproblemer hvis (Math.Abs (vel.X) + Math.Abs (vel.Y) < 0.00000000001f) vel = Vector2.Zero; vel *= 0.97f; // particles gradually slow down x.State.Velocity = vel;
Vi kommer tilbake og forbedrer denne metoden på et øyeblikk. La oss først lage partikkeleffekter, slik at vi faktisk kan teste ut endringene våre. I GameRoot
, erklære en ny ParticleManager
og ring det Oppdater()
og Tegne()
fremgangsmåter.
// i GameRoot offentlig statisk ParticleManager ParticleManager get; privat sett; // i GameRoot.Initialize () ParticleManager = ny ParticleManager (1024 * 20, ParticleState.UpdateParticle); // i GameRoot.Update () ParticleManager.Update (); // i GameRoot.Draw () spriteBatch.Begin (SpriteSortMode.Deferred, BlendState.Additive); ParticleManager.Draw (); spriteBatch.End ();
Også, erklære en ny Texture2D
kalt LineParticle
for partikkelens tekstur i Kunst
klasse, og last tekstur som vi gjorde for de andre sprites.
La oss nå få fiender til å eksplodere. Endre Enemy.WasShot ()
metode som følger.
offentlig ugyldig WasShot () IsExpired = true; for (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);
Dette skaper 120 partikler som skyter utover med forskjellige hastigheter i alle retninger. Den tilfeldige hastigheten vektes slik at partikler er mer sannsynlig å bevege seg nær maksimalhastigheten. Dette vil føre til at flere partikler kommer til å ligge i eksplosjonens kant etter hvert som den ekspanderer. Partiklene varer 190 bokser, eller litt over tre sekunder.
Du kan nå kjøre spillet og se på fiender eksplodere. Imidlertid er det fortsatt noen forbedringer som skal gjøres for partikkeleffekter.
Det første problemet er partiklene forsvinner brått når deres varighet løper ut. Det ville være bedre hvis de kunne jevne ut. Men la oss gå litt lenger enn dette og få partiklene til å lyse lysere når de beveger seg raskt. Også, det ser fint ut hvis vi forlenger fortflyttende partikler og forkorter sakte bevegelige seg.
Endre ParticleState.UpdateParticle ()
metode som følger (endringer er uthevet).
offentlig statisk tomrom UpdateParticle (ParticleManager.Particle particle) var vel = particle.State.Velocity; partikkel.Posisjon + = vel; particle.Orientation = vel.ToAngle (); flytehastighet = vel.Length (); float alpha = Math.Min (1, Math.Min (particle.PercentLife * 2, hastighet * 1f)); alfa * = alfa; partikkel.Kolor.A = (byte) (255 * alfa); particle.Scale.X = particle.State.LengthMultiplier * Math.Min (Math.Min (1f, 0.2f * speed + 0.1f), alfa); hvis (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;
Eksplosjonene ser mye bedre ut nå, men de er alle i samme farge. Vi kan gi dem mer variasjon ved å velge tilfeldig farger. En metode for å produsere tilfeldige farger er å velge de røde, blå og grønne komponentene tilfeldig, men dette vil produsere mange kjedelige farger, og vi vil at partiklene våre har et neonlysutseende. Vi kan ha mer kontroll over våre farger ved å spesifisere dem i HSV-fargeplassen. HSV står for fargetone, metning og verdi. Vi ønsker å velge farger med et tilfeldig fargetone, men en fast metning og verdi. Vi trenger en hjelperfunksjon som kan produsere en farge fra HSV-verdier.
statisk klasse ColorUtil offentlig statisk farge HSVToColor (float h, float s, float v) hvis (h == 0 && s == 0) returner ny farge (v, v, v); flyte c = s * v; flyte x = c * (1 - Math.Abs (h% 2 - 1)); flyte m = v - c; hvis (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);
Nå kan vi endre Enemy.WasShot ()
å bruke tilfeldige farger. For å gjøre eksplosjonsfargen mindre ensformig, velger vi to nærliggende nøkkelfarger for hver eksplosjon og linjært interpolerer mellom dem med en tilfeldig mengde for hver partikkel.
offentlig ugyldig WasShot () IsExpired = true; float hue1 = rand.NextFloat (0, 6); float hue2 = (hue1 + rand.NextFloat (0, 2))% 6f; Fargefarge1 = ColorUtil.HSVToColor (hue1, 0.5f, 1); Color color2 = ColorUtil.HSVToColor (hue2, 0.5f, 1); for (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);
Eksplosjonene skal se ut som animasjonen nedenfor.
Du kan leke med fargegenerasjonen som passer dine preferanser. En alternativ teknikk som fungerer bra, er å velge en rekke fargemønstre for eksplosjoner og velge tilfeldig blant dine forhåndsvalgte fargeskjemaer.
Vi kan også få kulene til å eksplodere når de kommer til kanten av skjermen. Vi vil i hovedsak gjøre det samme som vi gjorde for fiendtlige eksplosjoner.
Legg til en statisk Tilfeldig
medlem til Kule
klasse.
privat statisk Random rand = ny tilfeldig ();
Endre deretter Bullet.Update ()
som følger.
// slette kuler som går utenfor skjermen hvis (! GameRoot.Viewport.Bounds.Contains (Position.ToPoint ())) IsExpired = true; for (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 );
Du kan legge merke til at det å gi partiklene en tilfeldig retning er søppelaktig, fordi minst halvparten av partiklene umiddelbart vil gå utenfor skjermen (mer hvis kulen eksploderer i et hjørne). Vi kunne gjøre litt ekstra arbeid for å sikre at partikler bare gis hastigheter motsatt veggen de står overfor. I stedet skjønner vi imidlertid fra Geometry Wars og gjør alle partikler sprette av veggene. Eventuelle partikler som går utenfor skjermen vil bli spurt tilbake.
Legg til følgende linjer til ParticleState.UpdateParticle ()
hvor som helst mellom de første og siste linjene.
var pos = x.Position; int bredde = (int) GameRoot.ScreenSize.X; int høyde = (int) GameRoot.ScreenSize.Y; // kolliderer med kantene på skjermen hvis (pos.X < 0) vel.X = Math.Abs(vel.X); else if (pos.X > bredde) vel.X = -Math.Abs (vel.X); hvis (pos.Y < 0) vel.Y = Math.Abs(vel.Y); else if (pos.Y > høyde) vel.Y = -Math.Abs (vel.Y);
Vi får en virkelig stor eksplosjon når spilleren blir drept. endre PlayerShip.Kill ()
som så:
Offentlig tomrom Kill () framesUntilRespawn = 60; Farge gul = ny Farge (0,8f, 0,8f, 0,4f); for (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);
Dette ligner fiendens eksplosjoner, men vi bruker flere partikler og bruker alltid samme fargevalg. Partikkeltypen er også satt til ParticleType.None
.
I demonstrasjonen sakter partikler fra fiendeeksplosjoner raskere enn partikler fra spillerens skip eksploderer. Dette gjør spillerens eksplosjon siste litt lenger og ser litt mer episk ut.
Nå som vi har partikkeleffekter, la vi gå tilbake til de svarte hullene og få dem til å samhandle med partikler.
Svarte hull bør påvirke partikler i tillegg til andre enheter, så vi må endre ParticleState.UpdateParticle ()
. Legg til følgende linjer.
hvis (x.State.Type! = ParticleType.IgnoreGravity) foreach (var blackHole i EntityManager.BlackHoles) var dPos = blackHole.Position - pos; flyteavstand = dPos.Length (); var n = dPos / avstand; vel + = 10000 * n / (avstand * avstand + 10000); // legge tangentiell akselerasjon for nærliggende partikler hvis (avstand < 400) vel += 45 * new Vector2(n.Y, -n.X) / (distance + 100);
Her, n
er enheten vektoren peker mot det svarte hullet. Den attraktive kraften er en modifisert versjon av den inverse kvadratfunksjonen. Den første modifikasjonen er at nevneren er \ (avstand ^ 2 + 10.000 \). Dette får den attraktive kraften til å nærme seg en maksimumsverdi i stedet for å tippe mot uendelig ettersom avstanden blir svært liten. Når avstanden er mye større enn 100 piksler, blir \ (avstand ^ 2 \) mye større enn 10 000. Derfor legger 10 000 til \ (avstand ^ 2 \) en svært liten effekt, og funksjonen tilnærmer en normal inversfirkantfunksjon. Men når avstanden er mye mindre enn 100 piksler, har avstanden en liten effekt på verdien av nevnen, og ligningen blir omtrent lik:
vel + = n;
Den andre modifikasjonen er å legge en sidelengs komponent til hastigheten når partiklene kommer nær nok til det svarte hullet. Dette tjener to formål. For det første gjør partiklene spiral med urviseren inn mot det svarte hullet. For det andre, når partiklene kommer nær nok, vil de nå likevekt og danne en glødende sirkel rundt det svarte hullet.
Tips: For å rotere en vektor, ta V, 90 ° med klokken, ta(V.Y, -V.X)
. På samme måte, for å rotere 90 ° mot urviseren, ta (-V.Y, V.X)
. Svarte hull vil produsere to typer partikler. Først vil de periodisk sprøyte ut partikler som vil bane rundt dem. For det andre, når et svart hull er skutt, vil det sprøyte ut spesielle partikler som ikke påvirkes av dens tyngdekraft.
Legg til følgende kode i BlackHole.WasShot ()
metode.
float hue = (float) ((3 * GameRoot.GameTime.TotalGameTime.TotalSeconds)% 6); Fargefarge = ColorUtil.HSVToColor (fargetone, 0.25f, 1); const int numParticles = 150; float startOffset = rand.NextFloat (0, MathHelper.TwoPi / numParticles); for (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);
Dette fungerer stort sett på samme måte som de andre partikkeleksplosjonene. En forskjell er at vi velger fargen på fargen basert på totalt forløpt spilletid. Hvis du skyter det svarte hullet flere ganger i rask rekkefølge, vil du se fargen på eksplosjonene gradvis rotere. Dette ser mindre rotete ut enn å bruke tilfeldige farger samtidig som det tillater variasjon.
For den orbitende partikkelsprøyten må vi legge til en variabel til Svart hull
klasse for å spore den retningen som vi for tiden sprøyter partikler på.
privat float sprayAngle = 0;
Legg nå følgende til BlackHole.Update ()
metode.
// De svarte hullene sprayer noen baneformede partikler. Sprøyten skifter av og på hvert kvart sekund. hvis ((GameRoot.GameTime.TotalGameTime.Milliseconds / 250)% 2 == 0) Vector2 sprayVel = MathUtil.FromPolar (sprayAngle, rand.NextFloat (12, 15)); Fargefarge = ColorUtil.HSVToColor (5, 0,5f, 0,8f); // lys lilla Vector2 pos = Posisjon + 2f * ny 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); // roter sprayretningen sprayAngle - = MathHelper.TwoPi / 50f;
Dette vil føre til at de svarte hullene spruter sprut av lilla partikler som danner en kul glødende ring som kretser rundt det svarte hullet, slik som:
Som diktert av lovene i geometrisk-neon fysikk, driver spillers skip seg ved å jette en strøm av brennende partikler ut av eksosrøret. Med vår partikkelmotor på plass, er denne effekten lett å lage og legger til visuell flair til skipets bevegelse.
Når skipet beveger seg, oppretter vi tre strømmer av partikler: en senterstrøm som brenner rett ut på skipets bakside, og to sidestrømmer med vinkler som svinger frem og tilbake i forhold til skipet. De to sidestrømmene svinger i motsatt retning for å lage et kryssovergangsmønster. Sidestrømmene har en rødere farge, mens senterstrømmen har en varmere gul-hvit farge. Animasjonen nedenfor viser effekten.
For å få brannen til å lyse mer lys enn det ville blomstre alene, vil vi få skipet avgir ytterligere partikler som ser slik ut:
Disse partiklene blir tonet og blandet med de vanlige partiklene. Koden for hele effekten er vist nedenfor.
privat tomrom MakeExhaustFire () if (Velocity.LengthSquared ()> 0.1f) // sette opp noen variabler Orientering = Velocity.ToAngle (); Quaternion rot = Quaternion.CreateFromYawPitchRoll (0f, 0f, Orientering); dobbel t = GameRoot.GameTime.TotalGameTime.TotalSeconds; // Partikkelens primære hastighet er 3 piksler / ramme i retning motsatt som skipet reiser. Vector2 baseVel = Velocity.ScaleTo (-3); // Beregn sidelengde for de to sidestrømmene. Retningen er vinkelrett på skipets hastighet og // størrelsen varierer sinusformet. Vector2 perpVel = ny Vector2 (baseVel.Y, -baseVel.X) * (0.6f * (float) Math.Sin (t * 10)); Color sideColor = ny farge (200, 38, 9); // dyprød Farge midColor = ny Farge (255, 187, 30); // oransje-gul Vector2 pos = Posisjon + Vector2.Transform (ny Vector2 (-25, 0), rot); // posisjon av skipets eksosrør. const float alfa = 0,7f; // mellompartikkelstrøm Vector2 velMid = baseVel + rand.NextVector2 (0, 1); GameRoot.ParticleManager.CreateParticle (Art.LineParticle, pos, Color.White * alfa, 60f, ny Vector2 (0.5f, 1), ny ParticleState (velMid, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.Glow, pos, midColor * alfa, 60f, ny Vector2 (0.5f, 1), ny ParticleState (velMid, ParticleType.Enemy)); // sidepartikkelstrømmer 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 * alfa, 60f, ny Vector2 (0.5f, 1), ny ParticleState (vel1, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.LineParticle, pos, Color.White * alfa, 60f, ny Vector2 (0.5f, 1), ny ParticleState (vel2, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.Glow, pos, sideColor * alfa, 60f, ny Vector2 (0.5f, 1), ny ParticleState (vel1, ParticleType.Enemy)); GameRoot.ParticleManager.CreateParticle (Art.Glow, pos, sideColor * alfa, 60f, ny Vector2 (0.5f, 1), ny ParticleState (vel2, ParticleType.Enemy));
Det er ikke noe snø som skjer i denne koden. Vi bruker en sinusfunksjon til å produsere svivelvirkningen i sidestrømmene ved å variere sidelengshastigheten over tid. For hver strøm genererer vi to overlappende partikler per ramme: en halvtransparent-hvit LineParticle
og en farget glødpartikkel bak den. Anrop MakeExhaustFire ()
ved slutten av PlayerShip.Update ()
, umiddelbart før du setter fartøyets hastighet til null.
Med alle disse partikkeleffekter begynner Shape Blaster å se ganske kul ut. I den siste delen av denne serien vil vi legge til en ekstra fantastisk effekt: det klingende bakgrunnsnettet.