Manipulerer partikkelbevegelse med Stardust Particle Engine - Del 1

Stardust Particle Engine gir to store tilnærminger til fritt manipulere partikkelbevegelse, nemlig gravitasjonsfelt og deflektorer. Gravitasjonsfelt er vektorfelt som påvirker partikkelens akselerasjon, og deflektorer manipulerer både partikkelens posisjon og hastighet.

Den første delen av denne opplæringen dekker grunnleggende om partikkelbevegelse og gravitasjonsfelt. Dessuten demonstrerer det hvordan du lager dine egne tilpassede gravitasjonsfelter. Den andre delen fokuserer på deflektorer og hvordan man oppretter tilpassede deflektorer.

Forkunnskaper om grunnleggende bruk av Stardust er nødvendig for å fortsette å lese denne opplæringen. Hvis du ikke er kjent med Stardust, kan du sjekke ut min tidligere veiledning om emnet, Skyt ut stjerner med Stardust Particle Engine, før du fortsetter.


Endelig resultatforhåndsvisning

La oss se på det endelige resultatet vi skal jobbe for. Dette er et eksempel på et tilpasset vortex gravitasjonsfelt.


Particle Motion Basics

Det er på tide for litt rask tilbakeringing på videregående skolefysikk. Husk grunnleggende kinematikk? Det handler om forskyvning, noe som bare er en finere måte å si "posisjon" og dens forhold til tid. For omfanget av denne opplæringen trenger vi bare en ganske enkel forståelse av emnet.

Displacement

Forskyvning betyr nåværende posisjon for et objekt. I denne opplæringen er "gjenstandene" vi hovedsakelig arbeider med, partikler i 2D-rom. I 2D-rom representeres forskyvningen av et objekt med en 2D-vektor.

Hastighet

En objekts hastighet angir hvor fort en objekts posisjon endres og retningen for endringen. Hastigheten til en gjenstand i 2D plass er også representert av en 2D vektor. Vektors x- og y-komponenter representerer retningen for posisjonsendringen, og vektorens absolutte verdi angir objektets hastighet, det vil si hvor raskt objektet beveger seg.

Akselerasjon

Accelerasjon er til hastighet som hastigheten er for forskyvning. Akselerasjonen av et objekt angir hvor fort en objektets hastighet endres og retningen for endringen. Akkurat som hastigheten på et objekt i 2D-rom representeres en aksels akselerasjon av en 2D-vektor.


Vector Fields

En annen ting som er verdt å nevne er begrepet vektorfelt. Du kan i utgangspunktet se et vektorfelt som en funksjon som tar en vektor som sin inngang og utdataer en annen vektor. Gravitasjonsfelt er en slags vektorfelt som tar posisjonsvektorer som innganger og utgangsakselerasjonsvektorer. For eksempel, i fysikk simulering, vanligvis en uniform tyngdekraften peker nedover er brukt på alle objekter; i dette tilfellet er gravitasjonsfeltet som representerer tyngdekraften et vektorfelt som utgir en konstant vektor (peker ned), uansett hva inngangspositorene er.

Dette er en visualisert graf av et vektorfelt. Utgangsvektoren til en gitt inngangsvektor (1, 2) er (0,5, 0,5), mens utgangen av en inngang (4, 3) er (-0,5, 0,5).

De Felt klassen i Stardust representerer et 2D vektorfelt, og dets 3D motpart, den Field3D klassen representerer et 3D-vektorfelt. I denne veiledningen fokuserer vi bare på 2D-vektorfelt.

De Field.getMotionData () metoden tar a Particle2D objekt, som inneholder en partikkel 2D-posisjon og hastighetsinformasjon, som parameter. Denne metoden returnerer a MotionData2D objekt, en 2D-vektor "verdiobjekt" som består av x- og y-komponenter. Kombinert med Tyngde handling, a Felt objekt kan brukes som et gravitasjonsfelt, hvis utgang brukes til å manipulere partikkelhastighet.

Det er alt for vår videregående skolefysikk. Nå er det tid for noen virkelige Stardust ting.


Gravity Action

Som tidligere nevnt, Tyngde action klassen benytter seg av Felt gjenstander som gravitasjonsfelt for å manipulere partikkelhastighet. Slik lager du et jevnt vektorfelt, et vektorfelt som returnerer en konstant vektor uansett hvilken inngang er gitt, og bryter den inn i en Tyngde handling.

 // opprett et jevnt vektorfelt som peker nedover (husk positiv y-koordinat betyr "nede" i Flash) var-feltet: Felt = nytt UniformField (0, 1); // lage en tyngdekraft handling var tyngdekraften: Gravity = new Gravity (); // legg til feltet til gravity action gravity.addField (felt);

Dette Tyngde Handlingen er nå klar til bruk på samme måte som alle andre ordinære Stardust-handlinger.

 // legge tyngdekraften til en emittent emitter.addAction (tyngdekraften);

Eksempel: Vindregn

Vi skal skape en blåsig regn effekt ved hjelp av Tyngde handling.


Trinn 1: Grunnregneffekt

Opprett et nytt Flash-dokument, velg en mørk farge for bakgrunn, tegne et regndråpe på scenen, og konverter regndropen til et filmklippssymbol, eksportert for ActionScript med et klassenavn "Regndråpe". Slett regndråpe-forekomsten på scenen etterpå.

Nå skal vi lage en AS-fil for dokumentklassen, og en AS-fil for regndoseren. Jeg vil ikke forklare koden her, siden jeg allerede har dekket den grunnleggende bruken av Stardust i min tidligere opplæring. Hvis du ikke er kjent med Stardust eller trenger litt forfriskning, anbefaler jeg på det sterkeste at du leser min forrige veiledning før du fortsetter.

Dette er dokumentklassen.

 pakke import flash.display. *; importer flash.events. *; importer idv.cjcat.stardust.common.emitters. *; importer idv.cjcat.stardust.common.renderers. *; importer idv.cjcat.stardust.twoD.renderers. *; offentlig klasse WindyRain utvider Sprite private var emitter: Emitter; privat var renderer: Renderer; offentlig funksjon WindyRain () emitter = new RainEmitter (); renderer = ny DisplayObjectRenderer (dette); renderer.addEmitter (emitter); addEventListener (Event.ENTER_FRAME, mainLoop);  privat funksjon mainLoop (e: Event): void emitter.step (); 

Og dette er emitterklassen som brukes i dokumentklassen.

 pakke import idv.cjcat.stardust.common.clocks. *; importer idv.cjcat.stardust.common.initializers. *; importer idv.cjcat.stardust.common.math. *; importer idv.cjcat.stardust.twoD.actions. *; importer idv.cjcat.stardust.twoD.emitters. *; importer idv.cjcat.stardust.twoD.initializers. *; importer idv.cjcat.stardust.twoD.zones. *; offentlig klasse RainEmitter utvider Emitter2D offentlig funksjon RainEmitter () super (new SteadyClock (1)); // initialisatorer addInitializer (ny DisplayObjectClass (regndråpe)); addInitializer (ny posisjon (ny RectZone (-300, -40, 940, 20))); addInitializer (ny hastighet (ny RectZone (-0,5, 2, 1, 3))); addInitializer (new Mass (new UniformRandom (2, 1))); addInitializer (new Scale (new UniformRandom (1, 0.2))); // handlinger addAction (new Move ()); addAction (new Oriented (1, 180)); addAction (ny DeathZone (ny RectZone (-300, -40, 960, 480), true)); 

Dette er hva vår nåværende fremgang ser ut.


Trinn 2: Gjør det vind

Nå skal vi få regnen til å virke blåsende ved å legge til et uniform gravitasjonsfelt som "trekker" regndråpene til høyre. Legg til følgende kode i konstruktøren til RainEmitter klasse.

 // opprett en uniformfelt som alltid returnerer (0.5, 0) var-felt: Felt = nytt UniformField (0,5, 0); // ta hensyn til partikkelmasse field.massless = false; // lage en tyngdekraftshandling og legg til feltet til det var tyngdekraften: Gravity = new Gravity (); gravity.addField (felt); // legge tyngdekraftvirkningen til emitter addAction (tyngdekraften);

Legg merke til at vi satte Field.massless eiendom til falsk, som er sant som standard. Når den er satt til sann, forårsaker denne egenskapen at feltene skal virke som vanlige gravitasjonsfelt, og påvirker alle objekter like uavhengig av deres masse. Men når eiendommen er satt til falsk, tas partikkelmasse i betraktning: partikler med større masse er mindre påvirket av feltet, mens partikler med mindre masse påvirkes mer. Det er derfor vi brukte Masse initialiserer i vår tidligere emitterkode, for å legge til litt tilfeldighet i regneffekten.

Test filmen igjen, og dette er hva vårt utfall ser ut. Regndråper påvirkes nå av et tyngdefelt og er alle "trukket" til høyre.


Eksempel: Turbulens

Nå skal vi bytte ut UniformField gjenstand med a BitmapField objekt, retur vektorfelt basert på bitmap fargekanaler, for å skape en turbulenseffekt. Hvis du har jobbet med ActionScript en stund, kan du forvente å bruke BitmapData.perlinNoise () metode når vi tenker på turbulens, og det er akkurat det vi skal gjøre.

Her ser du hvordan Perlin støybitamap ser ut. Perlin støy er en utmerket algoritme for å generere støy for å simulere turbulens, vannbølge, sky, etc. Du kan finne mer informasjon om Perlin-støy her.

Bitmap-felt

Du lurer kanskje på om vi skal bruke BitmapData.perlinNoise () metode for å generere en perlin støy bitmap, hvordan skal vi bruke denne bitmap som et vektorfelt? Vel, dette er hva BitmapField klassen er for. Det tar en bitmap og konverterer den til et vektorfelt.

La oss si at vi har et punktkartfelt hvis X kanal er satt til rød og Y-kanal er grønn. Dette betyr at når feltet tar en inngangsvektor, si (2, 3), ser den opp til bitmapets piksel på (2, 3) og utgangsvektorens X-komponent bestemmes fra pikselens røde kanal, og Y-komponenten er bestemt fra den grønne kanalen. Når komponentene til en inngangsvektor ikke er heltall, blir de avrundet først.

En fargekanalens verdi varierer fra 0 til 255, 127 er gjennomsnittet. En verdi mindre enn 127 betraktes som negativ av bitmap-feltet, mens en verdi større enn 127 blir tatt positiv. Null er den mest negative tall og 255 er mest positive en. Hvis vi for eksempel har en piksel med en farge 0xFF0000 i heksadesimal representasjon, som betyr en rød kanal med verdi 255 og grønn kanal med 0, vil bitmapfeltets utdata for denne piksel være en vektor med X-komponent av en mest positive mulig tall og Y-komponent av a mest negative mulig nummer, hvor dette mest positive / negative mulige tall, eller maksimalt antall, er spesifikk for bitmap-feltet. For å være mer presis, her er formelen for piksel-til-vektor-konvertering.


Trinn 1: Grunnleggende flygende piler

Lag et nytt Flash-dokument. Tegn en pil på scenen, konverter den til et symbol med navnet "Arrow" og eksporter det til ActionScript.

Opprett en AS-fil for dokumentklassen. Dette er nesten det samme som forrige eksempel.

 pakke import flash.display. *; importer flash.events. *; importer idv.cjcat.stardust.common.emitters. *; importer idv.cjcat.stardust.common.renderers. *; importer idv.cjcat.stardust.twoD.renderers. *; offentlig klasse Turbulens utvider Sprite private var emitter: Emitter; privat var renderer: Renderer; offentlig funksjon Turbulens () emitter = ny ArrowEmitter (); renderer = ny DisplayObjectRenderer (dette); renderer.addEmitter (emitter); addEventListener (Event.ENTER_FRAME, mainLoop);  privat funksjon mainLoop (e: Event): void emitter.step (); 

Opprett en annen AS-fil for vår emitterklasse.

 pakke import idv.cjcat.stardust.common.actions. *; importer idv.cjcat.stardust.common.clocks. *; importer idv.cjcat.stardust.common.initializers. *; importer idv.cjcat.stardust.common.math. *; importer idv.cjcat.stardust.twoD.actions. *; importer idv.cjcat.stardust.twoD.emitters. *; importer idv.cjcat.stardust.twoD.initializers. *; importer idv.cjcat.stardust.twoD.zones. *; offentlig klasse ArrowEmitter strekker Emitter2D offentlig funksjon ArrowEmitter () super (new SteadyClock (1)); // initializers addInitializer (new DisplayObjectClass (Arrow)); addInitializer (new Life (new UniformRandom (50, 10))); addInitializer (ny posisjon (nytt SinglePoint (320, 200))); addInitializer (new Velocity (new LazySectorZone (3, 2))); addInitializer (new Mass (new UniformRandom (2, 1))); addInitializer (new Scale (new UniformRandom (1, 0.2))); // handlinger addAction (new Age ()); addAction (new DeathLife ()); addAction (new Move ()); addAction (new Oriented ()); addAction (ny ScaleCurve (10, 10)); 

Nåværende fremgang ser slik ut.


Trinn 2: Gjør det turbulent

Legg til følgende kode som lager en 640-by-480 Perlin støybitamapdata i emitterkonstruktøren. For detaljerte forklaringer på hver parameter av BitmapData.perlinNoise () metode, kan du referere til denne dokumentasjonen. For å gjøre det enkelt, oppretter følgende kode en Perlin støybitamap med "oktaver" omtrent på størrelse 50X50, og støyen består av røde og grønne fargekanaler.

 // lage en Perlin støy bitmap data var støy: BitmapData = ny BitmapData (640, 400); noise.perlinNoise (50, 50, 1, 0, true, true, 1 | 2);

Deretter oppretter du en BitmapField objekt og tilordne bitmapdataene til den gjennom Oppdater() metode. Så resten av koden vedrørende Tyngde Handlingen er nøyaktig den samme som forrige eksempel.

 // opprett en uniformfelt som alltid returnerer (0,5, 0) var-felt: BitmapField = nytt BitmapField (); field.channelX = 1; // sett X kanal til rødt field.channelY = 2; // sett Y-kanal til grønt felt.max = 1; // angi maksimal vektorkomponent absolutt verdi field.update (støy); // oppdatere feltet med støybitemappen // ta del i partikkelmasse field.massless = false; // lage en tyngdekraftshandling og legg til feltet til det var tyngdekraften: Gravity = new Gravity (); gravity.addField (felt); // legge tyngdekraftvirkningen til emitter addAction (tyngdekraften);

Test nå filmen igjen, og du skal se at våre flyvende piler opplever turbulens.


Egendefinerte felt

Vi har brukt UniformField og BitmapField levert av Stardust, og nå skal vi lage våre egne tilpassede felt ved å utvide Felt klasse og overstyrer getMotionData2D () metode.

De getMotionData2D tar a Particle2D parameter som input, som inneholder partikkelposisjonens vektorinformasjon, og det er inngangen til feltet. Metoden returnerer a MotionData2D objekt, som representerer utgangen av feltet. Det er alt du trenger å vite for å lage et egendefinert felt. La oss lage et egendefinert virvelfelt.

Nedenfor er den visualiserte grafen for vårt virvelfelt. Det er ganske selvforklarende hvorfor det kalles et virvelfelt.

Her er formelen for vårt virvelfelt.

Og vortexfeltklasse er like enkelt som koden nedenfor. Vi har gjort bruk av Vec2D klasse for å gjøre alt det skitne arbeidet med å rotere en vektor med 90 grader med klokken og sette vektorens absolutte verdi. Deretter dumper vi vektorens x- og y-komponenter inn i en MotionData2D objekt, som er av gjenstandstypen som skal returneres.

 pakke import idv.cjcat.stardust.twoD.fields. *; importer idv.cjcat.stardust.twoD.geom. *; importer idv.cjcat.stardust.twoD.particles. *; offentlig klasse VortexField utvider felt public var centerX: Number; offentlig var sentrumY: Nummer; offentlig var styrke: tall; offentlig funksjon VortexField (centerX: Nummer = 0, centerY: Nummer = 0, styrke: Nummer = 1) this.centerX = centerX; this.centerY = centerY; this.strength = styrke;  overstyre beskyttet funksjon calculateMotionData2D (partikkel: Particle2D): MotionData2D var dx: Number = particle.x - centerX; var dy: Nummer = partikkel.y - centerY; var vec: Vec2D = ny Vec2D (dx, dy); vec.length = styrke; vec.rotateThis (90); returner ny MotionData2D (vec.x, vec.y); 

Nå som vi har vårt tilpassede felt, la oss teste det ut i følgende eksempel.


Eksempel: Vortex

Dette eksemplet fungerer som en teststasjon for vårt vortexvektorfelt. Det er like enkelt som å bytte et felt med en ny. Endre følgende kode fra det forrige eksempelet fra dette

 // opprett en uniformfelt som alltid returnerer (0,5, 0) var-felt: BitmapField = nytt BitmapField (); field.channelX = 1; // sett X kanal til rødt field.channelY = 2; // sett Y-kanal til grønt felt.max = 1; // angi maks vecotr lengde field.update (støy); // Oppdater feltet med støybitemappen

til dette

 // lage et virvelfelt sentrert på (320, 200) med styrke 1 var-felt: VortexField = nytt VortexField (); field.centerX = 320; field.centerY = 200; field.strength = 1;

Og vi er ferdige. Du kan teste filmen og se virvel effekten. Søt!


Konklusjon

Du har sett hvordan du bruker Tyngde handling og Felt klasse for å påvirke partikkelhastigheten. Og du har lært hvordan du lager dine egne tilpassede vektorfelt som skal brukes som gravitasjonsfelt. Den neste delen av denne opplæringen vil vise deg hvordan du kan bruke deflektorene til å manipulere både partikkelposisjon og hastighet på en gang.

Tusen takk for lesing!