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 ;)



sábado, 7 de julio de 2012

Utilizando Tile Maps en AndEngine



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



Hola a todos, si nuevamente por acá, esta vez les voy a hablar de un tema quizás no tan divertido, y como no soy diseñador gráfico, de ninguna manera piensen que puedo crear uno lindo jeje. Pero es muy importante conocerlo y saber como usarlo ya que es una parte fundamental de cualquier juego, así que aquí vamos.

Muchos de los juegos originales de arcade, están basados en Tiled para crear la escena del juego. En este post vamos a ver como manejar estos tiled con AndEngine.

Ahora me imagino que se estarán preguntando, porque usar Tile Maps? (y lo mas importante, también que es un Tile Maps)

Hay dos ventajas principales para utilizar Tile Maps, que fueron muy valiosas para los juegos en las primeras computadoras personales, y lo siguen siendo ahora, sobre todo en dispositivos móviles:

  • Para mucho de los juegos que intentemos armar, cuando diseñemos el escenario del juego, lo mas probable es que deseemos que este sea grande, y además extensible de una manera sencilla. En lugar de crear un bitmaps gigante, que demoremos una eternidad en cargar, y que nos consuma una enorme cantidad de recursos. Podemos utilizar unas pequeñas imágenes (los queridos tiled ) que se se repitan una y otra vez, formando el campo de juego que nosotros queremos y los grande que deseemos (Tile Maps).
  • Una ventaja es que con los Tiled se puede facilitar la detección de colisiones. En estos momentos existen muchas maneras de detectar colisiones, pero con los tiled esto se puede realizar consumiendo muy pocos recursos.

Tipos de Tile Maps:

Un tile maps es una imagen formada por un array polígonos repetidos. Para un tile maps sencillo, los polígonos normalmente son cuadrados. De esta manera podríamos pensar que es similar a una rejilla, donde al colocar los tiled de forma ordenada, colectivamente en conjunto terminaran formando una imagen, que es la que utilizaremos en nuestro escenario de juego.


Tile Maps Ortogonal:

La vista es directamente desde arriba, y los tiled normalmente son cuadrados, aunque a veces también se usan rectangulares. Este tipo de tile maps fue el primer tipo creado y tal vez el mas popular utilizado en los juegos. Este tipo es el mas sencillo, porque en ningún momento hay una superposición de los tiled .




Tile Maps Isométrico:

Este es otro tipo popular de tiled maps, la idea de este es crear una especie de efecto 3D (falso :D ) donde en vez de ver el territorio directamente desde arriba, se ve aproximadamente desde 45º grados.
Con este cambio de vista suceden 2 cosas.
  • El tiled cuadrado se ve transformado en forma de un rombo o diamante.
  • Algunas partes de los tiled mas cercanos, se terminan superponiendo sobre las que se encuentra en la parte posterior a la misma.

Tengamos en cuenta, que a pesar de este lindo efecto, de esta manera no puede lograrse lo mismo que se puede hacer con OpenGL en un juego verdaderamente en 3D.





Estructura de un Tile Maps.

El tiled maps esta formado por 3 partes, el mapa, el conjunto de tiled , y la imagen que provee la textura para los tiled . El mapa en si mismo es una estructura jerárquica.
  • Cada tiled tiene estas características, incluye su ID, que es la posición en el mapa y un ID global que identifica la textura que debería mostrar el tiled desde el Tiled set.
  • Los tiled se asignan a capas, cada una de ellas son una mapa completo de la zona 2D cubiertos por los tiled .
  • Las capas estas se combinan para formar el mapa.

Como dije antes, estos tile maps se han utilizado durante mucho tiempo en juego, y se ha desarrollado un formato estándar para guardar los tiled sets y el resultado de los tile maps. Estos nos sirven en resumen para poder crear y editar mapas sobre la base de estos estándares.

Archivos TMX y TSX:

Los archivos TMX es usado para los tiled maps, y los TSX para los tiled set, ambos tipos de archivos están basados en el formato XML. Los 2 trabajan juntos, donde el la mayoría de los archivos TMX hacen referencia a un archivo TSX para obtener información del lite set. Los archivos TMX se pueden integrar a AndEngine de una manera muy sencilla, se pueden cargar, manipular y procesar mediante un API bastante sencillo.


TMXLoader:

AndEngine incluye la clase TMXLoader que sabe como parsear y cargar archivos TMX y TSX dentro de un objeto TMXTiledMap. Deberíamos usar la clase TMXLoader primero para crear un nuevo objeto, posee varios constructores, este es el mas completo:

TMXLoader(final Context pContext, final TextureManager pTextureManager,
final TextureOptions pTextureOptions,
final ITMXTilePropertiesListener pTMXTilePropertyListener)

Los únicos dos parámetro obligatorios, son Context y TextureManager. Una vez creado el objeto, nosotros podemos usarlo para cargar el tiled map con uno de estos dos métodos:
TMXTiledMap loadFromAsset(final Context pContext, final String pAssetPath)
TMXTiledMap load(final InputStream pInputStream)

El primer método es el mas conveniente a menos que tenga algún problema para abrir el archivo .tmx cualquiera de estos pueden darnos una excepción del tipo TMXLoadException . El retorno es la raíz que vamos a usar para acceder a toda la información del tiled map.

TMXTiledMap es la clase AndEngine que corresponde a un tiled map entero, con todas sus capas, tiled , y las propiedades.
Normalmente no vamos a usar el constructor para crear todo el mapa, sino que vamos tomar el objeto para cargar un tiled como se ha mencionado antes. En cambio, si vamos a usar métodos getter TMXTiledMap para acceder a los contenidos del tiled maps como estos:

int getTileColumns()
int getTileRows()
int getTileWidth()
int getTileHeight()
ArrayList<TMXTileSet> getTMXTileSets()
ArrayList<TMXLayer> getTMXLayers()
ArrayList<TMXObjectGroup> getTMXObjectGroups()
TMXProperties<TMXTileProperty> getTMXTilePropertiesByGlobalTileID(
final int pGlobalTileID)
TMXProperties<TMXTiledMapProperty> getTMXTiledMapProperties()
TMXProperties<TMXTileProperty> getTMXTileProperties(
final int pGlobalTileID)

Y este:
TextureRegion getTextureRegionFromGlobalTileID(final int pGlobalTileID)

Este ultimo método nos permite recuperar el TextureRegion resultante de la creación del tiled maps una vez que se ha cargado.
Los Tile Maps se componen de capas, cada capa tiene su propio mapa de tiled . Ya hemos visto que podemos recuperar la lista de capas en un mapa con un objeto TMXTiledMap. Podemos seleccionar una capa en concreto y utilizar sus métodos para recuperar o establecer información sobre esa capa del mapa.
También podemos usar estos métodos:
TMXTile[][] getTMXTiles()
TMXTile getTMXTile(final int pTileColumn, final int pTileRow)
TMXTile getTMXTileAt(final float pX, final float pY)

Para que nos retorne una referencia a un objeto TMXTile y así podemos usar sus métodos getters y setters, dos métodos interesantes de estos son:

int getGlobalTileID()
void setGlobalTileID(final TMXTiledMap pTMXTiledMap, final int pGlobalTileID)

Si se acuerdan, yo ya había mencionado el ID Global, estos son asignados cuando construimos el tile map, para eso pueden usar por ejemplo el programa Tiled QT, o el que prefieran ustedes ;) Por lo tanto usted puede utilizar este método para manipular las imágenes que se muestran en tiempo de ejecución.

En este post no voy a hablar sobre como armar sus archivos .tmx, o como usar el editor Tiled QT, eso lo podemos llegar a ver mas adelante, o pueden Googlear un poco, ya que no es algo exclusivo de AndEngine. Además que no me gusta mucho el diseño jeje.

Acá les pongo de ejemplo, código fuente java, donde utilizamos el tiled map,


package com.aprendiendo.deandroid.ymas;

imports
/* Acá iría una lista grande de import que te los agrega de manera automática Eclipse, si usan ese IDE ;) */

public class MuestraTIled extends BaseGameActivity {
/* Estas son las constantes */

private static final int CAMERA_WIDTH = 480;
private static final int CAMERA_HEIGHT = 320;
private String tag = "WAVActivity";

private Handler mHandler;
protected Camera mCamera;
protected Scene mMainScene;
private TMXTiledMap mWAVTMXMap;
private TMXLayer tmxLayer;
private TMXTile tmxTile;
private int[] imagenes = new int[50];
private int coffinPtr = 0;
private int mCoffinGID = -1;
private int mOpenCoffinGID = 1;
private Random gen;

/* estos son los metodos que debemos implementar*/

@Override
public Engine onLoadEngine() {
mHandler = new Handler();
gen = new Random();
this.mCamera = new Camera(0, 0, CAMERA_WIDTH,
CAMERA_HEIGHT);
return new Engine(new EngineOptions(true,
ScreenOrientation.LANDSCAPE,
new RatioResolutionPolicy(CAMERA_WIDTH,
CAMERA_HEIGHT), this.mCamera));
}
@Override
public void onLoadResources() {
}
@Override
public Scene onLoadScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene(1);
try {
final TMXLoader tmxLoader = new TMXLoader(
this, this.mEngine.getTextureManager(),
TextureOptions.BILINEAR_PREMULTIPLYALPHA,
new ITMXTilePropertiesListener() {
@Override
public void onTMXTileWithPropertiesCreated(
final TMXTiledMap pTMXTiledMap,
final TMXLayer pTMXLayer,
final TMXTile pTMXTile,
final TMXProperties<TMXTileProperty>
pTMXTileProperties) {
if(pTMXTileProper-
ties.containsTMXProperty("imagen", "true")) {
imagenes[coffinPtr++] =
pTMXTile.getTileRow() * 15 +
pTMXTile.getTileColumn();
if (mCoffinGID<0){
mCoffinGID =
pTMXTile.getGlobalTileID();
}
}
}
});
this.mWAVTMXMap = tmxLoader.loadFromAsset(this,
"gfx/WAV/WAVmap.tmx");
} catch (final TMXLoadException tmxle) {
Debug.e(tmxle);
}
tmxLayer = this.mWAVTMXMap.getTMXLayers().get(0);
scene.getFirstChild().attachChild(tmxLayer);
scene.setOnSceneTouchListener(new IOnSceneTouchListener() {
@Override
public boolean onSceneTouchEvent(
final Scene pScene,
final TouchEvent pSceneTouchEvent) {
switch(pSceneTouchEvent.getAction()) {
case TouchEvent.ACTION_DOWN:
/* Get the touched tile */
tmxTile = tmxLayer.getTMXTileAt(
pSceneTouchEvent.getX(),
pSceneTouchEvent.getY());
if((tmxTile != null) &&
(tmxTile.getGlobalTileID() == mOpenCoffinGID)) {
tmxTile.setGlobalTileID(mWAVTMXMap, mCoffinGID);
}
break;
}
return true;
}
});
mHandler.postDelayed(openCoffin,gen.nextInt(2000));
return scene;
}
@Override
public void onLoadComplete() {
}
private Runnable openCoffin = new Runnable() {
public void run() {
int openThis = gen.nextInt(coffinPtr);
int tileRow = imagenes[openThis]/15;
int tileCol = imagenes[openThis] % 15;
tmxTile = tmxLayer.getTMXTileAt(tileCol*32 + 16,
tileRow*32 + 16);
tmxTile.setGlobalTileID(mWAVTMXMap, mOpenCoffinGID);
mHandler.postDelayed(openCoffin,gen.nextInt(4000));
}
};
}



Después de las importaciones habituales, declaraciones de variables y la configuración del motor, las mayores diferencias que encontramos arrancan en el método onLoadScene (). Tratamos de cargar el Tile Map en AndEngine creando un objeto nuevo y pidiendo TMXLoader para crear el mapa desde el asset. Como vamos a crear el TMXLoader, vamos a sobreescribir el método onTMXTileWithPropertiesCreated () y lo utilizamos para realizar un seguimiento cada vez que se crea un tiled su propiedad se establece en true. Cuando cargamos un tiled, hacemos un seguimiento de su posición en una matriz, int imagenes[].

AndEngine espera encontrar el nombre de archivo .tmx en la carpeta assets, modificado por el llamado setAssetBasePath () en onLoadResources (). Si llegas a estar usando subcarpetas, vamos a tener que editar manualmente los archivos .tsx y .tmx. para agregar la ruta completa de la carpeta assets.

Ejemplo de archivo .tmx:

<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" width="15" height="10"
tilewidth="32" tileheight="32">
<tileset firstgid="1" source="gfx/WAV/archivotile.tsx"/>
<layer name="Tile Layer 1" width="15" height="10">
<data encoding="base64" compression="gzip">
H4sIAAAAAAAAC5VQQQ4AMAQTG/9/8rKDpBFlO/RAldYWkQ3wVF9o0QtYw6E2zylBd3cV+6ueD5
4nZG38pMvqoK2yoL6b+fX28mv0xjJMXhhvhDtug+XEWAIAAA==
</data>
</layer>
</map>


Y archivo .tsx:

<?xml version="1.0" encoding="UTF-8"?>
<tileset name="WAVTileset" tilewidth="32" tileheight="32" spacing="2"
margin="2">
<image source="gfx/img/imagenes.png" width="256" height="64"/>
<tile id="4">
<properties>
<property name="imagen" value="true"/>
</properties>
</tile>
</tileset>


Con el tiled map cargado, se recupera la capa 0 (la única que hemos creado). Y la colocamos como un hijo de la actual Scene. Ahora podemos crear un onSceneTouchListener () para capturar eventos del usuario. Cuando un ACTION_DOWN se produce, se recupera el tile tocado de la capa que hemos creado, utilizando el método getTileAt (). Asi que con este método podemos comprobar el ID global del tile, para por ejemplo poder cambiar la imagen que se encuentra en el mismo o generar un evento o una acción, que nosotros pretendamos mostrar.

Tiled Maps Isométrico:

Este tipo de tiled maps puede hacer un juego más interesante, proporcionando una sensación de "3D" sin tener las dificultades que puede tener la creación de los modelos 3D y sus animaciones. El primer desafío que este nos pone es el tema de la elaboración de los tiled para que se vean correctamente desde la perspectiva adecuada. También está el como acomodarlos para que se vea bien en el “eje z”, lo que puede hacer o deshacer la ilusión de “3D”. Algunos artistas gráficos prefieren crear tiled isométricos utilizando modelos 3D, y a continuación, para después colocar la cámara virtual en la correspondiente posición y hacer una renderizado 2D. Esto no tiene nada que ver con la diferencia técnica que comente anteriormente para crear las secuencias de animación de modelos 3D.

Fuentes de referencia:





Este recurso es uno de los mas importantes:


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


Espero que les allá gustado el post, espero no haberlos aburrido :D, mas adelante veremos como manejar colisiones de partículas y demás cosas. Seguramente sera mas divertido, también quería comentarles que no eh puesto el código completo del proyecto porque seria medio engorroso. Pero como pueden ver en las referencias que puse, se pueden bajar mucho código de ejemplo. Nos vemos en la próxima, espero poder hacerlo en poco tiempo.


Saludos a todos, Gabriel E. Pozo