Shoot Out Stars met de Stardust Particle Engine

In deze tutorial zal ik de Stardust deeltjesmotor introduceren. Eerst zal ik je laten zien hoe je Stardust opzet, en dan zal ik de basisverantwoordelijkheden van Stardust class bespreken en hoe ze samenwerken om Stardust als een geheel te laten werken.

Vervolgens zullen we kijken naar de algemene workflow van een Stardust en gaan werken aan het creëren van een partikeleffect met sterren die uit de muiscursor schieten; de sterren vertragen geleidelijk, worden groter na de geboorte en krimpen bij het sterven.

Ten slotte zal ik de flexibiliteit van Stardust demonstreren door verschillende variaties van het al complete voorbeeld te maken, waaronder het gebruik van geanimeerde filmclips als deeltjes, tijdsschaal met variabele deeltjessimulatie en het afschieten van weergaveobjecten van verschillende klassen van een enkele zender.

Deze zelfstudie is bedoeld voor mensen die al bekend zijn met ActionScript 3.0-objectgeoriënteerd programmeren (OOP), dus ik ga ervan uit dat je al heel goed weet wat klassen, objecten, overerving en interface betekenen. Geen probleem met OOP? Laten we dan een paar sterren gaan schieten!




Stardust deeltjesmotor

Zoals de naam doet vermoeden, wordt Stardust gebruikt voor het creëren van deeltjeseffecten. Als je een ervaren ActionScripter bent, kun je vaak partikelingeffecten van de grond af hebben gemaakt en zeggen "Ik ben helemaal cool met het helemaal opnieuw creëren van deeltjeseffecten, dus waarom zou ik toch een deeltjesmotor nodig hebben?" Welnu, Stardust is er om u te helpen meer te focussen op daadwerkelijk ontwerp van deeltjesgedrag dan u zorgen te maken over de vervelende onderliggende dingen op een laag niveau, zoals geheugenbeheer. In plaats van code te schrijven voor het verwerken van deeltjesgegevens, het initialiseren en verwijderen van bronnen, met Stardust, sla je deze saaie routines over en beslis gewoon hoe je wilt dat je deeltjes zich gedragen.

Stardust-kenmerken

De klassenstructuur van Stardust werd geïnspireerd door FLiNT Particle System, een andere ActionScript 3.0-deeltjesmotor. Daarom delen ze enkele vergelijkbare basisfuncties.

  • 2D- en 3D-deeltjeseffecten - Stardust kan worden gebruikt om zowel 2D- als 3D-deeltjeseffecten te creëren. Het heeft een eigen ingebouwde 3D-engine en het kan ook worden gebruikt om te werken in combinatie met andere driedelige 3D-engines, waaronder ZedBox, Papervision3D en ND3D.
  • Hoge uitrekbaarheid - Stardust biedt een groot aantal deeltjesgedrag en renderers tot uw beschikking. Als geen van deze voldoet aan uw behoeften, kunt u altijd de basisklassen uitbreiden en uw eigen gedrag op basis van partikels creëren; U kunt ook uw eigen renderer maken om met een andere 3D-engine te werken die niet door Stardust wordt ondersteund.

Naast deze basisfuncties biedt Stardust ook verschillende geavanceerde functies voor ervaren gebruikers.

  • Verstelbare simulatie tijdschaal - De tijdschaal die wordt gebruikt voor deeltjessimulatie kan tijdens de looptijd dynamisch worden aangepast. Als u bijvoorbeeld de tijdschaal wijzigt in de helft van het origineel, zal het partikeleffect half zo snel zijn als de normale snelheid; en als u de tijdschaal aan tweemaal het origineel aanpast, zal het deeltjeseffect tweemaal zo snel als normaal worden gesimuleerd. Deze functie kan handig zijn als je een spel maakt met slow-motioneffecten: het partikeleffect kan langzamer worden aangepast aan de snelheid van je game-engine, en kan worden gesynchroniseerd met je game-animatie en graphics.
  • XML-serialisatie - U kunt uw particle systeem transformeren in een bestand in XML-formaat dat kan worden opgeslagen op uw harde schijf, later geladen tijdens runtime en geïnterpreteerd om uw orignal particle systeem te reconstrueren. Dit is erg handig wanneer u met een groot project werkt. Stel dat u uw deeltjes een klein beetje wilt vergroten, zodat u de parameters in de broncode aanpast en uw volledige Flash-toepassing opnieuw compileert, wat een minuut kan duren, of zelfs meer dan vijf minuten als uw project extreem groot is. Is het de moeite waard? Absoluut nee. Dat is een totale verspilling van tijd. Met behulp van de XML-serialisatiefunctie om uw particle systeem in externe XML-bestanden op te slaan, scheidt u parameters van de broncode voor de hoofdtoepassing. U hoeft dus alleen het XML-bestand te openen, de parameterwaarden te wijzigen, op te slaan en uw hoofdtoepassing opnieuw te openen. Dat is het! Er is helemaal geen recompilatie nodig. Ik zou zeggen dat dit de ideale manier is om met grote projecten te werken.

Als het gaat om deeltjeseffecten, is het erg belangrijk om massieve deeltjesgegevens efficiënt te verwerken. Stardust maakt zwaar gebruik van objectgroepen en gekoppelde lijsten om de prestaties te verbeteren:

  • Objectpools - Gebruikte objecten worden opgeslagen in een pool; later, als een object van hetzelfde type vereist is, start Stardust het niet meteen op, maar controleert het of er eerder een object in de objectgroep is opgeslagen. Zo ja, dan haalt Stardust eenvoudig dat object eruit en gebruikt het, in plaats van een geheel nieuw object te maken. Gewoonlijk hebben deeltjeseffecten te maken met veel object-instantiatie, wat CPU-verbruiken is. Door objectpools te gebruiken, vermindert Stardust de instantiation-overhead aanzienlijk.
  • Gekoppelde lijsten - Het is heel gemakkelijk en verleidelijk om deeltjesgegevens op te slaan in een array; In een geval waarin deeltjes zeer vaak worden gemaakt en verwijderd, vindt er echter veel array-koppeling plaats om dode deeltjes te verwijderen. Array-splitsing is een CPU-verterend proces, vooral voor lange arrays. Voor een gelinkte lijst, ongeacht hoe lang de lijst is, duurt het altijd even kort om dode deeltjes te splitsen. Vanaf versie 1.1 begon Stardust intern gekoppelde lijsten te gebruiken om deeltjesgegevens op te slaan.

Stardust instellen

Voordat we echt kunnen coderen, moeten we een kopie van Stardust Particle Engine nemen. Het is vrijgegeven onder MIT-licentie, wat betekent dat het volledig gratis is, ongeacht of u het in een commercieel of niet-commercieel project wilt gebruiken.

Dit is de startpagina van de Stardust: http://code.google.com/p/stardust-particle-engine/

U kunt Stardust hier downloaden: http://code.google.com/p/stardust-particle-engine/downloads/list

Op het moment van schrijven is de nieuwste versie die kan worden gedownload van de downloadlijst 1.1.132 Beta. Je kunt altijd de laatste revisie pakken uit de SVN-repository (die misschien niet stabiel is).

Op de startpagina van het project vindt u ook meer accessoires zoals API-documentatie en een PDF-handleiding. Er zijn zelfs videotutorials op YouTube.

Stardust Class Verantwoordelijkheden

Hier ga ik kort ingaan op de kernklassen van Stardust en hun verantwoordelijkheden.

StardustElement

Deze klasse is de superklasse van alle hoofdklassen, die eigenschappen en methoden definieert, met name voor XML-serialisatie.

Willekeurig

Over het algemeen gaat het bij deeltjeseffecten om het beheersen van een hoeveelheid entiteiten met een vergelijkbare maar gerandomiseerde verschijning en gedrag. De Random-klasse is voor het genereren van willekeurige getallen, die in Stardust kunnen worden gebruikt voor het randomiseren van deeltjeseigenschappen. De UniformRandom-klasse is bijvoorbeeld een subklasse van de klasse Random en de naam zegt alles: het willekeurige nummer dat door een UniformRandom-object wordt gegenereerd, wordt uniform verspreid en ik zal deze klasse in het bijzonder gebruiken voor de hele tutorial.

Zone

Er zijn tijden dat een eendimensionaal willekeurig getal niet genoeg is. Soms hebben we tweedimensionale willekeurige getallen nodig, die in wezen paren van willekeurige getallen zijn, voor eigenschappen zoals positie en snelheid. De zoneklasse is voor het genereren van tweedimensionale willekeurige nummerparen. Deze klasse modelleert een willekeurig getalpaar als een willekeurig punt in een 2D-zone. De CircleZone genereert bijvoorbeeld willekeurige nummerparen (x, y) van willekeurige punten in een cirkelvormig gebied. De klassen Random en Zone worden hoofdzakelijk gebruikt door de klasse Initializer, die later worden behandeld. De Zone3D-klasse is de 3D-tegenhanger van deze klasse, voor 3D-deeltjeseffecten.

Emitter

De klasse Emitter is eigenlijk waar alle low-level dingen ingekapseld zijn. Een emitter initialiseert nieuw gecreëerde deeltjes voordat ze worden toegevoegd aan de simulatie, werkt deeltjeseigenschappen bij in elke hoofdlus-iteratie en verwijdert dode deeltjes uit de simulatie. De methode Emitter.step () is wat u herhaaldelijk wilt aanroepen om Stardust in de lucht te houden.

Klok

De klokklasse bepaalt de snelheid waarmee nieuwe deeltjes worden aangemaakt voor emitters. Eén emitter-object bevat precies één verwijzing naar een Clock-object. Aan het begin van elke methode-aanroep van de methode Emitter.step () vraagt ​​de emitter aan het object van de klok hoeveel nieuwe deeltjes het moet maken. Neem bijvoorbeeld de SteadyClock-klasse, het vertelt emitters om nieuwe deeltjes met een constante snelheid te creëren.

initializer

Deze klasse is voor het initialiseren van nieuw gemaakte deeltjes. Een Initializer-object moet aan een emitter worden toegevoegd om te kunnen werken. Kort gezegd initialiseert een Initializer-subklasse slechts één deeltjeseigenschap. De initialisatieklasse van Mass initialiseert bijvoorbeeld de massa nieuwe deeltjes. Sommige initializers accepteren een willekeurig object als een constructorparameter voor het initialiseren van deeltjes met willekeurige waarden. De volgende code creëert een Life-initialisator die deeltijdlevens initialiseert naar waarden gecentreerd op 50 met een variatie van 10, namelijk tussen het bereik van 40 tot 60.

 nieuw leven (nieuwe UniformRandom (50, 10));

Actie

Actieobjecten bijwerken deeltjeseigenschappen in elke iteratie van de hoofdlus (de methode Emiter.step ()). Met de actieklasse Move worden bijvoorbeeld de deeltjesposities volgens de snelheid bijgewerkt. Een Action-object moet aan een emitter worden toegevoegd om te kunnen werken.

Algemene Stardust-workflow

Nu je weet hoe de kernklassen samenwerken, laten we eens kijken naar een algemene workflow voor Stardust.

U begint met het maken van een emitter. Gebruik de klasse Emitter2D voor 2D-deeltjeseffecten en de klasse Emitter3D voor 3D-effecten.

 var emitter: Emitter = nieuwe Emitter2D ();

Om de snelheid van het aanmaken van deeltjes te specificeren, hebben we een klok nodig. Dit kan worden ingesteld door de eigenschap Emitter.clock of door een klok door te geven als de eerste parameter voor de constructor van de emitter.

 // property approach emitter.clock = new SteadyClock (1); // constructor-aanpak var-emitter: Emitter = nieuwe Emitter2D (nieuwe SteadyClock (1));

Voeg initializers toe aan de emitter via de methode Emitter.addInitializer ().

 emitter.addInitializer (nieuw leven (nieuwe UniformRandom (50, 10))); emitter.addInitializer (nieuwe schaal (nieuwe UniformRandom (1, 0.2)));

Acties aan de emitter toevoegen via de methode Emitter.addAction ().

 emitter.addAction (nieuwe verplaatsing ()); emitter.addAction (nieuwe Spin ());

Maak een renderer en voeg de emitter toe aan de renderer via de methode Renderer.addEmitter ().

 var renderer: Renderer = nieuw DisplayObjectRenderer (container); // "container" is onze containersprite renderer.addEmitter (emitter);

Tot slot roept u herhaaldelijk de methode Emitter.step () op om de deeltjessimulatie in stand te houden. Misschien wil je de enter-frame-gebeurtenis of een timer gebruiken om dit te doen. In een enkele aanroep van de methode Emitter.step () bepaalt de klok hoeveel nieuwe deeltjes moeten worden gemaakt, deze nieuwe deeltjes worden geïnitialiseerd door initializers, alle deeltjes worden bijgewerkt door acties, dode deeltjes worden verwijderd en ten slotte rendert de renderer het partikeleffect.

 // enter-frame event-aanpak addEventListener (Event.ENTER_FRAME, mainLoop); // timer approach timer.addEventListener (TimerEvent.TIMER, mainLoop); function mainLoop (e: Event): void emitter.step (); 

Alright. Dat is vrijwel alles voor de Stardust-primer. Nu is het tijd om de Flash IDE te openen en je handen vuil te maken.

Stap 1: Maak een nieuw Flash-document

Maak een nieuw Flash-document met een dimensie van 640x400 een framesnelheid van 60 fps en een donkere achtergrond. Hier heb ik een donkerblauwe gradient achtergrond gemaakt. Trouwens, Stardust werkt goed met zowel Flash Player 9 als 10, dus het is goed, ongeacht of je Flash CS3 of CS4 gebruikt. In deze tutorial gebruik ik Flash CS3.

Stap 2: teken een ster

We maken een partikeleffect met sterren, dus we moeten een ster tekenen en deze omzetten in een symbool, uiteraard geëxporteerd voor ActionScript. Dit symbool zal later worden gebruikt om ons partikeleffect te maken. Geef het symbool een naam en de geëxporteerde klasse "Star".

Stap 3: Maak de documentklasse

Maak een nieuwe documentklasse en noem deze StarParticles.

 pakket import flash.display.Sprite; public class StarParticles breidt uit met Sprite openbare functie StarParticles () 

Stap 4: Verleng de zender

Zoals vermeld in de algemene workflow, is de eerste stap het maken van een emitter. En de volgende stap is het toevoegen van initializers en acties aan de zender. Hoewel dit kan worden gedaan in de constructor van de documentklasse, raad ik u ten zeerste aan om dit in een afzonderlijke subklasse Emitter te doen. Het is altijd beter om het ontwerp van het deeltjesgedrag van het hoofdprogramma te scheiden; hierdoor is de code in de toekomst veel schoner en gemakkelijker aan te passen, zonder in de war te raken met het hoofdprogramma.

We gaan een 2D-deeltjeseffect creëren, dus de Emitter2D is de emitterklasse die we gaan uitbreiden. Breid de klasse Emitter2D uit en noem hem StarEmitter, want we gaan het later op sterren laten schieten. De Emitter-constructor accepteert een Clock-parameter, dus we zullen een constructorfactor declareren om een ​​Clock-objectreferentie door te geven aan de constructor van de superklasse.

 pakket import idv.cjcat.stardust.twoD.emitters.Emitter2D; openbare klasse StarEmitter breidt Emitter2D uit openbare functie StarEmitter (klok: klok) // geeft het klokobject door aan de constructorsuper van de superklasse (klok); 

Stap 5: constanten bekend maken

Een betere benadering om een ​​emittersubklasse te maken, is om deeltjeparameters te verklaren als statische constanten, gegroepeerd op één plaats. Dus als u de parameters wilt aanpassen, weet u altijd waar u de aangiften kunt vinden. De betekenis van deze constanten zal later worden uitgelegd wanneer ze worden gebruikt.

 // gemiddelde levensduur persoonlijke statische const LIFE_AVG: Number = 30; // levensduur variantie privé statische const LIFE_VAR: Number = 10; // average scale private static const SCALE_AVG: Number = 1; // schaalvariatie private static const SCALE_VAR: Number = 0.4; // scale growing time private static const GROWING_TIME: Number = 5; // schaal inkrimpingstijd private static const SHRINKING_TIME: Number = 10; // gemiddelde snelheid private static const SPEED_AVG: Number = 10; // snelheidsvariatie private static const SPEED_VAR: Number = 8; // gemiddelde omega (hoeksnelheid) privé-statische const OMEGA_AVG: Number = 0; // omegavariatie private static const OMEGA_VAR: Number = 5; // dempingscoëfficiënt privé statische const DAMPING: aantal = 0,1;

Stap 6: Initializers toevoegen

Welke initializers hebben we nodig om ons partikeleffect te creëren? Laten we de onderstaande lijst eens bekijken:

  • DisplayObjectClass - Met deze initialisator wordt aan elk deeltje een opgegeven weergaveobject toegewezen, dat door een DisplayObjectRenderer wordt gebruikt om partikeleffecten weer te geven. De constructor accepteert een klasseverwijzing naar de weergaveobjectklasse die we willen instantiëren; voor deze zelfstudie is deze klasse de sterklasse (symbool) die we in stap 2 hebben gemaakt.
  • Leven - Deze initializer wijst elk deeltje een willekeurige levenswaarde toe. Later zullen we acties aan de emittent toevoegen om deze levenswaarde door de tijd uit te putten en een deeltje als dood te markeren als de levenswaarde nul bereikt. Een willekeurig object wordt doorgegeven aan de constructor, die door deze initialisator wordt gebruikt om willekeurige waarde te genereren voor de levensduur van deeltjes. In de meeste gevallen is de UniformRandom-klasse handig en voldoende; de eerste parameter van de UniformRandom-constructor is de middelste (of gemiddelde) waarde van de gegenereerde willekeurige getallen, en de tweede is de straal (of variatie). Een UniformRandom-object met middelpunt 20 en variant 5 genereren willekeurige getallen binnen het bereik [15, 25]. Hier gebruiken we de constante LIFE_AVG voor de middelste waarde en LIFE_VAR voor de straal.
  • Schaal - Net als de Life-initialisator initialiseert de schaalinitialisator de schaal van een deeltje tot een willekeurige waarde, bepaald door een willekeurig object dat wordt doorgegeven aan de constructor van de initialisatie. Hier gebruiken we de constante SCALE_AVG voor de middelste waarde en SCALE_VAR voor de straal.
  • Positie - Deze initializer wijst een deeltje een willekeurige positie toe. In tegenstelling tot de initializers Life and Scale, die slechts 1D willekeurige getallen nodig hebben, vereist de Initializer van de Positie 2D-generatoren voor willekeurige nummerparen. Zoals beschreven in het gedeelte Stardust Class Verantwoordelijkheden, is de klasse Zone precies voor dit doel. Het Zone-object dat wordt doorgegeven aan de constructor van de initialisatie wordt gebruikt om 2D-willekeurige-nummerparen te genereren, die aan deeltjes worden toegewezen als positievectoren. In deze zelfstudie gaan we sterren laten schieten vanaf een enkel punt bij de muiscursor, dus we zullen een SinglePoint-klasse gebruiken, die een zonesubklasse is. Om de coördinaat van dit SinglePoint-object dynamisch aan te passen vanuit de documentklasse, moeten we een verwijzing naar dit puntobject openbaar maken via een openbare eigenschap. Dit is waar de "punt" -eigenschap voor is.
  • Snelheid - Gelijk aan de Position-initialisator, heeft de Velocity-initialisator een Zone-object nodig om 2D-willekeurige-waardeparen te genereren om de deeltjessnelheden te initialiseren. Een 2D-vector gegenereerd door het Zone-object, dat de coördinaat is van een willekeurig punt in de zone, wordt toegewezen aan deeltjes als hun snelheden. Hier gebruiken we de klasse LazySectorZone die een sectorregio vertegenwoordigt. Een sector is een deel van een cirkel omsloten door twee radii en twee hoeken. Voor de LazySectorZone zijn de twee hoeken standaard 0 en 360, wat een volledige hoek rondom een ​​cirkel vertegenwoordigt. De eerste constructorfactor van de LazySectorZone-klasse is het gemiddelde van de twee radii, en de tweede is de variatie van de radii. In dit geval vertegenwoordigt het gemiddelde van de twee radii de gemiddelde snelheid en vertegenwoordigt de variatie van radii de snelheidsvariatie. Hier gebruiken we de constante SPEED_AVG voor de eerste parameter en SPEED_VAR voor de tweede.
  • omwenteling - De Rotatie-initialisator initialiseert de rotatiehoek van een deeltje naar een willekeurige waarde. En zoals sommige van de bovengenoemde initializers, accepteert de constructor een willekeurig object om een ​​willekeurige waarde te genereren. Omdat we deeltjes met hoeken van 0 tot 360 graden willen hebben, gebruiken we 0 als middelpunt en 180 als de straal van het UniformRandom-object.
  • Omega - Omega betekent, zoals in de meeste natuurkundeboeken, hoeksnelheid. Met dat gezegd, het doel van deze initializer is duidelijk: het initialiseert de hoeksnelheid van een deeltje naar een willekeurige waarde, en de OMEGA_AVG constante wordt gebruikt als het centrum en OMEGA_VAR als de straal van het UniformRandom object.

En hier is de code:

 punt = nieuw SinglePoint (); addInitializer (nieuwe DisplayObjectClass (Star)); addInitializer (nieuwe Life (nieuwe UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (nieuwe schaal (nieuwe UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (nieuwe positie (punt)); addInitializer (nieuwe Velocity (nieuwe LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (nieuwe rotatie (nieuwe UniformRandom (0, 180))); addInitializer (nieuwe Omega (nieuwe UniformRandom (OMEGA_AVG, OMEGA_VAR)));

Stap 7: Acties toevoegen

Oké, we zijn klaar met de initializers. Nu is het tijd om acties aan de zender toe te voegen. Hieronder volgt een lijst met acties die we nodig hebben:

  • Leeftijd - De Age-actie verlaagt de levensduurwaarde van een deeltje met 1 in elke emitterstap.
  • Dood leven - Wanneer de levenswaarde van een deeltje nul bereikt, markeert deze actie het deeltje als dood en verandert de eigenschap isDead van false in true. Aan het einde van een emitterstap worden dode deeltjes verwijderd.
  • verhuizing - Zoals de naam doet vermoeden, werkt de Move-actie deeltjesposities bij overeenkomstig hun snelheden.
  • spinnen - Vergelijkbaar met de actie Verplaatsen, werkt de Spin-actie de rotatiehoek van een deeltje bij volgens de omega-waarde van het deeltje (hoeksnelheid).
  • Demping - Deze actie vermenigvuldigt de veloctiy van een deeltje met een factor binnen het bereik [0, 1], waarbij de dempingseffecten worden gesimuleerd en het deeltje geleidelijk wordt vertraagd. Een factor één betekent helemaal geen demping: deeltjes bewegen vrij alsof er geen dempingseffect is; een factor nul betekent totale demping: alle deeltjes kunnen niet een beetje bewegen. Deze factor wordt bepaald door de "dempingscoëfficiënt" door deze formule: "factor = 1 - (dempingscoëfficiënt)". De parameter die aan de constructor wordt doorgegeven, is de dempingscoëfficiënt; hier willen we alleen een beetje dempingseffect, dus gebruiken we de waarde 0.1 voor de coëfficiënt.
  • ScaleCurve - De ScaleCurve-actie wijzigt de schaal van een deeltje op basis van de levenswaarde. Het groeit van een initiële schaal naar een normale schaal na de geboorte en verdwijnt naar een uiteindelijke schaal als het sterft. Natuurlijk kan een deeltje ook een initiële of uiteindelijke schaalwaarde hebben die groter is dan de normale schaal; het hangt gewoon af van persoonlijke keuze. In veel gevallen willen we dat deeltjes een begin- en eindschaalwaarde van nul hebben, wat de standaardwaarde is. De eerste parameter in de constructor staat voor de groeitijd van een deeltje, en de tweede is de fading-tijd; dus we geven in de GROWING_TIME en SHRINKING_TIME-constanten respectievelijk de eerste en tweede parameter door. De groeitijd is 5, wat betekent dat een deeltje groeit van nulschaal tot normale schaal tijdens de eerste 5-eenheid van levensduur; en de krimptijd is 15, wat betekent dat een deeltje op de laatste 15-eenheid van levensduur krimpt tot nul. Merk op dat de overgang standaard lineair is, maar elke versnellingsfucntie kan worden gebruikt, met name de versnellingsvergelijkingen die zijn gemaakt door Robert Penner. Er is nog een soortgelijke actie genaamd AlphaCurve, die op dezelfde manier werkt op alpha-waarden.

Dat is het. Onze zender is klaar. Hier is de code voor deze zender in zijn geheel, noodzakelijke importstatements inbegrepen.

 pakket import idv.cjcat.stardust.common.actions.Age; import idv.cjcat.stardust.common.actions.DeathLife; import idv.cjcat.stardust.common.actions.ScaleCurve; import idv.cjcat.stardust.common.clocks.Clock; import idv.cjcat.stardust.common.initializers.Life; import idv.cjcat.stardust.common.initializers.Scale; import idv.cjcat.stardust.common.math.UniformRandom; import idv.cjcat.stardust.twoD.actions.Damping; import idv.cjcat.stardust.twoD.actions.Move; import idv.cjcat.stardust.twoD.actions.Spin; import idv.cjcat.stardust.twoD.emitters.Emitter2D; import idv.cjcat.stardust.twoD.initializers.DisplayObjectClass; import idv.cjcat.stardust.twoD.initializers.Omega; import idv.cjcat.stardust.twoD.initializers.Position; import idv.cjcat.stardust.twoD.initializers.Rotation; import idv.cjcat.stardust.twoD.initializers.Velocity; import idv.cjcat.stardust.twoD.zones.LazySectorZone; import idv.cjcat.stardust.twoD.zones.SinglePoint; public class StarEmitter breidt Emitter2D uit / ** * Constants * / private static const LIFE_AVG: Number = 30; private static const LIFE_VAR: Number = 10; private static const SCALE_AVG: Number = 1; private static const SCALE_VAR: Number = 0.4; privé statische const GROWING_TIME: Number = 5; private static const SHRINKING_TIME: Number = 10; private static const SPEED_AVG: Number = 10; private static const SPEED_VAR: Number = 8; private static const OMEGA_AVG: Number = 0; private static const OMEGA_VAR: Number = 5; privé statische const DAMPING: Number = 0.1; public var point: SinglePoint; openbare functie StarEmitter (klok: klok) super (klok); punt = nieuw SinglePoint (); // initializers addInitializer (nieuwe DisplayObjectClass (Star)); addInitializer (nieuwe Life (nieuwe UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (nieuwe schaal (nieuwe UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (nieuwe positie (punt)); addInitializer (nieuwe Velocity (nieuwe LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (nieuwe rotatie (nieuwe UniformRandom (0, 180))); addInitializer (nieuwe Omega (nieuwe UniformRandom (OMEGA_AVG, OMEGA_VAR))); // actions addAction (new Age ()); addAction (nieuwe DeathLife ()); addAction (nieuwe verplaatsing ()); addAction (nieuwe Spin ()); addAction (nieuwe Demping (DAMPING)); addAction (nieuwe ScaleCurve (GROWING_TIME, SHRINKING_TIME)); 

Stap 8: Beëindig de documentklasse

Nu is het tijd om terug te gaan naar de documentklasse en deze af te maken. Laten we de resterende taken bekijken.

  • Maak een StarEmitter-instantie - We gaan de klasse StarEmitter instantiëren die we zojuist hebben voltooid.
  • Wijs een Clock-object toe aan de emitter - We willen een constante snelheid van deeltjesemissie, dus we zullen de SteadyClock-klasse gebruiken. De parameter die wordt doorgegeven aan de constructor van de klok is de snelheid van emissie, of, met andere woorden, het aantal nieuwe deeltjes dat wordt gecreëerd in elke emitterstap; een fractionele snelheid van 0,5 betekent in elke emitterstap, er is een kans van 50% om een ​​nieuw deeltje te maken en 50% kans dat er geen deeltje wordt aangemaakt.
  • Maak een renderer - Om het partikeleffect te visualiseren, hebben we een renderer nodig. De DisplayObjectRenderer moet worden gebruikt in combinatie met de DisplayObjectClass-initialisator: de initialisator wijst een weergaveobject toe aan elk deeltje en de renderer voegt deze weergaveobjecten toe aan de weergavelijst van een container en werkt deze voortdurend bij. Vergeet ook niet om de emitter aan de renderer toe te voegen.
  • Bel de hoofdlus herhaaldelijk - Deze laatste stap houdt Stardust aan de gang. Hier zullen we gebruik maken van de enter-frame-gebeurtenis.
  • Hieronder vindt u de volledige code voor de documentklasse, inclusief noodzakelijke importstatements.

 pakket import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Rectangle; import idv.cjcat.stardust.common.clocks.SteadyClock; import idv.cjcat.stardust.common.renderers.Renderer; import idv.cjcat.stardust.twoD.renderers.DisplayObjectRenderer; public class StarParticles breidt Sprite uit private var emitter: StarEmitter; public function StarParticles () // instantiate the StarEmitter emitter = new StarEmitter (nieuwe SteadyClock (0.5)); // container container sprite var: Sprite = nieuwe Sprite (); // de renderer die het partikeleffect renderer render: Renderer = nieuw DisplayObjectRenderer (container); renderer.addEmitter (emitter); // voeg de container toe aan de weergavelijst, boven de achtergrond addChildAt (container, 1); // maak gebruik van de enter-frame event addEventListener (Event.ENTER_FRAME, mainLoop);  private function mainLoop (e: Event): void // update de SinglePoint-positie naar de muispositie emitter.point.x = mouseX; emitter.point.y = mouseY; // noem de hoofdlus emitter.step (); 

Eindelijk zijn we klaar! Laten we nu eens kijken naar de uitkomst. Druk op CTRL + ENTER in Flash om de film te testen en je ziet het resultaat.


Variatie 1: geanimeerde sterren

We zijn nog niet klaar! Laten we nog een paar variaties doen. De eerste maakt gebruik van geanimeerde filmclips voor onze deeltjes.

Stap 9: Maak een tijdlijnanimatie

Deze eerste variatie is vrij eenvoudig, zonder extra codering. Het is net zo eenvoudig als het maken van een eenvoudige tijdlijnanimatie. Bewerk het stersymbool in Flash IDE, maak nog een keyframe en verander de kleur van de ster in dit frame in rood. Dit zorgt er in feite voor dat de sterren tussen geel en rood knipperen. Misschien wil je wat meer lege frames invoegen, omdat een framesnelheid van 60 fps te snel is voor een knipperend tweerichtingsframe.

Test nu de film en controleer het resultaat. Het knipperende stereffect ziet er cartoonachtig uit; dit kan worden gebruikt voor klassieke duizelige stereffecten, wat vaak wordt gezien in tekenfilms.


Variatie 2: Tijdschaal dynamisch aanpassen

Zoals ik eerder al zei, is een van de Stardust-functies "instelbare simulatieschema's", wat betekent dat de tijdschaal die Stardust gebruikt voor deeltjessimulatie dynamisch kan worden aangepast. Alles wordt gedaan door de eigenschap Emitter.stepTimeInterval te wijzigen, die standaard 1 is. Het volgende codefragment verandert deze waarde naar 2, waardoor deeltjes twee keer zo snel bewegen en emitter nieuwe deeltjes met dubbele snelheid maken.

 emitter.stepTimeInterval = 2;

In deze variant maken we een schuifregelaar op het podium en gebruiken we deze om de tijdschaal van de simulatie dynamisch aan te passen.

Stap 10: maak een schuifregelaar

Sleep een schuifregelaarcomponent uit het componentenpaneel naar het werkgebied. Noem het "slider".

Stap 11: schuifregelaarparameters instellen

We willen graag dat de schuif tussen 0,5 en 2 schuift, wat betekent dat we willen dat onze deeltjessimulatie minstens de helft sneller is dan normaal en hooguit twee keer zo snel. Stel ook 'liveDragging' in op true, zodat we de update kunnen zien terwijl we de duim van de schuifregelaar scrubben.

Stap 12: gebeurtenisluisteraar met schuifregelaars

Nu moeten we luisteren naar de veranderingsgebeurtenis van de schuifregelaar om de tijdschaal van de simulatie dynamisch te wijzigen. Importeer eerst de SliderEvent-klasse in de documentklasse.

 import fl.events.SliderEvent;

En luister dan naar de gebeurtenis van de schuifregelaar in de constructor van de documentklasse.

 slider.addEventListener (SliderEvent.CHANGE, changeTimescale);

Wijzig ten slotte de simulatie-tijdschaal in de luisteraar. Voeg de volgende listener toe aan de documentklasse.