martes, 31 de julio de 2012

Sistema de partículas en AndEngine parte 1


Primeros pasos en la creación de Vídeos Juego


Hola a todos nuevamente en este post voy a tratar de comenzar a hablarles de partículas. Creo que es un tema muy interesante y entretenido, pero seguramente al principio puede ser un poco tedioso, hasta que adquiramos los conocimientos necesarios. Bueno ahora a comenzar ;)


El sistema de partículas es  una parte fundamental de un juego, que uno a visto una infinidad de veces, aunque no te hayas dado cuenta exactamente de cual era. (suele pasar hasta que uno aprende sobre un tema :D ) Este sistema nos resuelve el problema, que nos puede dar, un patrón de muchas partículas en movimiento. Pensemos por ejemplo en el fuego, el humo, o la lluvia; donde vamos a necesitar una gran cantidad de partículas para lograr un efecto que intente parecer real. Las partículas pueden seguir reglas, pero para darles un efecto real, debe haber algo de “aleatoriedad” para que se asemeje a la realidad. Este sistema nos provee un entorno, para crear un emisor de partículas  ( que es un efecto individual ). Esto es mucho más común verlo en juego 3D, pero AndEngine nos proporcionan varios ejemplos dentro de su paquete de ejemplos y además podemos crear nuestros propios emisores ;)


Se están preguntando que  es un emisor de partículas?

AndEngine como dije antes, nos proporciona un entorno para crear y ejecutar emisores de partículas. Estos emisores nos sirven para crear patrones de partículas desde una posición de la pantalla. Tratar de representar esas partículas con los sprite, crearían una sobrecarga demasiado grande para un motor de juego común, incluyendo al de AndEngine. Lo que necesitamos entonces para resolver esto, es un subsistema  especial, que comience con una textura  y pueda ir modificando en el tiempo, imitando la física de las partículas para lograr un buen efecto. Crear un emisor convincente es tanto un arte ( algo para lo que no soy bueno ) como una ciencia. La codificación de uno, no es realmente complicado, pero el crear un efecto real y convincente, nos va  a tomar seguramente muchas pruebas y error, teniendo en cuenta que hasta el cambio más pequeño e insignificante puede lograr una verdadera diferencia en el resultado. Y hay que sumarle a esto que además los emisores de partículas, generalmente no funcionan del todo bien en el emulador de Android, asi que como nos va a resultar muy difícil depurar el efecto desde el mismo, va  a ser muy recomendable que lo prueben en un dispositivo real.


Cómo funciona?

El arte en esto, viene en los fenómenos naturales que queramos modelar. Nosotros sabemos lo que el fuego parece, pero si nos ponemos a mirar, este cuenta con una gran cantidad de partículas corriendo por ahí. Pensemos en la llama de la vela, donde tenemos un exterior color rojo, un interior  amarillo brillante, que se va degradando junto a un azul. El calor de la mecha que hace que las moléculas de cera se vayan evaporando y finalmente las corrientes aleatorias que afectan el movimiento de la llama.
Para modelar este comportamiento en un emisor de partículas, ahi algunas cosas que sabemos cómo se van a comportar y otras que necesitamos que sean aleatorias. Por ejemplo sabemos que la llama,comenzará cerca de la mecha y normalmente saldrá hacia arriba. Pero el detalle esta en que el ángulo exacto en que salen hacia arriba debe ser aleatorio, al igual que la variación de los colores de la misma, donde va a comenzar por uno, puede pasar por varios en el medio, y finalmente terminara en un color totalmente diferente. También sabemos que no todas las partículas cambian de color a la vez, así que ese comportamiento también deberá ser aleatorio, al igual que la velocidad del movimiento de las misma.
Lo bueno de esto, es que podremos  generar una masa ( de miles por ejemplo ) de partículas, estableciendo algunos parámetros básicos  y aplicar la variación de los parámetros para el comportamiento al azar. Las partículas, pueden responder a la gravedad de forma positiva, negativa o ausente. También se puede asociar, un tiempo de vida, tamaño, color dirección, aceleración y giro, en resumen puede cambiar todo. También podemos modificar la forma en que las partículas se mezclan con el fondo o incluso como lo cubre.


Ahora vamos a ver como es el sistema de partículas en AndEngine.
Este sistema, en AndEngine es una jerarquía de componentes:

ParticleSystem: Este componente comprende el efecto del conjunto, esto se refiere al ParticleEmitter, una pequeña textura en OpenGL y algunos parámetros que controlan la velocidad y la  cantidad degeneraciónn de particulas.

ParticleEmitter: Este componente genera,  muestra  y controla la modificación de las partículas en el lapso de su vida. Ahí diferentes tipo, y cada uno va a definir la zona y la forma en la que se generarán las partículas. Para cada partícula esté, de manera aleatoria genera la posición inicial, la velocidad , aceleración, rotación, gravedad , color  y transparencia dentro de los límites que nosotros definimos dentro del ParticleInitializers.

Particle: Este es el elemento individual generado y mostrado por el ParticleEmitter. Todas las partículas además de los efectos, tienen la misma textura OpenGL que puede ser cualquier textura ( pequeña ). Al mismo tiempo cada , cada partícula tiene su propio periodo de vida y parámetros ( que pueden ir cambiando durante su lapso de vida con el ParticleModifiers ).

ParticleInitializers: Este componente establece las condiciones iniciales para el efecto que tendrán todas las partículas.  Este proporciona un rango de valores mínimos y máximos, para la velocidad, la aceleración, rotación, gravedad, color y transparencia de las partículas. Después el ParticleEmitter toma valores aleatorios que están dentro del rango que hemos establecido, en cada una de las partículas que se generan.

ParticleModifiers: Este componente le dice al ParticleSystem como modificar cada partícula a lo largo de su vida. Este modificador existe durante toda la vida de la partícula definiendo la hora de inicio y fin, como los parámetros máximos y mínimos. Durante cada actualización, el ParticleEmitter ajusta los valores para cada partícula siguiendo las instrucciones del ParticleModifiers


ParticleSystemEste tiene un constructor, que necesita que le pasemos unos simples parámetros:

ParticleSystem(final IParticleEmitter pParticleEmitter, final float pMinRate,final float pMaxRate, final int pMaxParticles,
final TextureRegion pTextureRegion)


Los parámetros son muy sencillos el rate maximo y minimo se dan en partículas por segundo, y el ParticleSystem de manera aleatoria va usando ese rango.

El TextureRegion lo vamos a usar para todas las partículas del sistema. Obviamente deberemos cargar el TextureRegion antes de poder llamar a su constructor. Usando los mismos metodos que se usan para cargar los sprites y cualquier otra cosa en AndEngine.

ParticleEmitters: Si queremos crear un ParticleSystem vamos a necesitar un ParticleEmitters, se han creado diferente clases, para el efecto que deseemos que tenga nuestro ParticleEmitter. Cada emisor genera partículas en posiciones aleatorias, dentro de los parámetros que nosotros le pasemos. AndEngine usa la utilidad Random de Java para generar de manera aleatoria partículas, hay varios tipos de emisores:

CircleParticleEmitter: Este emisor se utiliza cuando queremos que las partículas salgan de una región elíptica o circular en la pantalla.
Estos son los constructores:
CircleParticleEmitter(final float pCenterX, final float pCenterY,
final float pRadius)

CircleParticleEmitter(final float pCenterX, final float pCenterY,
final float pRadiusX, final float pRadiusY)


El primer constructor usa un área circular con centro en  (pCenterX, pCenterY), y el segundo constructor usa un área elíptica. Las partículas se generan manera aleatoria, dentro de las áreas con forma de círculo o elipse. La elipse puede girar a cualquier ángulo con un RotationInitializer.

CircleOutlineParticleEmitter: Este emisor también utiliza una forma circular o eliptica, pero en este caso las partículas se despliegan por el borde de las mismas.

CircleOutlineParticleEmitter(final float pCenterX, final float pCenterY,final float pRadius)
CircleOutlineParticleEmitter(final float pCenterX, final float pCenterY,final float pRadius)


Los parámetros son los mismo que en el anterior emisor.

PointParticleEmitter: Con este emisor las partículas emergen simplemente de un punto.

PointParticleEmitter(final float pCenterX, final float pCenterY)
RectangleParticleEmitter: Este emisor como su nombre lo dice, genera partículas en forma de rectángulo, donde obviamente si una de sus dimensiones es 0, puede hacerlo en forma de una línea.
RectangleParticleEmitter(final float pCenterX, final float pCenterY,final float pWidth, final float pHeight)

Al igual que con el emisor en forma de círculo o elipse, con un RotationInitializer se puede ajustar el ángulo del mismo ;)

RectangleOutlineEmitter: Al igual que como los emisores anteriores, este genera las partículas en los bordes.
RectangleOutlineParticleEmitter(final float pCenterX, final float pCenterY,final float pWidth, final float pHeight)
ParticleInitializers: Cuando creamos el sistema de partículas  con el ParticleInitializer podemos crear y añadir  a nuestro sistema, los emisores para poder controlar la su configuración inicial.

Hay inicializadores para la aceleración, gravedad, colores, etc etc.Todos estos inicializadores nos permiten establecer un valor fijo o un rango para nuestros inicializadores.

AccelerationInitializer: Este grupo de metodos nos permite establecer la aceleracion de partida para las partículas generadas en nuestro sistema.

AccelerationInitializer(final float pAcceleration)
AccelerationInitializer(final float pAccelerationX, final float pAccelerationY)
AccelerationInitializer(final float pMinAccelerationX, final float pMaxAccelerationX, final float MinAccelerationY, final float pMaxAccelerationY)


Los primeros dos inicializadores generar valores fijos, el tercer constructor es más flexible, lo que nos permite especificar los rango de inicialización. Las direcciones x e y son relativas a nuestro emisor.

AlphaInitializer: Estos dos metodos especifican la transparencia que van a tener las partículas en un comienzo.

AlphaInitializer(final float pAlpha)
AlphaInitializer(final float pMinAlpha, final float pMaxAlpha)


Como antes, tenemos la opción de un valor fijo, o al azar.

ColorInitializer: Estos metodos establecen los colores de inicio de nuestras particulas.

ColorInitializer(final float pRed, final float pGreen, final float pBlue)
ColorInitializer(final float pMinRed, final float pMaxRed, final float pMinGreen,
final float pMaxGreen, final float pMinBlue, final float pMaxBlue)


El primer constructor inicializa directamente el color de las partículas, y  el segundo genera valores aleatorios.

GravityInitializer: Este método puede ser usado para activar la gravedad (Que es lo mismo que establecer la aceleración en el valor fijo de la gravedad de la Tierra).

RotationInitializer: Este método establece la rotación inicial de nuestro emisor que puede ir desde 0 a 360 grados.
RotationInitializer(final float pRotation)
RotationInitializer(final float pMinRotation, final float pMaxRotation)


VelocityInitializer : Este método puede setear la velocidad inicial de las partículas:
VelocityInitializer(final float pVelocity)
VelocityInitializer(final float pVelocityX, final float pVelocityY)
VelocityInitializer(final float pMinVelocityX, final float pMaxVelocityX, final float
pMinVelocityY, final float pMaxVelocityY)


Este es muy similar al AccelerationInitializer, con excepción que ahora vamos a iniciar la velocidad inicial de las partículas, y también la x e y son relativas al emisor.

ParticleModifiers: ahora que hemos iniciado nuestro sistema, tenemos que decir en que manera las partículas van a cambiar a lo largo de su ciclo de vida, para eso utilizaremos esto.

AlphaModifier: Modifica gradualmente la transparencia de las partículas a lo largo de su ciclo de vida:
AlphaModifier(final float pFromAlpha, final float pToAlpha,
final float pFromTime, final float pToTime)


ColorModifier: Con este se puede ir cambiando el color a lo largo de su vida.
ColorModifier(final float pFromRed, final float pToRed, final float pFromGreen,
final float pToGreen, final float pFromBlue, final float pToBlue,
final float pFromTime, final float pToTime)


ExpireModifier: Simplemente define el tiempo de vida de las partículas.

ExpireModifier(final float pLifeTime)
ExpireModifier(final float pMinLifeTime, final float pMaxLifeTime)


El primer constructor define el mismo tiempo de vida para todas las partículas, mientras que el segundo define de manera aleatoria, dentro del rango indicado.

RotationModifier: Este metodo gira las partículas durante el tiempo indicado.

RotationModifier(final float pFromRotation, final float pToRotation,final float pFromTime, final float pToTime)

ScaleModifier: Cambia la escala de la particula a lo largo de la vida de la misma.

ScaleModifier(final float pFromScale, final float pToScale,
final float pFromTime, final float pToTime)
ScaleModifier(final float pFromScaleX, final float pToScaleX,
final float pFromScaleY, final float pToScaleY, final float pFromTime,final float pToTime)


El primer constructor lo hace de manera uniforme en ambas direcciones (X e Y), mientras que el segundo lo hace de manera asimétrica.

Cositas a saber sobre nuestro ParticleSystem:


Este trar algunos metodos integrados que son bastantes útiles, por ejemplo podemos iniciarlo y detenerlo, o establecer la manera en que se mezcla con otras texturas. Por ejemplo para iniciar o detener las partículas podemos usar:
void setParticlesSpawnEnabled(final boolean pParticlesSpawnEnabled)


Simplemente con true, las iniciamos y con false las paramos.
Tambien podemos comprobar su estado con:
boolean isParticlesSpawnEnabled()
Se puede ajustar la manera en que OpenGL mezcla diferentes texturas en pantalla:
void setBlendFunction(final int pSourceBlendFunction, final int pDestinationBlendFunction)

Por supuesto que el trato con OpenGL puede ser extremadamente más complejo, cosa que por ahora no puedo explicar, pero va a ser cuestión de investigar, que otras cosas más podemos configurar.


Fuentes de referencia:

http://www.andengine.org/blog/

http://www.andengine.org/forums/

https://github.com/nicolasgramlich/AndEngine


Este recurso es uno de los mas importantes:
http://code.google.com/p/andengineexamples/

Y una muy buena lectura el libro Learnin Android Game Programing:

http://www.amazon.com/Learning-Android-Game-Programming-Hands-On/dp/0321769627

Por supuesto que esto no ha terminado aún, es más no hemos visto lo interesante :D pero es necesario este conocimiento para poder empezar a trabajar con partículas dentro de AndEngine.
Espero no haberlos aburrido mucho, creo que el proximo post va a estar bastante más entretenido ( por lo menos para mi gusto ;) )
Es todo por ahora, como siempre les recomiendo mucho tratar de leer la docu oficial y ver los ejemplos que ellos tienen alojados allí.


Saludos a todos, Gabriel E. Pozo


P.D: Si ya lo se, un post que no tiene ninguna imagen :D, en el proximo les prometo que va a estar mas entretenido ;)