Este tutorial es una traducción y adaptación al español por Julio Laguna, Autorizada por el autor , del tutorial de TONYPA Tile Based Games sujeta a una licencia Creative Commons.
Creative Commons License

Juegos basados en tiles para Flash.
por Julio Laguna (Traducción) - Originalmente escrito en Inglés por TONYPA

1 Juegos basados en "tiles" para Flash.

1.20 Profundidad.

Hace ya tiempo que estamos trabajando, como se habrá dado cuenta, en un juego estrictamente en 2D. Esto realmente no está mal. Tanto en uno como en otro de los ejemplos que hemos trabajado, se trata de una vista superior y una vista lateral. Se trata de vistas muy utilizadas en muchos tipos de juegos 2D, muy válidas y muy sencillas de programar con Flash y ActionScript (bueno todo es relativo). Sin embargo en este tipo de vistas no incorpora esa sensación de saber cuando un objeto está mas cerca de otro, o delante o detrás, etc... mas propio de sistemas en 3D. En los sistemas 2D como el que hemos desarrollado y antes de entrar en las vistas isométricas, existe una solución ampliamente utilizada en otras épocas, la sensación de profundidad, que con un poco de trabajo podremos implementar. Observe el ejemplo bajo estas líneas y verá a lo que me refiero:




Capas en Flash

Seguramente si ha utilizado Flash en otras ocasiones, será consciente en como cuando dibujamos en Flash, los dibujos solapados se tapan entre si. Si estamos dibujando objetos en la misma capa, por defecto lo último que dibujamos tapa (se posiciona en el "front") a lo anterior. También puede cambiar este orden en el posicionamiento de los objetos con las opciones "bring to front/send to back" del menú Modify->Arrange, o seleccionando el objeto y pulsando CTRL+Flecha UP/DOWN.

Pero Flash nos brinda una opción fenomenal, al igual que otros muchos programas de dibujo, que es la posibilidad de dibujo en capas ("Layers"), lo cual es fenomenal para la organización de objetos. Los objetos dibujados en una capa superior a otra (mas arriba), tapan a aquellos que están en capas inferiores.

En la imagen de arriba se puede observar un ejemplo de lo dicho. El cuadrado rojo y el cuadrado azul están ambos dibujados en la misma capa. El cuadrado azul fue el último en dibujarse y por eso permanece al frente del rojo, tapandolo. El cuadrado amarillo está dibujado en la capa "Layer2", y puesto que la capa "Layer2" está situada por encima de la capa "Layer1", este tapa al resto de cuadrados, es el cuadrado, digamos mas al frente.

En la siguiente imagen, disponemos de 4 cuadrados, el rojo y el verde están contenidos dentro de un movieclip, "mc1", y el azul y amarillo están contenidos dentro del movieClip "mc2". Los cuadrados amarillo y azul tapán o están mas al frente que el verde y rojo, ya que mc2 está por encima de mc1.

Dentro de un movieClip podemos organizar los dibujo tal y como hemos comentado antes, sin embargo no podremos hacer que el azul quede por encima del rojo y al mismo tiempo que el amarillo esté por debajo, tapado por el rojo. En este caso las unidades de objetos, vienen marcadas por los movieClips "mc1" y "mc2".

Estos ejemplos que hemos visto hasta ahora, son sencillos de comprender y como denominador común está el hecho de que se trata de objetos arrastrados directamente a la escena utilizando el entorno de Flash. Sin embargo no es lo que estamos haciendo nosotros con los Tiles, ya que no arrastramos directamente a la escena los Tiles. no no no! nosotros siempre nos complicamos la vida!. En lugar de eso, estamos utilizando el método o instrucción "attachMovie" (ActionScript 1.0/2.0), para poner los movieClips en la pantalla de forma dinámica.
El comando attachMovie tiene la siguinete sintaxis:

anyMovieClip.attachMovie(idName, newname, depth);

Como verá uno de los parametros que incorpora, es el llamado "depth" (profundidad). ¿Que significado exacto tiene esa "depth" (profundidad) en la instrucción?. Todo aquello que usted dibuje directamente en la escena, se ubica en _level0 . Es lo mas lejos que irá. Todo aquello que añada dinámicamente (utilizando attachMovie, duplicateMovieClip o loadMovie), se situará en el nivel mas alto, por encima de _level0.
A partir de ahora, solo nos deberemos batir con movieClips añadidos (attach) a la escena. El resto de niveles los olvidaremos.


Buscando la profundidad correcta.

En la imagen bajo estas líneas, en la imagen A, el heroe cubre parte de la pared, así que se produce la sensación de que el heroe está mas cerca del espectador que la pared. En la figura B , la pared tapa a parte del heroe, de modo que el espectador tiene la sensación que la pared está mas cerca que el heroe.

Así que, ¿Cual es la diferencia entre estas dos imagenes en las que heroe y pared se tapan? El heroe y la pared son los mismos de siempre, La pared está siempre en el mismo sitio. Eso si, el heroe se ha movido hacia arriba. Así que llegamos a la conclusión mas importante en esto: los objetos se mueven mas cerca cuando la coordenada y se incrementa. Vale la pena recordar, que hemos de considerar una "depth" (profundidad) mayor para estar mas cerca del espectador.

Pero, ¿Como podemos cambiar la profundidad del heroe dinámicamente? Para esto, flash dispone de un comando que nos viene de perlas: "swapDepths". Podemos modificar la profundidad de cualquier movieClip, mientras indiquemos (y sepamos) cual debe de ser la correcta. De la imagen de arriba, podemos extraer la conclusión de que para la mayoría de objetos "basicos", esta profundidad se corresponde con su coordenada "y".

mc.swapDepths(mc._y)

Puesto que tenemos filas de Tiles, todas ellas compartiendo la misma coordenada "y", hemos de tener también en cuenta la coordenada "x", para que dos movieClips diferentes no compartan la misma profundidad en Flash (como en los inmortales solo quedaría uno!). Si realizamos un "swapDepth" de un movieClip, a la profundidad donde resida otro movieClip diferente con esa misma profundidad, estos intercambiarán sus profundidades (depth), que al fin y al cabo es lo que hace la funcion swapDepth. Y por supuesto nosotros no queremos que esto suceda.

mc.swapDepths(mc._y*movie_width+mc._x)

El Tile en la esquina superior-izquierda será el mas alejado. La profundidad de los Tiles aumenta (estarán mas cerca), conforme avanzamos a la derecha y hacia abajo.


z-sorting

z-sorting (que traducido sería algo así como orden-z), es el nombre técnico, mas elaborado con el que se conoce todo esto que hemos estado haciendo con las profundidades (posiblemente a los que conocen el css le suene como el orden de visualización de las capas "layers", z-order).
Es un nombre que procede del mundo 3D, donde cada punto se define por coordenadas (x, y , z). La coordenada z determina como de cerca o lejos esta ese punto con respecto al espectador. Vamos a hacer que todos nuestro Tiles tengan la profundidad correcta y cuando el heroe se mueva alrededor de ellos, cambiaremos su profundidad de acuerdo a la posición donde esté.

Aseguresé que tanto los Tiles como el heroe tengan el punto de registro en sus respectivos MovieClips en la esquina superior-izquierda. Dibuje aquellas partes que quiera que se solapen entre si por encima del punto de registro del movieClip adecuado. Fijesé en la imagen bajo estas líneas para entender a lo que me refiero.

Y ahora, declaremos el objeto "char".

char={xtile:2, ytile:1, speed:4, width:20, height:20};

El ancho y alto deben ser los predeterminados, y no los leidos con _height (que serán algo mayores) ya que queremos que el heroe camine parcialmente sobre las paredes.
Ahora veamos como será la función buildMap:

function buildMap (map) {
  _root.attachMovie("empty", "tiles", 1);
  _root.tiles.attachMovie("empty", "back", 0);

Vamos a añadir movieClips extra al clip "tiles". Es ahí donde situaremos los Tiles de terreno que no pueden solaparse con el heroe. Los Tiles como paredes y árboles, que también pueden estar en frente del heroe, se situarán en el movieClip "tiles" directamente. Como el movieClip "back", está en el level0 dentro del movieClip "tiles", siempre estará por detras de cualquier otro objeto que ubiquemos directamente en el movieClip "tiles", incluyendo al heroe, árboles y cualquier otra cosa que se nos ocurra. Y cualquier objeto que insertemos dentro de "back" por tanto también estará por detrás de los objetos insertados directamente en "tiles" (ya que "back", fue el primer mc al que hicimos "attach" en "tiles").
Para el bucle que crea los Tiles, utilice este código:

var name = "t_"+i+"_"+j;
game[name]= new game["Tile"+map[i][j]];
if(game[name].walkable){
  var clip=game.clip.back;
}else{
  var clip=game.clip;
}
game[name].depth= i*game.tileH*300+j*game.tileW+1;
clip.attachMovie("tile", name, game[name].depth);
clip[name]._x = (j*game.tileW);
clip[name]._y = (i*game.tileH);
clip[name].gotoAndStop(game[name].frame);

Tras crear el objeto para el Tile correspondiente, comprobamos si se trata de un tile pisable (walkable=true), y si es así, lo ubicamos en el clip "back". Seguidamente, calculamos la profundidad del Tile. Añadimos 1 a la profundidad para evitar que el Tile en x=0 e y=0 se añada al nivel 0 donde tenemos el movieClip "back". Si lo permitieramos, entonces "tile0_0" sustituiría al movieClip "back".

Ahora calculamos la profundidad del heroe:

ob.depth=ob.y*300+ob.x+1;
game.clip.attachMovie("char", "char", ob.depth);

Y como el heroe puede cambiar su profundidad a cada paso, añada este código al final de la función moveChar:

ob.depth=ob.y*300+ob.x+1;
ob.clip.swapDepths(ob.depth);
return (true);

Así cada vez que se ejecuta la función moveChar, la profundidad del objeto de actualiza. Asimismo si queremos modificar la profundidad de otros objetos (como un enemigo), también podrán actualizar sus profundidades al valor correcto. Sin embargo, si planea añadir mas objetos móviles, aseguresé que entre ellos no pueden tener exactamente las mismas coordenadas x/y o este método fallará.

Y esto es todo sobre profundidad. Puede ver el código completo descargando el fichero fla bajo la película de ejemplo al comienzo de esta página.

El siguiente tema trata un tipo de vista diferente a las trabajdas hasta ahora y muy popular, la vista isométrica.

« Anterior
Indice
Siguiente »