I denne opplæringen vil jeg introdusere Stardust Particle Engine. Først skal jeg vise deg hvordan du konfigurerer Stardust, og så skal jeg dekke de grunnleggende Stardust-klassens ansvar og hvordan de samarbeider for å få Stardust til å fungere som en helhet.
Deretter skal vi se på en Stardust generell arbeidsflyt og komme ned for å skape en partikkel-effekt med stjerner som skyter ut fra musemarkøren; stjernene vil sakte gradvis, vokse større etter fødselen, og krympe når de dør.
Til slutt vil jeg demonstrere fleksibiliteten til Stardust ved å skape flere variasjoner fra det allerede komplette eksemplet, inkludert bruk av animerte filmklipp som partikler, variabel partikkel simulering tidsskala og skyting av visningsobjekter av forskjellige klasser fra en enkelt emitter.
Denne veiledningen er ment for folk som allerede er kjent med ActionScript 3.0 objektorientert programmering (OOP), så jeg antar at du allerede vet veldig godt hvilke klasser, objekter, arv og grensesnitt som betyr. Ikke noe problem med OOP? Så la oss skyte noen stjerner!
Som navnet antyder, er Stardust brukt til å skape partikkeleffekter. Hvis du er en erfaren ActionScripter, kan du ha opprettet partikkeleffekter fra grunnen mange ganger, og si "Jeg er helt kul med å skape partikkeleffekter fra grunnen av, så hvorfor ville jeg trenge en partikkelmotor uansett?" Vel, Stardust er her for å hjelpe deg med å fokusere mer på selve partikkeladferddsdesign enn å bekymre deg for de kjedelige underliggende lavnivået, for eksempel minnehåndtering. I stedet for å skrive kode for å ta vare på partikkeldata, initialisere og disponere ressurser, med Stardust, kommer du til å hoppe over disse kjedelige rutinene og bare bestemme hvordan du vil at partiklene skal oppføre deg.
Klassestrukturen til Stardust ble inspirert av FLiNT Particle System, en annen ActionScript 3.0 partikkelmotor. Dermed deler de noen lignende grunnleggende funksjoner.
I tillegg til disse grunnleggende funksjonene tilbyr Stardust flere avanserte funksjoner for erfarne brukere.
Når det gjelder partikkeleffekter, er det svært viktig å håndtere massive partikkeldata effektivt. Stardust gjør stor bruk av objektbassenger og tilknyttede lister for å forbedre ytelsen:
Før vi går ned til selve kodingen, må vi ta en kopi av Stardust Particle Engine. Den er utgitt under MIT-lisens, noe som betyr at den er helt gratis, uansett om du vil bruke den i et kommersielt eller ikke-kommersielt prosjekt.
Her er Stardusts prosjektside: http://code.google.com/p/stardust-particle-engine/
Du kan laste ned Stardust her: http://code.google.com/p/stardust-particle-engine/downloads/list
Når du skriver, kan den nyeste versjonen som lastes ned fra nedlastingslisten, være 1.1.132 Beta. Du kan alltid ta tak i den siste revisjonen fra SVN-depotet (som kanskje ikke er stabilt).
På prosjektets hjemmeside kan du også finne flere tilbehør som API-dokumentasjon og en kopi av PDF-håndboken. Det er enda videoopplæringer på YouTube.
Her skal jeg kortfattet dekke Stardust-kjerneklassene og deres ansvar.
Denne klassen er superklassen til alle kjerneklasser, som definerer egenskaper og metoder spesielt for XML-serialisering.
Vanligvis handler partikkelvirkninger om å kontrollere en mengde enheter med lignende, men randomisert utseende og atferd. Den tilfeldige klassen er for å generere tilfeldige tall, som kan brukes i Stardust for randomisering av partikkelegenskaper. For eksempel er UniformRandom-klassen en underklasse av Random-klassen, og navnet heter alt: det tilfeldige tallet som genereres av et UniformRandom-objekt, er jevnt fordelt, og jeg vil bruke denne klassen spesielt for hele opplæringen.
Det er tider når et endimensjonalt tilfeldig tall ikke er nok. Noen ganger trenger vi todimensjonale tilfeldige tall, som egentlig er par av tilfeldige tall, for egenskaper som posisjon og hastighet. Sone-klassen er for å generere todimensjonale tilfeldige nummerpar. Denne klassen modellerer et tilfeldig talepar som et tilfeldig punkt i en 2D-sone. For eksempel genererer CircleZone tilfeldige nummerpar (x, y) fra tilfeldige punkter i en sirkulær region. Random og Zone klassene brukes hovedsakelig av Initializer-klassen, som dekkes senere. Zone3D-klassen er 3D-motparten av denne klassen, for 3D-partikkeleffekter.
Emitter klassen er i utgangspunktet hvor alle lavt nivå ting er innkapslet. En emitter initierer nyopprettede partikler før de legges til i simuleringen, oppdaterer partikkelegenskaper i hver hovedløkke iterasjon, og fjerner døde partikler fra simuleringen. Metoden Emitter.step () er hva du vil gjenta flere ganger for å holde Stardust oppe og i gang.
Klokke-klassen bestemmer hastigheten på ny partikkelsett for emittere. Én emitterobjekt inneholder nøyaktig en referanse til et klokkeobjekt. Ved begynnelsen av hvert Emitter.step () metodeanrop spør emitteren klokkeobjektet hvor mange nye partikler den skal skape. Ta for eksempel SteadyClock-klassen, det forteller emittere å lage nye partikler med en konstant hastighet.
Denne klassen er for å initialisere nyopprettede partikler. Et Initializer-objekt må legges til en emitter for at den skal fungere. I utgangspunktet initialiserer en Initializer-underklasse bare en partikkelegenskap. For eksempel initierer Mass initialiserer klassen massen av nye partikler. Enkelte initiativer aksepterer et tilfeldig objekt som en konstruktørparameter for initialisering av partikler med randomiserte verdier. Følgende kode oppretter en Life initializer som initierer partikkel liv til verdier sentrert til 50 med variasjon på 10, nemlig mellom området 40 til 60.
nytt liv (nytt UniformRandom (50, 10));
Handlingsobjekter oppdaterer partikkelegenskaper i hver iterasjon av hovedløkken (Emiter.step () -metoden). For eksempel oppdaterer Move-handlingsklassen partikkelposisjoner i henhold til hastighet. Et handlingsobjekt må legges til en emitter for at den skal fungere.
Nå som du vet hvordan kjerneklassene samarbeider sammen, la oss se på en generell arbeidsflyt for Stardust.
Du starter med å lage en emitter. Bruk Emitter2D-klassen til 2D-partikkeleffekter og Emitter3D-klassen for 3D-effekter.
varemitter: Emitter = ny Emitter2D ();
For å spesifisere graden av partikkeloppretting trenger vi en klokke. Dette kan enten settes av Emitter.clock-egenskapen eller ved å sende en klokke som den første parameteren til emitterens konstruktør.
// egenskapstilgang emitter.clock = ny SteadyClock (1); // constructor approach var emitter: Emitter = ny Emitter2D (ny SteadyClock (1));
Legg til initiatorer til emitteren gjennom Emitter.addInitializer () -metoden.
emitter.addInitializer (nytt liv (nytt UniformRandom (50, 10))); emitter.addInitializer (new Scale (new UniformRandom (1, 0.2)));
Legg til handlinger i emitteren gjennom Emitter.addAction () -metoden.
emitter.addAction (ny Flytt ()); emitter.addAction (ny spin ());
Opprett en gjengivelse og legg emitteren til rendereren gjennom metoden Renderer.addEmitter ().
var renderer: Renderer = ny DisplayObjectRenderer (container); // "container" er vår container sprite renderer.addEmitter (emitter);
Til slutt, ring gjentatte ganger Emitter.step () metoden for å holde partikkel simuleringen gå. Du vil kanskje bruke enter-frame-hendelsen eller en timer for å gjøre dette. I en enkelt anrop av Emitter.step () -metoden bestemmer klokken hvor mange nye partikler som skal opprettes, disse nye partiklene initialiseres av initiatorer, alle partikler oppdateres av handlinger, døde partikler fjernes, og til slutt gjør rendereren partikkel-effekten.
// enter-frame-tilnærming tilnærming addEventListener (Event.ENTER_FRAME, mainLoop); // timer tilnærming timer.addEventListener (TimerEvent.TIMER, mainLoop); funksjon mainLoop (e: Event): void emitter.step ();
Ok. Det er stort sett alt for Stardust primer. Nå er det på tide å åpne Flash IDE og få hendene skitne.
Opprett et nytt Flash-dokument med en dimensjon på 640X400, en rammefrekvens på 60 fps, og en mørk bakgrunn. Her laget jeg en mørkblå gradientbakgrunn. Forresten fungerer Stardust godt med både Flash Player 9 og 10, så det er greit uansett om du bruker Flash CS3 eller CS4. I denne opplæringen bruker jeg Flash CS3.
Vi lager en partikkel-effekt med stjerner, så vi må tegne en stjerne og konvertere den til et symbol, eksportert for ActionScript selvfølgelig. Dette symbolet vil bli brukt senere for å gjengi partikkel-effekten. Navn symbolet og den eksporterte klassen "Star".
Opprett en ny dokumentklasse, og navnet den StarParticles.
pakke import flash.display.Sprite; offentlig klasse StarParticles utvider Sprite offentlig funksjon StarParticles ()
Som nevnt i den generelle arbeidsflyten, er det første trinnet å skape en emitter. Og neste trinn er å legge til initiatorer og handlinger til emitteren. Selv om dette kan gjøres i dokumentklassekonstruktøren, anbefaler jeg sterkt at det gjøres i en egen Emitter-underklasse. Det er alltid bedre å skille partikkeladferdelsesdesignet til hovedprogrammet; ved å gjøre det, koden er mye renere og enklere å endre i fremtiden, uten å være blandet opp med hovedprogrammet.
Vi skal lage en 2D partikkel effekt, så Emitter2D er emitter klassen vi skal utvide. Utvid Emitter2D-klassen og navnet den StarEmitter, siden vi skal gjøre det skyte ut stjerner senere. Emitterkonstruenten aksepterer en klokkeparameter, så vi vil erklære en konstruktorparameter for å overføre en klokkeobjektreferanse til superklassens konstruktør.
pakke import idv.cjcat.stardust.twoD.emitters.Emitter2D; offentlig klasse StarEmitter utvider Emitter2D offentlig funksjon StarEmitter (klokke: Klokke) // pass på klokkeobjektet til superklassens superstruktør (klokke);
En bedre tilnærming til å lage en emitter-underklasse er å erklære partikkelparametere som statiske konstanter, gruppert på et enkelt sted. Så hvis du vil tilpasse parametrene, vil du alltid vite hvor du skal finne deklarasjonene. Betydningen av disse konstantene vil bli forklart senere når de brukes.
// gjennomsnittlig levetid privat statisk const LIFE_AVG: Number = 30; // levetid variasjon privat statisk const LIFE_VAR: Number = 10; // gjennomsnittlig skala privat statisk const SCALE_AVG: Number = 1; // skala variasjon privat statisk const SCALE_VAR: Number = 0.4; // skala dyrkingstid privat statisk const GROWING_TIME: Number = 5; // skala krympetid privat statisk const SHRINKING_TIME: Number = 10; // gjennomsnittlig hastighet privat statisk const SPEED_AVG: Number = 10; // hastighetsvariasjon privat statisk const SPEED_VAR: Number = 8; // gjennomsnittlig omega (vinkelhastighet) privat statisk const OMEGA_AVG: Number = 0; // omega variasjon privat statisk const OMEGA_VAR: Number = 5; // dempingskoeffisient privat statisk const DAMPING: Nummer = 0,1;
Hvilke initiatorer trenger vi for å skape vår partikkel effekt? La oss se på listen nedenfor:
Og her er koden:
pek = nytt SinglePoint (); addInitializer (ny DisplayObjectClass (Star)); addInitializer (new Life (new UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (new Scale (new UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (ny posisjon (punkt)); addInitializer (new Velocity (new LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (new Rotation (new UniformRandom (0, 180))); addInitializer (ny Omega (new UniformRandom (OMEGA_AVG, OMEGA_VAR)));
Ok, vi er ferdige med initiativtakerne. Nå er det på tide å legge til handlinger til emitteren. Nedenfor er en liste over handlinger vi trenger:
Det er det. Vår emitter er ferdig. Her er koden for denne emitteren i sin helhet, nødvendige importopplysninger inkludert.
pakke import idv.cjcat.stardust.common.actions.Age; importer idv.cjcat.stardust.common.actions.DeathLife; importer idv.cjcat.stardust.common.actions.ScaleCurve; importer idv.cjcat.stardust.common.clocks.Clock; importer idv.cjcat.stardust.common.initializers.Life; importer idv.cjcat.stardust.common.initializers.Scale; importer idv.cjcat.stardust.common.math.UniformRandom; importere idv.cjcat.stardust.twoD.actions.Damping; importer idv.cjcat.stardust.twoD.actions.Move; importer idv.cjcat.stardust.twoD.actions.Spin; importer idv.cjcat.stardust.twoD.emitters.Emitter2D; importer idv.cjcat.stardust.twoD.initializers.DisplayObjectClass; importer idv.cjcat.stardust.twoD.initializers.Omega; importer idv.cjcat.stardust.twoD.initializers.Position; importer idv.cjcat.stardust.twoD.initializers.Rotation; importer idv.cjcat.stardust.twoD.initializers.Velocity; importer idv.cjcat.stardust.twoD.zones.LazySectorZone; importer idv.cjcat.stardust.twoD.zones.SinglePoint; offentlig klasse StarEmitter strekker Emitter2D / ** * Konstanter * / privat statisk const LIFE_AVG: Number = 30; privat statisk const LIFE_VAR: Number = 10; privat statisk const SCALE_AVG: Number = 1; privat statisk konst SCALE_VAR: Nummer = 0,4; privat statisk const GROWING_TIME: Number = 5; privat statisk const SHRINKING_TIME: Nummer = 10; privat statisk const SPEED_AVG: Number = 10; privat statisk const SPEED_VAR: Number = 8; privat statisk const OMEGA_AVG: Number = 0; privat statisk const OMEGA_VAR: Number = 5; privat statisk const DAMPING: Number = 0.1; offentlig var punkt: SinglePoint; offentlig funksjon StarEmitter (klokke: Klokke) super (klokke); pek = nytt SinglePoint (); // initializers addInitializer (ny DisplayObjectClass (Star)); addInitializer (new Life (new UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (new Scale (new UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (ny posisjon (punkt)); addInitializer (new Velocity (new LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (new Rotation (new UniformRandom (0, 180))); addInitializer (ny Omega (new UniformRandom (OMEGA_AVG, OMEGA_VAR))); // handlinger addAction (new Age ()); addAction (new DeathLife ()); addAction (new Move ()); addAction (ny spin ()); addAction (ny Damping (DAMPING)); addAction (ny ScaleCurve (GROWING_TIME, SHRINKING_TIME));
Nå er det på tide å gå tilbake til dokumentklassen og fullføre den. La oss ta en titt på de gjenværende oppgavene.
Nedenfor er den komplette koden for dokumentklassen, nødvendige importopplysninger inkludert.
pakke import flash.display.Sprite; importer flash.display.StageScaleMode; importere flash.events.Event; importer flash.geom.Rectangle; importer idv.cjcat.stardust.common.clocks.SteadyClock; importer idv.cjcat.stardust.common.renderers.Renderer; importer idv.cjcat.stardust.twoD.renderers.DisplayObjectRenderer; offentlig klasse StarParticles utvider Sprite private var emitter: StarEmitter; offentlig funksjon StarParticles () // instantiate StarEmitter emitter = ny StarEmitter (ny SteadyClock (0.5)); // container sprite var container: Sprite = new Sprite (); // rendereren som gjør partikkel-effekten var renderer: Renderer = ny DisplayObjectRenderer (container); renderer.addEmitter (emitter); // legg beholderen til visningslisten over bakgrunnen addChildAt (container, 1); // gjøre bruk av enter-frame hendelsen addEventListener (Event.ENTER_FRAME, mainLoop); privat funksjon mainLoop (e: Event): void // oppdater SinglePoint posisjonen til musposisjonen emitter.point.x = mouseX; emitter.point.y = mouseY; // ring hovedløkken emitter.step ();
Endelig er vi ferdige! La oss nå se på resultatet. Trykk CTRL + ENTER i Flash for å teste filmen, og du får se resultatet.
Vi er ikke ferdige ennå! La oss gjøre noen flere variasjoner. Den første bruker animerte filmklipp til partiklene våre.
Denne første varianten er ganske enkel, ikke med noen ekstra koding. Det er så enkelt som å lage en grunnleggende tidslinje animasjon. Rediger stjernesymbolet i Flash IDE, opprett en annen nøkkelramme, og endre stjernens farge i denne rammen til rød. Dette fører i hovedsak til at stjernene blinker mellom gul og rød. Du vil kanskje sette inn noen flere tomme rammer mellom, siden en bildefrekvens på 60 fps er for rask til en to-rammes blinkende.
Test nå filmen og sjekk resultatet. Den blinkende stjerneneffekten ser tegneserieaktig ut; Dette kan brukes til klassiske svimmelstjerner, som vanligvis ses i tegneserier.
Som nevnt tidligere, er en av Stardust-funksjonen "justerbar simuleringstidskala", som betyr at tidsskala brukt av Stardust for partikkel-simulering kan justeres dynamisk. Alt gjøres ved å endre egenskapen Emitter.stepTimeInterval, som er 1 som standard. Følgende kodestykke endrer denne verdien til 2, noe som resulterer i at partikler beveger seg dobbelt så fort og emitter oppretter nye partikler med dobbel hastighet.
emitter.stepTimeInterval = 2;
I denne varianten lager vi en skyveknapp på scenen og bruker den til å dynamisk justere simuleringstidskalaen.
Dra en Slider-komponent ut fra komponentpanelet til scenen. Gi det navnet "glidebryteren".
Vi ønsker at glidebryteren skal glide mellom 0,5 og 2, noe som betyr at vi vil at partikkelsimuleringen skal være minst halv så rask som normalt og maksimalt to ganger raskt. Sett også "liveDragging" til ekte slik at vi kan se oppdateringen når vi skrubbe skyveminnet.
Nå må vi lytte til glidebryterens endringshendelse for å dynamisk endre simuleringstidsskalaen. Først importerer du SliderEvent-klassen i dokumentklassen.
importere fl.events.SliderEvent;
Og hør deretter på skyvebryterens endringshendelse i dokumentklassekonstruktøren.
slider.addEventListener (SliderEvent.CHANGE, changeTimescale);
Endre endre simuleringstidskalaen i lytteren. Legg til følgende lytter i dokumentklassen.
privat funksjon changeTimescale (e: SliderEvent): void emitter.stepTimeInterval = slider.value;
La oss se på resultatet. Legg merke til at når du skrubber skyvekontrollens tommel til venstre, reduseres partikkel-simuleringen, og hvis du skrubber til høyre, går simuleringen raskere.
Stardust tilbyr en spesiell initialiserer kalt SwitchInitializer. Konstruktøren godtar to arrays som parametere; den første er en rekke initialiserere, og den andre, med samme lengde som den første, er en rekke "vekter". Hver gang Stardust bruker denne initialisatoren til å initialisere partikler, velges en av initialisatorene i den første gruppen tilfeldig for å initialisere partiklene. Jo mer vekt en initialiserer har, jo mer sannsynlig blir det plukket for initialisering. I denne varianten kommer vi til å få emitteren til å skytes ut, ikke bare stjerner, men også hvite sirkler.
Tegn en hvit sirkel, konverter den til et symbol, eksportert for ActionScript, og merk symbolet og klassen "Sirkel". Dette er klassen vi skal bruke for de hvite sirkler.
Åpne StarEmitter-klassen, og slett den følgende linjen. Dette deaktiverer DisplayObjectClass-initialisereren vi satt opp i de forrige trinnene.
addInitializer (ny DisplayObjectClass (Star));
Legg nå følgende kode til konstruktøren. Vi vil gjerne ha stjerner og sirkler som skal sendes like sannsynlig, så vi gir dem begge en vekt på 1.
// initialiseringen for stjerner var doc1: DisplayObjectClass = ny DisplayObjectClass (Star); // initialisatoren for hvite sirkler var doc2: DisplayObjectClass = ny DisplayObjectClass (Circle); // bryteren initialiseringen var si: SwitchInitializer = ny SwitchInitializer ([doc1, doc2], [1, 1]); // legg til bryteren initialiserer til emitter addInitializer (si);
Til slutt, test filmen. Du kan se både stjerner og sirkler blir sendt ut fra emitteren, se