Mapas isométricos en Flash
Tiles dibujables
Debido a que el mapa puede ser mucho más grande que la pantalla, no es factible dibujar todos los tiles del mapa en cada frame. Por lo tanto, antes de dibujar el mapa se debe verificar que tiles entran dentro del puerto de visualización para luego iterar por las filas y las columnas que corresponden.

Figura 8. El viewport muestra sólo parte del mapa isométrico
Tenemos la posición de viewport y su tamaño. Deseamos conocer en cada vértice extremo del vierport a que fila y columna del mapa corresponde. Por lo tanto, deseamos convertir de coordenadas de mundo plano a coordenadas de mapa.
rowcol = GetRowColFromPlaneWorldCoords(Viewport._x + Viewport._width, Viewport._y + Viewport._height);
var rowTo = Util.ClampTo(rowcol[0]+1, 0, ROWS);
rowcol = GetRowColFromPlaneWorldCoords(Viewport._x, Viewport._y);
var rowFrom = Util.ClampTo(rowcol[0], 0, ROWS);
rowcol = GetRowColFromPlaneWorldCoords(Viewport._x + Viewport._width, Viewport._y);
var colTo = Util.ClampTo(rowcol[1]+1, 0, COLS);
rowcol = GetRowColFromPlaneWorldCoords(Viewport._x, Viewport._y + Viewport._height);
var colFrom = Util.ClampTo(rowcol[1], 0, COLS);
Luego, podremos iterar por las filas y las columnas que ingresen en el rango especificado.
Dibujado del mapa en Flash
Utilizando la plataforma de desarrollo Macromedia Flash MX 2004, cada bloque del mapa será un movieclip que se creará dinámicamente y se agregará a un movieclip del referencia donde estará contenida toda la escena.
Ya hemos mencionado que no es factible dibujar todo el mapa cuando sólo se está viendo parte de él. Pues tampoco podremos crear tantos movieclips como bloques tengan nuestro mapa porque esto serÃa un derroche de recursos.
Crearemos tantos movieclips como bloques entren dentro del viewport en el peor caso, luego nos manejaremos con estos movieclips y en el caso de estar visualizando menos de la cantidad total creada, ocultaremos el exedente.
Nunca crearemos ni destruiremos movieclips en tiempo de dibujado.
Veamos ahora el algoritmo para la creación de los movieclips correspondientes cuando el mapa es construido:
// Calcula la cantidad máxima de tiles que entran en el puerto de visualización
var maxCols = Math.ceil(Viewport._width / (tw / 2));
var maxRows = Math.ceil(Viewport._height / (th / 2));
// Creo la cantidad de tiles máxima
for (var i=0; i<maxCols * maxRows; i++)
{
_mcBlocks[i] = targetClip.attachMovie(mcBlocks, "bck_" + i, i);
_mcBlocks[i]._visible = false;
}
// Guardo la cantidad máxima de movieclips que habrá en escena
_maxMovieClipCount = maxCols * maxRows;
Donde:
_mcBlocks: Es un array de movieclips.
tw: Ancho de cada tile.
th: Alto de cada tile.
col: Columna actual procesada.
row: Fila actual procesada.
Profundidad
Otro de los aspectos a tener en cuenta para la correcta visualización de los objetos que contendrá el mapa será el orden correcto en el dibujado de los mismos (si es que el dispositivo no posee algún mecanismo que haga de z-buffer).

Figura 9. El objeto delante y detrás de la referencia
En la figura anterior se pueden apreciar los dos casos clásicos. A la izquierda el objeto verde se encuentra sobre el rojo, pero a derecha esto es al revés.
En Macromedia Flash cada movie clip posee una profundidad (no es posible que dos movieclips se encuentren en la misma profundidad). La clase MovieClip posee un método llamado swapDepths que permite alterar la profundida de un movie clip por la de otro.
Entonces el objeto verde debe poder advertir esta situación y alernar su profundidad por la del objeto rojo ¿Y cómo hacemos esto? Como primer medida deberemos asignar a cada celda una profundidad calculada. La idea será que los valores mantengan la misma relación que en la siguiente figura:

Figura 10. Ejemplo de valores de profundidad
Aunque no es necesario que todos los valores de profundidad sean adyacentes.
La cuenta que podremos utilizar para calcular la profundidad es la siguiente:
prof. del bloque = ((COLS - col) * tw + row * th * COLS) * 2;
donde
COLS: Cantidad total de columnas.
tw: Ancho de cada tile.
th: Alto de cada tile.
col: Columna actual procesada.
row: Fila actual procesada.
Todos los bloques poseerán profundidades pares, Luego los objetos móviles poseerán profundidades impares lo cual asegurará que nunca objeto suplante un movieclip de tile existente.
Notar que el cálculo no arrojará los números expresados por la última figura sino que arrojará números que mantegan la misma relación relativa entre las celdas. Los valores reales según la fórmula propuesta será:
Suponiendo tw = 30 y th = 15:

Figura 11. Las profundidades calculadas para nuestro ejemplo
Ahora bastará obtener el tile sobre el cual está parado el personaje cada momento e intercambiar el depth con el valor de la profundidad de la celda en cuestión más uno:
_spriteMovieClip.swapDepths(tileblockdepth + 1);
Conversión de coordenadas
Coordenadas de mundo isométricas a coordenadas de mundo plano
Las primitivas fundamentales del motor de mapas isométricos es la correcta y eficiente conversión de coordenadas. Veamos como pasar de una a la otra.
Tal vez la conversión más importante sea la de mundo isométrico a mundo plano. Aquà pasaremos de un sistema de tres coordenadas a un sistema de dos coordenadas y lo que haremos será básicamente una proyección ortogonal de una posición.

Figura 12. Los dos sistemas de coordenadas
Para realizar la conversión emplearemos dos ecuaciones sencillas:

Figura 13. Cálculo a partir de proyecciones
Proyectaremos Xi e Zi sobre X, siendo la suma de estas proyecciones Xp. Luego proyectaremos Xi e Zi sobre Y, siendo su diferencia Yp:
Xp = Xi * Cos ?1 + Zi * Cos ?2
Yp = Xi * Sen ?1 – Zi * Sen ?2
Pero en todo mapa isométrico, el ángulo ?1 = ?2 (de otro modo no serÃa isométrico), entonces:
Xp = Xi * Cos ? + Zi * Cos ?
Yp = Xi * Sen ? – Zi * Sen ?
y:
Xp = (Xi + Zi) Cos ?
Yp = (Xi – Zi) Sen ?
Pero el cálculo de Yp no es del todo correcto, no estamos teniendo en cuenta la coordenada Yi que no modifica a Xp pero si modifica a Yp. Su agregado a nuestra segunda fórmula es muy simple:
Yp = (Xi – Zi) Sen ? + Yi
Por último, nuestro mapa no siempre posee su origen en el (0, 0) del mundo. PodrÃa estar ubicado en cualquier otra posición por lo tanto agregaremos la posibilidad de que esto pueda ser asÃ:
Xp = Xmapa + (Xi + Zi) Cos ?
Yp = Ymapa – [(Xi - Zi) Sen ? + Yi]
Tengamos en cuenta que ? siempre es:
alfa = ArcTg(th / tw)
Notar que todas las operaciones trigonométricas pueden ser precalculadas cuando el mapa es construido ya que la relación entre alto y ancho del tile se mantiene constante.





Comentarios (1)



MUY interesante esto =) felicitaciones por el trabajo