Dispara a las estrellas con el motor de partículas de polvo de estrellas

En este tutorial les presentaré el motor de partículas Stardust. Primero, le mostraré cómo configurar Stardust, y luego cubriré las responsabilidades básicas de la clase de Stardust y cómo colaboran juntos para que Stardust funcione en conjunto..

A continuación, veremos el flujo de trabajo general de Stardust y comenzaremos a crear un efecto de partículas con estrellas que salen del cursor del mouse; las estrellas disminuirán gradualmente, crecerán después del nacimiento y se reducirán al morir.

Finalmente, demostraré la flexibilidad de Stardust mediante la creación de varias variaciones del ejemplo ya completo, que incluye el uso de clips de película animados como partículas, la escala de tiempo de simulación de partículas variables y el disparo de objetos de diferentes clases en un solo emisor..

Este tutorial está dirigido a personas que ya están familiarizadas con la programación orientada a objetos (OOP) de ActionScript 3.0, por lo que supongo que ya saben muy bien qué significan las clases, los objetos, la herencia y la interfaz. No hay problema con OOP? Entonces vamos a disparar algunas estrellas!




Motor de partículas de polvo de estrellas

Como su nombre lo indica, Stardust se utiliza para crear efectos de partículas. Si eres un ActionScripter experimentado, es posible que hayas creado efectos de partículas desde cero muchas veces, y dices: "Soy totalmente bueno con la creación de efectos de partículas desde cero, así que, ¿por qué necesitaría un motor de partículas de todos modos?" Bueno, Stardust está aquí para ayudarlo a enfocarse más en el diseño de comportamiento de partículas real que en preocuparse por las tediosas cosas subyacentes de bajo nivel, como la administración de memoria. En lugar de escribir código para cuidar los datos de partículas, inicializar y desechar recursos, con Stardust, puede omitir estas rutinas aburridas y simplemente decidir cómo desea que se comporten sus partículas..

Características de Stardust

La estructura de clase de Stardust se inspiró en FLiNT Particle System, otro motor de partículas ActionScript 3.0. Por lo tanto, comparten algunas características básicas similares.

  • Efectos de partículas 2D y 3D - Stardust se puede utilizar para crear efectos de partículas 2D y 3D. Tiene su propio motor 3D incorporado y también se puede usar para trabajar en combinación con otros motores 3D de tercera partícula, incluidos ZedBox, Papervision3D y ND3D..
  • Alta extensibilidad - Stardust proporciona un amplio conjunto de comportamientos de partículas y renderizadores a su disposición. Si ninguno de ellos se ajusta a sus necesidades, siempre puede ampliar las clases base y crear sus propios comportamientos personalizados de partículas; también, puede crear su propio procesador para trabajar con otro motor 3D que no es compatible con Stardust.

Además de estas funciones básicas, Stardust también proporciona varias funciones avanzadas para usuarios experimentados.

  • Simulación de tiempo ajustable - La escala de tiempo utilizada para la simulación de partículas se puede ajustar dinámicamente durante el tiempo de ejecución. Por ejemplo, si cambia la escala de tiempo a la mitad del original, el efecto de partículas será la mitad de rápido que la velocidad normal; y si ajusta la escala de tiempo al doble del original, el efecto de partículas se simulará dos veces más rápido de lo normal. Esta función puede ser útil cuando está creando un juego que tiene efectos de cámara lenta: el efecto de partículas puede disminuir para adaptarse a la velocidad del motor de su juego, sincronizándose con la animación y los gráficos del juego..
  • Serialización XML - Puede transformar su sistema de partículas en un archivo en formato XML que se puede almacenar en su disco duro, cargar más tarde durante el tiempo de ejecución e interpretar para reconstruir su sistema de partículas original. Esto es muy útil cuando estás trabajando con un proyecto grande. Digamos que solo desea dimensionar sus partículas un poco, así que modifica los parámetros en el código fuente y vuelve a compilar toda su aplicación Flash, lo que puede llevar un minuto, o incluso más de cinco minutos si su proyecto es extremadamente grande. ¿Vale la pena? Absolutamente no. Eso es una pérdida total de tiempo. Al utilizar la función de serialización XML para guardar su sistema de partículas en archivos XML externos, está separando los parámetros del código fuente de la aplicación principal. Entonces, lo que tendrá que hacer es simplemente abrir el archivo XML, cambiar los valores de los parámetros, guardarlo y volver a abrir su aplicación principal. ¡Eso es! No se requiere ninguna recompilación en absoluto. Yo diría que esta es la manera ideal de trabajar con grandes proyectos..

Cuando se trata de efectos de partículas, es muy importante manejar datos masivos de partículas de manera eficiente. Stardust hace un uso intensivo de grupos de objetos y listas vinculadas para mejorar el rendimiento:

  • Grupos de objetos - Los objetos usados ​​se almacenan en una piscina; más adelante, si se requiere un objeto del mismo tipo, Stardust no lo creará de inmediato, sino que verificará si hay algún objeto almacenado previamente en el conjunto de objetos. Si es así, Stardust simplemente saca ese objeto y lo usa, en lugar de crear un objeto completamente nuevo. Por lo general, los efectos de partículas implican una gran cantidad de ejemplos de objetos, que consumen CPU. Al utilizar grupos de objetos, Stardust reduce en gran medida la sobrecarga de creación de instancias..
  • Listas enlazadas - Es muy fácil y tentador almacenar datos de partículas en una matriz; sin embargo, en un caso en el que las partículas se crean y eliminan con mucha frecuencia, se lleva a cabo una gran cantidad de empalmes de matrices para eliminar las partículas muertas. El empalme de arreglos es un proceso que consume CPU, especialmente para arreglos largos. Para una lista enlazada, sin importar qué tan larga sea la lista, siempre lleva el mismo corto tiempo empalmar las partículas muertas. Desde la versión 1.1, Stardust comenzó a usar listas enlazadas internamente para almacenar datos de partículas..

Configuración de Stardust

Antes de pasar a la codificación real, necesitaremos obtener una copia de Stardust Particle Engine. Se ha publicado bajo la licencia MIT, lo que significa que es totalmente gratuito sin importar si desea usarlo en un proyecto comercial o no comercial..

Aquí está la página de inicio del proyecto de Stardust: http://code.google.com/p/stardust-particle-engine/

Puede descargar Stardust aquí: http://code.google.com/p/stardust-particle-engine/downloads/list

Al momento de escribir este artículo, la versión más reciente que se puede descargar de la lista de descargas es 1.1.132 Beta. Siempre puede obtener la última revisión del repositorio de SVN (que puede no ser estable, sin embargo).

En la página de inicio del proyecto, también puede encontrar más accesorios como documentación de API y una copia del manual en PDF. Incluso hay videos tutoriales en YouTube.

Responsabilidades de la Clase Stardust

Aquí voy a cubrir brevemente las clases principales de Stardust y sus responsabilidades.

StardustElement

Esta clase es la superclase de todas las clases principales, que define propiedades y métodos especialmente para la serialización XML.

Aleatorio

En términos generales, los efectos de partículas tienen que ver con controlar una cantidad de entidades con apariencia y comportamientos similares pero aleatorios. La clase aleatoria es para generar números aleatorios, que se pueden usar en Stardust para aleatorizar propiedades de partículas. Por ejemplo, la clase UniformRandom es una subclase de la clase Random, y su nombre lo dice todo: el número aleatorio generado por un objeto UniformRandom se distribuye uniformemente, y usaré esta clase en particular para todo el tutorial.

Zona

Hay ocasiones en que un número aleatorio unidimensional no es suficiente. A veces necesitamos números aleatorios bidimensionales, que son esencialmente pares de números aleatorios, para propiedades como la posición y la velocidad. La clase de zona es para generar pares de números aleatorios bidimensionales. Esta clase modela un par de números aleatorios como un punto aleatorio en una zona 2D. Por ejemplo, CircleZone genera pares de números aleatorios (x, y) a partir de puntos aleatorios dentro de una región circular. Las clases Random y Zone son utilizadas principalmente por la clase Initializer, que se tratará más adelante. La clase Zone3D es la contraparte 3D de esta clase, para efectos de partículas 3D.

Emisor

La clase de Emisor es básicamente donde se encapsulan todas las cosas de bajo nivel. Un emisor inicializa las partículas recién creadas antes de agregarlas a la simulación, actualiza las propiedades de las partículas en cada iteración del bucle principal y elimina las partículas muertas de la simulación. El método Emitter.step () es lo que desea invocar repetidamente para mantener Stardust en funcionamiento.

Reloj

La clase Reloj determina la tasa de creación de nuevas partículas para los emisores. Un objeto Emisor contiene exactamente una referencia a un objeto Reloj. Al comienzo de cada llamada al método Emitter.step (), el emisor le pregunta al objeto del reloj cuántas partículas nuevas debe crear. Tome la clase SteadyClock, por ejemplo, le dice a los emisores que creen nuevas partículas a una velocidad constante.

Inicializador

Esta clase es para inicializar partículas recién creadas. Es necesario agregar un objeto Inicializador a un emisor para que funcione. Básicamente, una subclase de inicializador inicializa solo una propiedad de partícula. Por ejemplo, la clase de inicializador de masa inicializa la masa de nuevas partículas. Algunos inicializadores aceptan un objeto aleatorio como parámetro de constructor para inicializar partículas con valores aleatorios. El siguiente código crea un inicializador de vida que inicializa la vida de las partículas a valores centrados en 50 con una variación de 10, es decir, entre el rango de 40 a 60.

 nueva vida (nuevo UniformRandom (50, 10));

Acción

Los objetos de acción actualizan las propiedades de las partículas en cada iteración del bucle principal (el método Emiter.step ()). Por ejemplo, la clase de acción Mover actualiza las posiciones de las partículas según la velocidad. Un objeto de acción debe agregarse a un emisor para que funcione.

Flujo de trabajo general Stardust

Ahora que sabe cómo colaboran las clases principales, echemos un vistazo a un flujo de trabajo general para Stardust.

Empiezas creando un emisor. Use la clase Emitter2D para efectos de partículas 2D y la clase Emitter3D para efectos 3D.

 var emitter: Emitter = new Emitter2D ();

Para especificar la tasa de creación de partículas, necesitamos un reloj. Esto se puede establecer mediante la propiedad Emitter.clock o pasando un reloj como primer parámetro al constructor del emisor.

 // enfoque de propiedad emitter.clock = new SteadyClock (1); // enfoque del constructor var emitter: Emitter = new Emitter2D (new SteadyClock (1));

Agregue inicializadores al emisor a través del método Emitter.addInitializer ().

 emitter.addInitializer (nueva Vida (nuevo UniformRandom (50, 10))); emitter.addInitializer (nueva Escala (nuevo UniformRandom (1, 0.2)));

Agregue acciones al emisor a través del método Emitter.addAction ().

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

Cree un procesador y agregue el emisor al procesador a través del método Renderer.addEmitter ().

 var renderer: Renderer = new DisplayObjectRenderer (contenedor); // "contenedor" es nuestro contenedor sprite renderer.addEmitter (emisor);

Finalmente, llame repetidamente al método Emitter.step () para mantener en funcionamiento la simulación de partículas. Es posible que desee utilizar el evento enter-frame o un temporizador para hacer esto. En una sola llamada del método Emitter.step (), el reloj determina cuántas partículas nuevas deben crearse, las nuevas partículas se inicializan con inicializadores, todas las partículas se actualizan mediante acciones, se eliminan las partículas muertas y, finalmente, el renderizador el efecto partícula.

 // enfoque del evento enter-frame addEventListener (Event.ENTER_FRAME, mainLoop); // timer enfoque timer.addEventListener (TimerEvent.TIMER, mainLoop); función mainLoop (e: Evento): void emitter.step (); 

Bien. Eso es prácticamente todo para la cartilla de Stardust. Ahora es el momento de abrir el IDE de Flash y ensuciarse las manos.

Paso 1: Crear un nuevo documento de Flash

Cree un nuevo documento de Flash con una dimensión de 640X400, una velocidad de fotogramas de 60 fps y un fondo oscuro. Aquí hice un fondo degradado azul oscuro. Por cierto, Stardust funciona bien con Flash Player 9 y 10, así que está bien, sin importar que uses Flash CS3 o CS4. En este tutorial usaré Flash CS3..

Paso 2: dibuja una estrella

Estamos creando un efecto de partícula con estrellas, por lo que tendremos que dibujar una estrella y convertirla en un símbolo, por supuesto, exportado para ActionScript. Este símbolo se usará más adelante para representar nuestro efecto de partículas. Nombra el símbolo y la clase exportada "Estrella".

Paso 3: Crear la clase de documento

Cree una nueva clase de documento y asígnele el nombre StarParticles.

 paquete import flash.display.Sprite; clase pública StarParticles extiende Sprite función pública StarParticles () 

Paso 4: Extender el Emisor

Como se mencionó en el flujo de trabajo general, el primer paso es crear un emisor. Y el siguiente paso es agregar inicializadores y acciones al emisor. Si bien esto se puede hacer en el constructor de la clase de documento, recomiendo encarecidamente que se haga en una subclase de Emisor separada. Siempre es mejor separar el diseño de comportamiento de partículas del programa principal; Al hacerlo, el código es mucho más limpio y fácil de modificar en el futuro, sin confundirse con el programa principal..

Vamos a crear un efecto de partículas 2D, por lo que Emitter2D es la clase de emisor que vamos a extender. Amplíe la clase Emitter2D y asígnele el nombre StarEmitter, ya que haremos que dispare estrellas más tarde. El constructor Emisor acepta un parámetro Reloj, por lo que declararemos un parámetro constructor para pasar una referencia de objeto Reloj al constructor de la superclase.

 paquete import idv.cjcat.stardust.twoD.emitters.Emitter2D; la clase pública StarEmitter extiende Emitter2D public function StarEmitter (clock: Clock) // pasa el objeto de reloj al constructor de la superclase super (clock); 

Paso 5: Declara las constantes

Un mejor enfoque para crear una subclase de emisor es declarar los parámetros de partículas como constantes estáticas, agrupadas en un solo lugar. Entonces, en caso de que desee modificar los parámetros, siempre sabrá dónde encontrar las declaraciones. El significado de estas constantes se explicará más adelante cuando se utilicen..

 // promedio de vida útil privada estática const LIFE_AVG: Número = 30; // variación de la vida útil const. estática privada LIFE_VAR: Número = 10; // escala estática privada de la escala promedio SCALE_AVG: Number = 1; // variación de escala const. estática privada SCALE_VAR: Número = 0.4; // escala tiempo de crecimiento privado const. estática GROWING_TIME: Número = 5; // escala tiempo de encogimiento privado const. estática SHRINKING_TIME: Número = 10; // velocidad media estática privada const SPEED_AVG: Number = 10; // variación de velocidad const. estática privada SPEED_VAR: Number = 8; // promedio omega (velocidad angular) const. estática privada OMEGA_AVG: Número = 0; // variación omega constante estática privada OMEGA_VAR: Número = 5; // coeficiente de amortiguamiento privado const. estática DAMPING: Number = 0.1;

Paso 6: Añadir Inicializadores

¿Qué inicializadores necesitamos para crear nuestro efecto de partículas? Echemos un vistazo a la siguiente lista:

  • DisplayObjectClass - Este inicializador asigna un objeto de visualización específico a cada partícula, que será utilizado por un DisplayObjectRenderer para representar efectos de partículas. El constructor acepta una referencia de clase a la clase de objeto de visualización que deseamos instanciar; para este tutorial, esta clase será la clase Star (símbolo) que creamos en el Paso 2.
  • Vida - Este inicializador asigna a cada partícula un valor de vida aleatorio. Más adelante, agregaremos acciones al emisor para agotar este valor de vida a través del tiempo y para marcar una partícula como muerta si su valor de vida llega a cero. Se pasa un objeto aleatorio al constructor, que será utilizado por este inicializador para generar un valor aleatorio para la vida de las partículas. Para la mayoría de los casos, la clase UniformRandom es conveniente y suficiente; el primer parámetro del constructor UniformRandom es el valor central (o promedio) de los números aleatorios generados, y el segundo es el radio (o variación). Por ejemplo, un objeto UniformRandom con centro 20 y variación 5 genera números aleatorios dentro del rango [15, 25]. Aquí usamos la constante LIFE_AVG para el valor central y LIFE_VAR para el radio.
  • Escala - Al igual que el inicializador de vida, el inicializador de escala inicializa la escala de una partícula a un valor aleatorio, determinado por un objeto aleatorio que se pasa al constructor del inicializador. Aquí usamos la constante SCALE_AVG para el valor central y SCALE_VAR para el radio.
  • Posición - Este inicializador asigna una partícula a una posición aleatoria. A diferencia de los inicializadores de vida y escala, que solo necesitan números aleatorios 1D, el inicializador de posición requiere generadores de pares de números aleatorios 2D. Como se describe en la sección Responsabilidades de la Clase de Stardust, la clase de Zona es exactamente para este propósito. El objeto de zona pasado al constructor del inicializador se utiliza para generar pares de números aleatorios 2D, que se asignarán a las partículas como vectores de posición. En este tutorial vamos a hacer que las estrellas salgan disparadas desde un solo punto ubicado en el cursor del mouse, así que usaremos una clase SinglePoint, que es una subclase de zona. Para poder ajustar dinámicamente la coordenada de este objeto SinglePoint desde la clase de documento, necesitamos exponer una referencia a este objeto puntual a través de una propiedad pública. Esto es para lo que es la propiedad "punto".
  • Velocidad - Al igual que el inicializador de posición, el inicializador de velocidad necesita un objeto de zona para generar pares de valores aleatorios 2D para inicializar las velocidades de las partículas. Un vector 2D generado por el objeto Zona, que es la coordenada de un punto aleatorio en la zona, se asigna a las partículas como sus velocidades. Aquí usamos la clase LazySectorZone que representa una región sectorial. Un sector es una porción de un círculo rodeado por dos radios y dos ángulos. Para LazySectorZone, los dos ángulos son 0 y 360 por defecto, lo que representa un ángulo completo alrededor de un círculo. El primer parámetro constructor de la clase LazySectorZone es el promedio de los dos radios, y el segundo es la variación de los radios. En este caso, el promedio de los dos radios representa la velocidad promedio, y la variación de los radios representa la variación de la velocidad. Aquí usamos la constante SPEED_AVG para el primer parámetro y SPEED_VAR para el segundo.
  • Rotación - El inicializador de rotación inicializa el ángulo de rotación de una partícula a un valor aleatorio. Y como algunos de los inicializadores mencionados anteriormente, el constructor acepta un objeto aleatorio para generar un valor aleatorio. Como nos gustaría tener partículas con ángulos de 0 a 360 grados, usaremos 0 como el centro y 180 como el radio del objeto UniformRandom.
  • Omega - Omega, como en la mayoría de los libros de texto de física, significa velocidad angular. Dicho esto, el propósito de este inicializador es claro: inicializa la velocidad angular de una partícula a un valor aleatorio, y la constante OMEGA_AVG se usa como el centro y OMEGA_VAR como el radio del objeto UniformRandom.

Y aquí está el código:

 point = new SinglePoint (); addInitializer (new DisplayObjectClass (Star)); addInitializer (new Life (nuevo UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (nueva escala (nuevo UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (nueva posición (punto)); addInitializer (nuevo Velocity (nuevo LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (nueva rotación (nuevo UniformRandom (0, 180))); addInitializer (nuevo Omega (nuevo UniformRandom (OMEGA_AVG, OMEGA_VAR)));

Paso 7: Agregando Acciones

Está bien, hemos terminado con los inicializadores. Ahora es el momento de agregar acciones al emisor. A continuación hay una lista de acciones que necesitamos:

  • Años - La acción Edad disminuye el valor de vida de una partícula en 1 en cada paso del emisor.
  • DeathLife - Cuando el valor de vida de una partícula llega a cero, esta acción marca la partícula como muerta, cambiando su propiedad isDead de falso a verdadero. Al final de un paso de emisor, se eliminan las partículas muertas..
  • Movimiento - Más o menos como su nombre lo sugiere, la acción Mover actualiza las posiciones de las partículas de acuerdo con sus velocidades.
  • Girar - Similar a la acción Mover, la acción Girar actualiza el ángulo de rotación de una partícula de acuerdo con el valor omega de la partícula (velocidad angular).
  • Mojadura - Esta acción multiplica la velocidad de una partícula con un factor dentro del rango [0, 1], simulando efectos de amortiguamiento y disminuyendo gradualmente la velocidad de la partícula. Un factor de uno significa que no hay amortiguación en absoluto: las partículas se mueven libremente como si no hubiera efecto de amortiguación; un factor de cero significa una amortiguación total: todas las partículas no pueden moverse un poco. Este factor está determinado por el "coeficiente de amortiguamiento" mediante esta fórmula: "factor = 1 - (coeficiente de amortiguamiento)". El parámetro pasado al constructor es el coeficiente de amortiguamiento; Aquí solo queremos un poco de efecto de amortiguación, así que usamos el valor 0.1 para el coeficiente.
  • ScaleCurve - La acción ScaleCurve cambia la escala de una partícula de acuerdo con su valor de vida. Crece de una escala inicial a una escala normal después del nacimiento, y se desvanece a una escala final a medida que muere. Por supuesto, una partícula también puede tener un valor de escala inicial o final que es más grande que la escala normal; sólo depende de la elección personal. En muchos casos, nos gustaría que las partículas tuvieran un valor de escala inicial y final de cero, que es el valor predeterminado. El primer parámetro en el constructor representa el tiempo de crecimiento de una partícula, y el segundo es el tiempo de desvanecimiento; así que pasamos las constantes GROWING_TIME y SHRINKING_TIME como el primer y segundo parámetro, respectivamente. El tiempo de crecimiento es de 5, lo que significa que una partícula crece de escala cero a escala normal durante sus primeras 5 unidades de vida útil; y el tiempo de contracción es 15, lo que significa que una partícula se contrae a escala cero en las últimas 15 unidades de vida útil. Tenga en cuenta que la transición es lineal por defecto, pero se puede usar cualquier función de suavizado, específicamente las ecuaciones de suavizado creadas por Robert Penner. Hay otra acción similar llamada AlphaCurve, que funciona en valores alfa de la misma manera.

Eso es. Nuestro emisor está hecho. Aquí está el código para este emisor en su totalidad, incluidas las declaraciones de importación necesarias.

 paquete import idv.cjcat.stardust.common.actions.Age; importar idv.cjcat.stardust.common.actions.DeathLife; importar idv.cjcat.stardust.common.actions.ScaleCurve; importar idv.cjcat.stardust.common.clocks.Clock; importar idv.cjcat.stardust.common.initializers.Life; importar idv.cjcat.stardust.common.initializers.Scale; importar idv.cjcat.stardust.common.math.UniformRandom; importar idv.cjcat.stardust.twoD.actions.Damping; importar idv.cjcat.stardust.twoD.actions.Move; importar idv.cjcat.stardust.twoD.actions.Spin; importar idv.cjcat.stardust.twoD.emitters.Emitter2D; importar idv.cjcat.stardust.twoD.initializers.DisplayObjectClass; importar idv.cjcat.stardust.twoD.initializers.Omega; importar idv.cjcat.stardust.twoD.initializers.Position; importar idv.cjcat.stardust.twoD.initializers.Rotation; importar idv.cjcat.stardust.twoD.initializers.Velocity; importar idv.cjcat.stardust.twoD.zones.LazySectorZone; importar idv.cjcat.stardust.twoD.zones.SinglePoint; clase pública StarEmitter extiende Emitter2D / ** * Constantes * / const. estática privada LIFE_AVG: Número = 30; constata estática privada LIFE_VAR: Número = 10; constata estática privada SCALE_AVG: Número = 1; constata estática privada SCALE_VAR: Número = 0.4; constata estática privada GROWING_TIME: Número = 5; constata estática privada SHRINKING_TIME: Número = 10; constata estática privada SPEED_AVG: Número = 10; constata estática privada SPEED_VAR: Number = 8; constata estática privada OMEGA_AVG: Número = 0; constata estática privada OMEGA_VAR: Número = 5; DAMPING estático privado: Número = 0.1; punto de var público: SinglePoint; función pública StarEmitter (reloj: reloj) super (reloj); point = new SinglePoint (); // inicializadores addInitializer (new DisplayObjectClass (Star)); addInitializer (new Life (nuevo UniformRandom (LIFE_AVG, LIFE_VAR))); addInitializer (nueva escala (nuevo UniformRandom (SCALE_AVG, SCALE_VAR))); addInitializer (nueva posición (punto)); addInitializer (nuevo Velocity (nuevo LazySectorZone (SPEED_AVG, SPEED_VAR))); addInitializer (nueva rotación (nuevo UniformRandom (0, 180))); addInitializer (nuevo Omega (nuevo UniformRandom (OMEGA_AVG, OMEGA_VAR))); // acciones addAction (new Age ()); addAction (nuevo DeathLife ()); addAction (new Move ()); addAction (new Spin ()); addAction (nueva amortiguación (DAMPING)); addAction (nuevo ScaleCurve (GROWING_TIME, SHRINKING_TIME)); 

Paso 8: Termina la clase de documento

Ahora es el momento de volver a la clase de documentos y terminarla. Echemos un vistazo a las tareas restantes..

  • Crear una instancia de StarEmitter - Vamos a crear una instancia de la clase StarEmitter que acabamos de terminar.
  • Asignar un objeto de reloj al emisor - Queremos una tasa constante de emisión de partículas, por lo que usaremos la clase SteadyClock. El parámetro que se pasa al constructor del reloj es la tasa de emisión o, en otras palabras, el número de nuevas partículas creadas en cada paso del emisor; una tasa fraccionaria de 0.5 significa en cada paso del emisor, hay un 50% de probabilidad de que se cree una nueva partícula y un 50% de probabilidad de que no se cree ninguna partícula.
  • Crear un renderizador - Para visualizar el efecto de partículas, necesitaremos un renderizador. El DisplayObjectRenderer debe usarse junto con el inicializador DisplayObjectClass: el inicializador asigna un objeto de visualización a cada partícula, y el renderizador agrega estos objetos de visualización a la lista de visualización de un contenedor, actualizándolos constantemente. Además, no olvides añadir el emisor al renderizador..
  • Llama al bucle principal repetidamente - Este último paso mantiene Stardust en funcionamiento. Aquí haremos uso del evento enter-frame..
  • A continuación se muestra el código completo de la clase de documento, incluidas las declaraciones de importación necesarias.

 paquete import flash.display.Sprite; importar flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Rectangle; importar idv.cjcat.stardust.common.clocks.SteadyClock; importar idv.cjcat.stardust.common.renderers.Renderer; importar idv.cjcat.stardust.twoD.renderers.DisplayObjectRenderer; la clase pública StarParticles extiende Sprite private var emitter: StarEmitter; función pública StarParticles () // crear una instancia del emisor de StarEmitter = nuevo StarEmitter (nuevo SteadyClock (0.5)); // el contenedor sprite var container: Sprite = new Sprite (); // el renderizador que representa el renderizador var del efecto de partículas: Renderer = new DisplayObjectRenderer (container); renderer.addEmitter (emisor); // agregar el contenedor a la lista de visualización, sobre el fondo addChildAt (container, 1); // hacer uso del evento enter-frame addEventListener (Event.ENTER_FRAME, mainLoop);  función privada mainLoop (e: Evento): void // actualizar la posición de SinglePoint a la posición del mouse emitter.point.x = mouseX; emitter.point.y = mouseY; // llamar al bucle principal emitter.step (); 

¡Finalmente, hemos terminado! Ahora echemos un vistazo al resultado. Presione CTRL + ENTRAR en Flash para probar la película y verá el resultado.


Variación 1: Estrellas animadas

¡No hemos terminado todavía! Hagamos algunas variaciones más. El primero es usar clips de película animados para nuestras partículas..

Paso 9: Crear una animación de línea de tiempo

Esta primera variación es bastante simple, no implica ninguna codificación adicional. Es tan simple como crear una animación de línea de tiempo básica. Edite el símbolo de la estrella en Flash IDE, cree otro fotograma clave y cambie el color de la estrella en este marco a rojo. Esto esencialmente hace que las estrellas parpadeen entre amarillo y rojo. Es posible que desee insertar más marcos vacíos en el medio, ya que una velocidad de fotogramas de 60 fps es demasiado rápida para un parpadeo de dos cuadros.

Ahora prueba la película y comprueba el resultado. El efecto de estrella parpadeante parece caricaturesco; esto se puede usar para los efectos clásicos de mareos, que se ven comúnmente en los dibujos animados.


Variación 2: Ajuste de escala de tiempo dinámicamente

Como mencioné anteriormente, una de las características de Stardust es "escala de tiempo de simulación ajustable", lo que significa que la escala de tiempo utilizada por Stardust para la simulación de partículas se puede ajustar de manera dinámica. Todo se hace cambiando la propiedad Emitter.stepTimeInterval, que es 1 de forma predeterminada. El siguiente fragmento de código cambia este valor a 2, lo que hace que las partículas se muevan dos veces más rápido y que el emisor cree nuevas partículas a doble velocidad..

 emitter.stepTimeInterval = 2;

En esta variación, crearemos un control deslizante en el escenario y lo utilizaremos para ajustar dinámicamente la escala de tiempo de la simulación.

Paso 10: crear un control deslizante

Arrastre un componente Slider desde el Panel de componentes al escenario. Nombra "deslizador".

Paso 11: Configurar los parámetros del control deslizante

Nos gustaría que el control deslizante se deslice entre 0.5 y 2