Spara le stelle con il motore di particelle di polvere di stelle

In questo tutorial ti presenterò lo Stardust Particle Engine. Per prima cosa ti mostrerò come impostare Stardust e poi parlerò delle responsabilità di base della classe Stardust e di come collaborano insieme per rendere Stardust un lavoro nel suo complesso.

Successivamente, esamineremo il flusso di lavoro generale di Stardust e passeremo alla creazione di un effetto particellare con stelle che escono dal cursore del mouse; le stelle rallenteranno gradualmente, diventeranno più grandi dopo la nascita e si restringeranno quando moriranno.

Infine, dimostrerò la flessibilità di Stardust creando diverse varianti dall'esempio già completo, incluso l'utilizzo di clip animati come particelle, la scala temporale della simulazione di particelle variabili e l'estrazione di oggetti di visualizzazione di classi diverse da un singolo emettitore.

Questo tutorial è rivolto a persone che hanno già familiarità con la programmazione orientata agli oggetti ActionScript 3.0 (OOP), quindi presumo che tu sappia già molto bene cosa significano classi, oggetti, ereditarietà e interfaccia. Nessun problema con OOP? Allora andiamo a sparare ad alcune stelle!




Stardust Particle Engine

Come suggerisce il nome, Stardust è usato per creare effetti particellari. Se sei un ActionScripter esperto, potresti aver creato effetti particellari da zero molte volte, e dire "Sono assolutamente fantastico con la creazione di effetti particellari da zero, quindi perché dovrei comunque avere un motore particellare?" Bene, Stardust è qui per aiutarti a concentrarti maggiormente sulla progettazione del comportamento delle particelle reali piuttosto che preoccuparti del noioso contenuto di basso livello sottostante, come la gestione della memoria. Invece di scrivere codice per occuparsi dei dati delle particelle, inizializzare e smaltire le risorse, con Stardust, puoi saltare queste routine noiose e decidere come vuoi che le tue particelle si comportino.

Caratteristiche di polvere di stelle

La struttura di classe di Stardust è stata ispirata da FLiNT Particle System, un altro motore particellare ActionScript 3.0. Pertanto, condividono alcune caratteristiche di base simili.

  • Effetti di particelle 2D e 3D - Stardust può essere utilizzato per creare effetti di particelle 2D e 3D. Ha il suo motore 3D incorporato e può anche essere utilizzato per lavorare in combinazione con altri motori 3D di terze parti, inclusi ZedBox, Papervision3D e ND3D.
  • Elevata estensibilità - Stardust offre una vasta serie di comportamenti e riproduttori di particelle a tua disposizione. Se nessuno di essi soddisfa le tue esigenze, puoi sempre estendere le classi base e creare comportamenti personalizzati delle particelle; inoltre, puoi creare il tuo renderer per lavorare con un altro motore 3D che non è supportato da Stardust.

Oltre a queste funzionalità di base, Stardust offre anche diverse funzionalità avanzate per utenti esperti.

  • Tempo di simulazione regolabile - La scala cronologica utilizzata per la simulazione delle particelle può essere regolata dinamicamente durante l'esecuzione. Ad esempio, se si modifica la scala cronologica a metà dell'originale, l'effetto particella sarà a metà della velocità normale; e se modifichi la scala cronologica al doppio dell'originale, l'effetto particella verrà simulato due volte più velocemente del normale. Questa funzione può essere utile quando stai creando un gioco con effetti al rallentatore: l'effetto particella può rallentare per adeguarsi alla velocità del motore di gioco, sincronizzandosi con l'animazione e la grafica del gioco.
  • Serializzazione XML - Puoi trasformare il tuo sistema di particelle in un file in formato XML che può essere memorizzato sul tuo disco rigido, caricato in seguito durante il tempo di esecuzione e interpretato per ricostruire il tuo sistema di particelle originale. Questo è molto utile quando lavori con un grande progetto. Supponiamo di voler ridimensionare un po 'le particelle, in modo da regolare i parametri nel codice sorgente e ricompilare l'intera applicazione Flash, che potrebbe richiedere un minuto o anche più di cinque minuti se il progetto è estremamente grande. Ne vale la pena? Assolutamente no. Questa è una totale perdita di tempo. Utilizzando la funzione di serializzazione XML per salvare il sistema particellare in file XML esterni, si separano i parametri dal codice sorgente per l'applicazione principale. Quindi quello che devi fare è semplicemente aprire il file XML, modificare i valori dei parametri, salvarlo e riaprire l'applicazione principale. Questo è tutto! Non è richiesta nessuna ricompilazione. Direi che questo è il modo ideale per lavorare con grandi progetti.

Quando si tratta di effetti particellari, è molto importante gestire in modo efficiente enormi quantità di dati particellari. Stardust fa un uso pesante di pool di oggetti e elenchi collegati per migliorare le prestazioni:

  • Pool di oggetti - Gli oggetti usati sono memorizzati in un pool; più tardi, se è richiesto un oggetto dello stesso tipo, Stardust non lo istanzia immediatamente, ma controlla se c'è qualche oggetto precedentemente memorizzato nel pool di oggetti rimasto. Se sì, Stardust semplicemente estrae quell'oggetto e lo usa, invece di creare un oggetto completamente nuovo. Di solito gli effetti particellari implicano molta istanziazione di oggetti, che è un consumo di CPU. Usando pool di oggetti, Stardust riduce notevolmente il sovraccarico di istanziazione.
  • Elenchi collegati - È molto facile e allettante memorizzare i dati delle particelle in un array; tuttavia, in un caso in cui le particelle vengono create e rimosse molto frequentemente, viene eseguito un sacco di splicing di array per rimuovere le particelle morte. Lo splicing di array è un processo che consuma CPU, specialmente per array lunghi. Per una lista collegata, non importa quanto lunga sia la lista, richiede sempre la stessa quantità di tempo per suddividere le particelle morte. Dalla versione 1.1, Stardust ha iniziato a utilizzare elenchi concatenati internamente per memorizzare i dati delle particelle.

Impostazione di Stardust

Prima di passare alla vera codifica, dovremo prendere una copia di Stardust Particle Engine. È rilasciato sotto licenza MIT, il che significa che è totalmente gratuito, non importa se si desidera utilizzarlo in un progetto commerciale o non commerciale.

Ecco la homepage del progetto di Stardust: http://code.google.com/p/stardust-particle-engine/

Puoi scaricare Stardust qui: http://code.google.com/p/stardust-particle-engine/downloads/list

Al momento della scrittura, l'ultima versione che può essere scaricata dalla lista di download è la 1.1.132 Beta. Puoi sempre prendere l'ultima revisione dal repository SVN (che potrebbe non essere stabile, comunque).

Sulla home page del progetto, puoi trovare anche altri accessori come la documentazione dell'API e una copia del manuale in PDF. Ci sono anche video tutorial su YouTube.

Responsabilità della classe Stardust

Qui parlerò brevemente delle classi chiave di Stardust e delle loro responsabilità.

StardustElement

Questa classe è la superclasse di tutte le core classes, che definisce proprietà e metodi specialmente per la serializzazione XML.

Casuale

In generale, gli effetti particellari riguardano il controllo di una quantità di entità con aspetto e comportamenti simili ma casuali. La classe Random serve a generare numeri casuali, che possono essere usati in Stardust per randomizzare le proprietà delle particelle. Per esempio, la classe UniformRandom è una sottoclasse della classe Random, e il suo nome dice tutto: il numero casuale generato da un oggetto UniformRandom è distribuito uniformemente, e userò questa classe in particolare per l'intero tutorial.

Zona

Ci sono momenti in cui un numero casuale unidimensionale non è sufficiente. A volte abbiamo bisogno di numeri casuali bidimensionali, che sono essenzialmente coppie di numeri casuali, per proprietà come la posizione e la velocità. La classe Zone serve a generare coppie di numeri casuali bidimensionali. Questa classe modella una coppia numerica casuale come un punto casuale in una zona 2D. Ad esempio, CircleZone genera coppie di numeri casuali (x, y) da punti casuali all'interno di una regione circolare. Le classi Random e Zone vengono principalmente utilizzate dalla classe Initializer, che verrà trattata in seguito. La classe Zone3D è la controparte 3D di questa classe, per effetti particellari 3D.

Emettitore

La classe Emitter è fondamentalmente in cui tutte le cose di basso livello sono incapsulate. Un emettitore inizializza le particelle appena create prima di essere aggiunte alla simulazione, aggiorna le proprietà delle particelle in ciascuna iterazione del ciclo principale e rimuove le particelle morte dalla simulazione. Il metodo Emitter.step () è ciò che si desidera richiamare ripetutamente per mantenere attivo e funzionante Stardust.

Orologio

La classe Clock determina il tasso di creazione di nuove particelle per gli emettitori. Un oggetto Emettitore contiene esattamente un riferimento a un oggetto Orologio. All'inizio di ogni chiamata al metodo Emitter.step (), l'emettitore chiede all'oggetto orologio quante nuove particelle dovrebbe creare. Prendiamo ad esempio la classe SteadyClock, che dice agli emettitori di creare nuove particelle a una velocità costante.

initializer

Questa classe serve per inizializzare le particelle appena create. Un oggetto Initializer deve essere aggiunto a un emettitore affinché funzioni. Fondamentalmente, una sottoclasse Initializer inizializza solo una proprietà particella. Ad esempio, la classe di inizializzazione di massa inizializza la massa di nuove particelle. Alcuni inizializzatori accettano un oggetto casuale come parametro di costruzione per inizializzare particelle con valori randomizzati. Il codice seguente crea un inizializzatore Life che inizializza la vita delle particelle a valori centrati a 50 con variazione di 10, cioè nell'intervallo da 40 a 60.

 nuova vita (nuovo UniformRandom (50, 10));

Azione

Gli oggetti azione aggiornano le proprietà delle particelle in ogni iterazione del ciclo principale (il metodo Emiter.step ()). Ad esempio, la classe di azione Sposta aggiorna le posizioni delle particelle in base alla velocità. Un oggetto Action deve essere aggiunto a un emettitore affinché funzioni.

Flusso di lavoro generale Stardust

Ora che sai come collaborano le classi principali, diamo un'occhiata a un flusso di lavoro generale per Stardust.

Si inizia creando un emettitore. Usa la classe Emitter2D per effetti particellari 2D e la classe Emitter3D per effetti 3D.

 var emitter: Emitter = new Emitter2D ();

Per specificare il tasso di creazione di particelle, abbiamo bisogno di un orologio. Questo può essere impostato dalla proprietà Emitter.clock o passando un orologio come primo parametro al costruttore dell'emettitore.

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

Aggiungi gli inizializzatori all'emettitore tramite il metodo Emitter.addInitializer ().

 emitter.addInitializer (new Life (new UniformRandom (50, 10))); emitter.addInitializer (new Scale (new UniformRandom (1, 0.2)));

Aggiungere azioni all'emettitore tramite il metodo Emitter.addAction ().

 emitter.addAction (new Move ()); emitter.addAction (new Spin ());

Crea un renderer e aggiungi l'emettitore al renderer tramite il metodo Renderer.addEmitter ().

 var renderer: Renderer = new DisplayObjectRenderer (container); // "container" è il nostro contenitore sprite renderer.addEmitter (emitter);

Infine, chiama ripetutamente il metodo Emitter.step () per mantenere attiva la simulazione delle particelle. Potresti voler usare l'evento enter-frame o un timer per farlo. In una singola chiamata del metodo Emitter.step (), l'orologio determina quante nuove particelle dovrebbero essere create, queste nuove particelle vengono inizializzate dagli inizializzatori, tutte le particelle vengono aggiornate dalle azioni, le particelle morte vengono rimosse e infine, il renderer esegue il rendering l'effetto particellare.

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

Tutto apposto. Questo è praticamente tutto per Stardust Primer. Ora è il momento di aprire l'IDE Flash e sporcarsi le mani.

Passaggio 1: creare un nuovo documento Flash

Crea un nuovo documento Flash con una dimensione di 640X400 con una frequenza fotogrammi di 60 fps e uno sfondo scuro. Qui ho creato uno sfondo sfumato blu scuro. A proposito, Stardust funziona bene con Flash Player 9 e 10, quindi va bene, non importa che tu stia usando Flash CS3 o CS4. In questo tutorial userò Flash CS3.

Step 2: Disegna una stella

Stiamo creando un effetto particellare con le stelle, quindi dovremo disegnare una stella e convertirla in un simbolo, ovviamente esportato per ActionScript. Questo simbolo sarà usato in seguito per rendere il nostro effetto particellare. Assegna un nome al simbolo e alla classe esportata "Star".

Passaggio 3: creare la classe del documento

Creare una nuova classe di documento e denominarla StarParticles.

 pacchetto import flash.display.Sprite; classe pubblica StarParticles estende Sprite funzione pubblica StarParticles () 

Passaggio 4: estendere l'emettitore

Come menzionato nel flusso di lavoro generale, il primo passo è creare un emettitore. E il passo successivo è l'aggiunta di inizializzatori e azioni all'emettitore. Mentre questo può essere fatto nel costruttore della classe del documento, raccomando vivamente di farlo in una sottoclasse Emitter separata. È sempre meglio separare la progettazione del comportamento delle particelle dal programma principale; così facendo, il codice è molto più pulito e più facile da modificare in futuro, senza essere confuso con il programma principale.

Creeremo un effetto particellare 2D, quindi Emitter2D è la classe di emissione che stiamo per estendere. Estendi la classe Emitter2D e chiamala StarEmitter, dato che lo faremo sparare alle stelle in seguito. Il costruttore Emitter accetta un parametro Clock, quindi dichiareremo un parametro costruttore per passare un riferimento a oggetto Clock al costruttore della superclasse.

 package import idv.cjcat.stardust.twoD.emitters.Emitter2D; classe pubblica StarEmitter estende Emitter2D funzione pubblica StarEmitter (clock: Clock) // passa l'oggetto orologio al super costruttore della superclasse (orologio); 

Passaggio 5: dichiarare le costanti

Un approccio migliore per creare una sottoclasse di emettitore consiste nel dichiarare i parametri delle particelle come costanti statiche, raggruppate in un singolo punto. Quindi, nel caso in cui desideri modificare i parametri, saprai sempre dove trovare le dichiarazioni. Il significato di queste costanti verrà spiegato più avanti quando vengono utilizzate.

 // durata media della vita privata const const LIFE_AVG: Number = 30; // variazione della durata della vita private static const LIFE_VAR: Number = 10; // scale statiche private cost const SCALE_AVG: Number = 1; // scale variation private static const SCALE_VAR: Number = 0.4; // scala crescente tempo statico privato const GROWING_TIME: Number = 5; // ridimensionamento della scala private static const SHRINKING_TIME: Number = 10; // velocità media statica privata const SPEED_AVG: Number = 10; // variazione della velocità private static const SPEED_VAR: Number = 8; // media omega (velocità angolare) const statico privato OMEGA_AVG: Number = 0; // variazione omega private static const OMEGA_VAR: Number = 5; // coefficiente di smorzamento const statico privato DAMPING: Number = 0.1;

Passaggio 6: aggiunta di inizializzatori

Di quali inizializzatori abbiamo bisogno per creare il nostro effetto particellare? Diamo un'occhiata alla lista qui sotto:

  • DisplayObjectClass - Questo inizializzatore assegna un oggetto di visualizzazione specifico a ciascuna particella, che verrà utilizzato da un DisplayObjectRenderer per il rendering di effetti particellari. Il costruttore accetta un riferimento di classe alla classe dell'oggetto di visualizzazione che desideriamo istanziare; per questo tutorial, questa classe sarà la classe Star (simbolo) creata nel passaggio 2.
  • Vita - Questo inizializzatore assegna ad ogni particella un valore di vita casuale. Successivamente, aggiungeremo azioni all'emettitore per ridurre questo valore vitale nel tempo e per contrassegnare una particella come morta se il suo valore di vita raggiunge lo zero. Un oggetto casuale viene passato al costruttore, che verrà usato da questo inizializzatore per generare un valore casuale per la vita delle particelle. Per la maggior parte dei casi, la classe UniformRandom è comoda e sufficiente; il primo parametro del costruttore UniformRandom è il valore centrale (o medio) dei numeri casuali generati, e il secondo è il raggio (o variazione). Ad esempio, un oggetto UniformRandom con centro 20 e variazione 5 genera numeri casuali all'interno dell'intervallo [15, 25]. Qui usiamo la costante LIFE_AVG per il valore centrale e LIFE_VAR per il raggio.
  • Scala - Come l'inizializzatore Life, l'inizializzatore Scale inizializza la scala di una particella su un valore casuale, determinato da un oggetto casuale passato al costruttore dell'inizializzatore. Qui usiamo la costante SCALE_AVG per il valore centrale e SCALE_VAR per il raggio.
  • Posizione - Questo inizializzatore assegna a una particella una posizione casuale. A differenza degli inizializzatori Life e Scale, che richiedono solo numeri casuali 1D, l'inizializzatore di posizione richiede generatori di coppie di numeri casuali 2D. Come descritto nella sezione Responsabilità della classe Stardust, la classe Zone è esattamente per questo scopo. L'oggetto Zone passato al costruttore dell'inizializzatore viene utilizzato per generare coppie di numeri casuali 2D, che verranno assegnati alle particelle come vettori di posizione. In questo tutorial creeremo stelle da un singolo punto situato al cursore del mouse, quindi utilizzeremo una classe SinglePoint, che è una sottoclasse Zone. Per regolare dinamicamente le coordinate di questo oggetto SinglePoint dalla classe del documento, è necessario esporre un riferimento a questo oggetto punto attraverso una proprietà pubblica. Questo è ciò che è la proprietà "point".
  • Velocità - Come l'inizializzatore di posizione, l'inizializzatore di velocità ha bisogno di un oggetto zona per generare coppie di valori casuali 2D per inizializzare le velocità delle particelle. Un vettore 2D generato dall'oggetto Zone, che è la coordinata di un punto casuale nella zona, viene assegnato alle particelle come velocità. Qui usiamo la classe LazySectorZone che rappresenta una regione di settore. Un settore è una porzione di un cerchio racchiuso da due raggi e due angoli. Per LazySectorZone, i due angoli sono 0 e 360 ​​per impostazione predefinita, che rappresentano un angolo completo attorno a un cerchio. Il primo parametro costruttore della classe LazySectorZone è la media dei due raggi e il secondo è la variazione dei raggi. In questo caso, la media dei due raggi rappresenta la velocità media e la variazione dei raggi rappresenta la variazione di velocità. Qui usiamo la costante SPEED_AVG per il primo parametro e SPEED_VAR per il secondo.
  • Rotazione - L'inizializzatore di rotazione inizializza l'angolo di rotazione di una particella su un valore casuale. E come alcuni dei suddetti inizializzatori, il costruttore accetta un oggetto casuale per generare un valore casuale. Dal momento che vorremmo avere particelle con angoli che vanno da 0 a 360 gradi, useremo 0 come centro e 180 come raggio dell'oggetto UniformRandom.
  • Omega - Omega, come nella maggior parte dei libri di testo di fisica, significa velocità angolare. Detto questo, lo scopo di questo inizializzatore è chiaro: inizializza la velocità angolare di una particella su un valore casuale, e la costante OMEGA_AVG viene usata come centro e OMEGA_VAR come il raggio dell'oggetto UniformRandom.

Ed ecco il codice:

 point = new SinglePoint (); addInitializer (new DisplayObjectClass (Star)); addInitializer (new Life (new UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (new Scale (new UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (new Position (point)); addInitializer (nuovo Velocity (nuovo LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (new Rotation (new UniformRandom (0, 180))); addInitializer (nuovo Omega (nuovo UniformRandom (OMEGA_AVG, OMEGA_VAR)));

Passaggio 7: aggiunta di azioni

Ok, abbiamo finito con gli inizializzatori. Ora è il momento di aggiungere azioni all'emettitore. Di seguito è riportato un elenco di azioni di cui abbiamo bisogno:

  • Età - L'azione Age riduce il valore di vita di una particella di 1 in ciascuna fase dell'emettitore.
  • DeathLife - Quando il valore di vita di una particella raggiunge lo zero, questa azione contrassegna la particella come morta, cambiando la sua proprietà isDead da false a true. Alla fine di una fase di emettitore, le particelle morte vengono rimosse.
  • Mossa - Praticamente come suggerisce il nome, l'azione Sposta aggiorna le posizioni delle particelle in base alle loro velocità.
  • Rotazione - Simile all'azione Move, l'azione Spin aggiorna l'angolo di rotazione di una particella in base al valore omega della particella (velocità angolare).
  • damping - Questa azione moltiplica la velocità di una particella con un fattore compreso nell'intervallo [0, 1], simulando gli effetti di smorzamento e rallentando gradualmente la particella. Un fattore di uno significa niente smorzamento: le particelle si muovono liberamente come se non ci fosse alcun effetto di smorzamento; un fattore di zero significa smorzamento totale: tutte le particelle non possono muoversi un po '. Questo fattore è determinato dal "coefficiente di smorzamento" attraverso questa formula: "fattore = 1 - (coefficiente di smorzamento)". Il parametro passato al costruttore è il coefficiente di smorzamento; qui vogliamo solo un piccolo effetto di smorzamento, quindi usiamo il valore 0.1 per il coefficiente.
  • ScaleCurve - L'azione ScaleCurve modifica la scala di una particella in base al suo valore di vita. Cresce da una scala iniziale a una scala normale dopo la nascita e sfuma in scala finale quando muore. Naturalmente, una particella può anche avere un valore di scala iniziale o finale maggiore della scala normale; dipende solo dalla scelta personale. In molti casi, vorremmo che le particelle avessero un valore di scala iniziale e finale pari a zero, che è il valore predefinito. Il primo parametro nel costruttore indica il tempo di crescita di una particella e il secondo il tempo di dissolvenza; quindi passiamo le costanti GROWING_TIME e SHRINKING_TIME rispettivamente come primo e secondo parametro. Il tempo di crescita è 5, il che significa che una particella cresce dalla scala zero alla scala normale durante le sue prime 5 unità di durata della vita; e il tempo di restringimento è 15, il che significa che una particella si riduce alla scala zero nell'ultima 15 unità di durata della vita. Si noti che la transizione è lineare per impostazione predefinita, ma è possibile utilizzare qualsiasi funzione di andamento, in particolare le equazioni di andamento create da Robert Penner. C'è un'altra azione simile chiamata AlphaCurve, che funziona su valori alpha allo stesso modo.

Questo è tutto. Il nostro emettitore è fatto. Ecco il codice per questo emettitore nella sua interezza, incluse le istruzioni di importazione necessarie.

 package 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; la classe pubblica StarEmitter estende Emitter2D / ** * Costanti * / private static const LIFE_AVG: Number = 30; private static const LIFE_VAR: Number = 10; const statico privato SCALE_AVG: Number = 1; const statico privato SCALE_VAR: Number = 0.4; const statico privato GROWING_TIME: Number = 5; private static const SHRINKING_TIME: Number = 10; const statico privato SPEED_AVG: Number = 10; const statico privato SPEED_VAR: Number = 8; const statico privato OMEGA_AVG: Number = 0; const statico privato OMEGA_VAR: Number = 5; private static const DAMPING: Number = 0.1; punto var pubblico: SinglePoint; funzione pubblica StarEmitter (clock: Clock) super (orologio); point = new SinglePoint (); // inizializzatori addInitializer (new DisplayObjectClass (Star)); addInitializer (new Life (new UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (new Scale (new UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (new Position (point)); addInitializer (nuovo Velocity (nuovo LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (new Rotation (new UniformRandom (0, 180))); addInitializer (nuovo Omega (nuovo UniformRandom (OMEGA_AVG, OMEGA_VAR))); // azioni addAction (new Age ()); addAction (new DeathLife ()); addAction (new Move ()); addAction (new Spin ()); addAction (new Damping (DAMPING)); addAction (new ScaleCurve (GROWING_TIME, SHRINKING_TIME)); 

Passaggio 8: completare la classe del documento

Ora è il momento di tornare alla classe del documento e finirla. Diamo un'occhiata alle attività rimanenti.

  • Creare un'istanza StarEmitter - Istanziamo la classe StarEmitter che abbiamo appena terminato.
  • Assegna un oggetto Clock all'emettitore - Vogliamo un tasso costante di emissione di particelle, quindi useremo la classe SteadyClock. Il parametro passato al costruttore del clock è la velocità di emissione o, in altre parole, il numero di nuove particelle create in ciascuna fase dell'emettitore; una percentuale frazionaria di 0,5 significa in ciascuna fase dell'emettitore, c'è una probabilità del 50% di creare una nuova particella e una probabilità del 50% di non creare nessuna particella.
  • Crea un renderer - Per visualizzare l'effetto particella, avremo bisogno di un riproduttore. Il DisplayObjectRenderer deve essere utilizzato insieme all'inizializzatore DisplayObjectClass: l'inizializzatore assegna un oggetto di visualizzazione a ciascuna particella e il renderer aggiunge questi oggetti di visualizzazione all'elenco di visualizzazione di un contenitore, aggiornandoli costantemente. Inoltre, non dimenticare di aggiungere l'emettitore al renderer.
  • Chiamare ripetutamente il loop principale - Quest'ultimo passaggio mantiene Stardust attivo e funzionante. Qui faremo uso dell'evento enter-frame.
  • Di seguito è riportato il codice completo per la classe del documento, incluse le istruzioni di importazione necessarie.

 pacchetto 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; classe pubblica StarParticles estende Sprite emettitore private var: StarEmitter; funzione pubblica StarParticles () // istanzia l'emettitore StarEmitter = new StarEmitter (new SteadyClock (0.5)); // contenitore container sprite var: Sprite = new Sprite (); // il renderer che rende l'effetto particle var renderer: Renderer = new DisplayObjectRenderer (container); renderer.addEmitter (emettitore); // aggiungi il contenitore alla lista di visualizzazione, sopra lo sfondo addChildAt (container, 1); // usa l'evento enter-frame addEventListener (Event.ENTER_FRAME, mainLoop);  private function mainLoop (e: Event): void // aggiorna la posizione SinglePoint sulla posizione del mouse emitter.point.x = mouseX; emitter.point.y = mouseY; // chiama il ciclo principale emitter.step (); 

Finalmente, abbiamo finito! Ora diamo un'occhiata al risultato. Premi CTRL + INVIO in Flash per testare il film e vedrai il risultato.


Variazione 1: stelle animate

Non abbiamo ancora finito! Facciamo qualche altra variazione. Il primo utilizza filmati animati per le nostre particelle.

Passaggio 9: creare un'animazione della linea temporale

Questa prima variazione è abbastanza semplice, non implica alcuna codifica aggiuntiva. È semplice come creare un'animazione temporale di base. Modifica il simbolo Stella in Flash IDE, crea un altro fotogramma chiave e cambia il colore della stella in questo riquadro in rosso. Questo essenzialmente fa sì che le stelle lampeggino tra il giallo e il rosso. Si consiglia di inserire alcuni fotogrammi più vuoti in mezzo, poiché una frequenza fotogrammi di 60fps è troppo veloce per un lampeggiamento a due fotogrammi.

Ora prova il film e controlla il risultato. L'effetto stella lampeggiante sembra fumoso; questo può essere usato per i classici effetti stordenti, che si vedono comunemente nei cartoni animati.


Variazione 2: regolazione della scala cronologica in modo dinamico

Come accennato in precedenza, una delle caratteristiche di Stardust è "tempo di simulazione regolabile", il che significa che la scala cronologica utilizzata da Stardust per la simulazione delle particelle può essere regolata dinamicamente. Tutto avviene cambiando la proprietà Emitter.stepTimeInterval, che è 1 per impostazione predefinita. Il seguente frammento di codice cambia questo valore in 2, con il risultato che particelle si muovono due volte più velocemente e emettitori che creano nuove particelle a doppia frequenza.

 emitter.stepTimeInterval = 2;

In questa variante creeremo un cursore sullo stage e lo useremo per regolare dinamicamente la scala temporale della simulazione.

Passaggio 10: crea un dispositivo di scorrimento

Trascina un componente Slider dal pannello Componenti allo stage. Chiamalo "slider".

Passaggio 11: impostazione dei parametri del dispositivo di scorrimento

Vorremmo far scorrere il cursore tra 0,5 e 2, il che significa che vogliamo che la nostra simulazione delle particelle sia almeno la metà della velocità normale e al massimo due volte veloce. Inoltre, imposta "liveDragging" su true in modo che possiamo vedere l'aggiornamento mentre sfogliamo