06-Tiles y Planos

Aventuras en Megadrive: Tiles y Planos

 

DATOS TÉCNICOS

  • La MD maneja por hardware 2 planos de fondo, planos A y B, y además un plano de sprites.
  • Los planos A y B pueden tener scroll. Existe un plano opcional llamado window, que no es más que una parte del plano A estática (sin scroll). Suele usarse para el marcador.
  • Cada plano lo componen tiles de 8×8 píxels. Tile = Patrón = carácter.
  • La pantalla (un plano) son 40×28 tiles (horizontal x vertical). 1120 tiles visibles.
  • Si incluimos los tiles fuera de pantalla, no visibles (necesarios para hacer scroll), el  plano por defecto tiene 64×32 tiles. Un plano puede tener otras dimensiones (32×32, 64×64 o 32×128), máximo 4096 tiles.
  • Cada plano se pinta de izquierda a derecha y de arriba a abajo.
  • Cada tile puede ser usado tantas veces como queramos en cualquier plano.
  • Cada tile puede ser pintado con cualquiera de las 4 paletas de colores.
  • Cada tile puede ser pintado volteado/invertido sin necesidad de usar memoria adicional. Tanto horizontal como verticalmente.
  • Una cantidad importante de tiles pueden ser cargados en memoria usando DMA.
  • Los tiles se cargan en la memoria del VDP, llamada VRAM (Visual RAM).
  • La MD tiene 64KB de VRAM.

 

Otros datos que debes saber

  • 1 tile = 32 bytes.
  • El SGDK utiliza el primer tile de VRAM para rellenar el fondo.
  • El SGDK reserva espacio para 1310 tiles (+96 para la fuente).
  • Los tiles se mantienen en cada refresco de pantalla.
  • Cada pixel de un tile es un valor de 4 bits, que representa un índice color (en hexadecimal, de 0x0 a 0xF).

 

Podemos crear un tile de forma manual, para cada píxel, le damos un valor hexadecimal que representará el índice de color de la paleta elegida. Es decir, ponemos un valor de 0 a 15, esto son 16 posibles valores. Recordemos que una paleta de color puede tener 16 colores distintos.

#define MI_TILE 1
const u32 tile[8]=
{
		0x00111100,
		0x01144110,
		0x11244211,
		0x11244211,
		0x11222211,
		0x11222211,
		0x01122110,
		0x00111100
};

He creado una constante MI_TILE para referenciar el tile. Esto no es necesario pero es didáctico.

¿Qué color es 0, 1, 2 o 4? Dependerá de qué color hemos elegido en la paleta aplicada a este tile. Es más, podemos cambiar esta paleta cuando queramos y cambiarían los colores del tile. Pero no nos adelantemos, vamos por partes. ¿Cómo mostrar este tile por pantalla?

// ...
	
	//carga el tile en la posición 1 de la VRAM
	VDP_loadTileData( (const u32 *)tile, MI_TILE , 1, 0); 
	
	//dibuja la tile 1 en el plano A en pos (5,5) con la paleta 0
	VDP_setTileMapXY(PLAN_A, MI_TILE, 5, 5);
	
	while(1)
	{
		VDP_waitVSync();
	}

VDP_loadTileData:   Carga el tile en memoria en la posición 1. No lo cargamos en la posición 0 (en C se comienza siempre en el cero), porque llenaríamos el background con el tile. El último parámetro indica que no vamos a usar DMA (es el último 0).

VDP_setTileMapXY: Dibuja el tile en el plano A en la posición (5,5). Recordemos que hablamos en tiles, no en píxels. En píxels sería la posición (40,40). Además por defecto le asigna la paleta 0, que por defecto en el SGDK esta es una paleta de grises.

Si queremos cambiar de plano, paleta o voltear el tile hemos de decírselo con TILE_ATTR_FULL():

        // TILE_ATTR_FULL()	
	//primer parámetro: paleta.  PAL2 = paleta de verdes
	//segund parámetro: prioridad.  0 = baja prioridad
	//tercer parámetro: volteo vertical.   1 = vflip
	//cuarto parámetro: voltero horizon.   0 = no hflip
	//quinto parámetro: tile referenciado.
	VDP_setTileMapXY(PLAN_B, TILE_ATTR_FULL(PAL2, 0, 1, 0, MI_TILE), 6, 5);

PRIORIDAD

 

Ahora hablemos de la prioridad.

GenesisPlanes

MD nos da la posibilidad de marcar un tile con alta o baja prioridad. Tanto para planos como para sprites.

La explicación sencilla es que un tile con alta prioridad siempre aparecerá por encima de uno con baja prioridad, incluso aunque estén en planos distintos. De esta forma aunque el plano B está por debajo del plano A, podemos obligar a ciertos tiles del plano B a estar “por encima”. Lo mismo podemos aplicarlo para sprites, al fin y al cabo los sprites están formado por tiles. Pero esto lo veremos luego.

Un ejemplo bastante completo, vamos a poner varias tiles en pantalla, unas en plano A y otras en plano B, luego jugaremos con la prioridad y las que están en el plano B con alta prioridad saldrán por delante de las que están en plano A con baja prioridad.

Además invertiremos las tiles tanto horizontal como verticalmente.

 

#include <genesis.h>

#define MI_TILE 1

const u32 tile[8]=
{
0x44444421,
0x44442211,
0x44422110,
0x44221100,
0x42211000,
0x42110000,
0x21100000,
0x11000000
};

int main( )
{

//carga el tile en VRAM
VDP_loadTileData( (const u32 *)tile, MI_TILE, 1, 0);

//dibuja la tile en el plano A en pos (1,5) con la paleta por defecto (pal 0)
VDP_setTileMapXY(PLAN_A, MI_TILE, 1, 5);

//Dibuja el tile usando TILE_ATTR_FULL()
//primer parámetro: paleta. PAL2 = paleta de verdes
//segund parámetro: prioridad. 0 = baja prioridad
//tercer parámetro: volteo vertical. 1 = vflip
//cuarto parámetro: volteo horizon. 0 = no hflip
//quinto parámetro: tile referenciado.
VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL2, 0, 0, 0, MI_TILE), 3, 5);

//Dibuja 2 veces el tile, la primera vez en el plano B con pal 0 (grises)
//la segunda en el plano A con pal1 (rojos),
VDP_setTileMapXY(PLAN_B, TILE_ATTR_FULL(PAL0, 0, 0, 0, MI_TILE), 5, 5);
VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, MI_TILE), 5, 5);

//Dibuja 2 veces el tile, igual que antes pero el tile del plano B con alta prioridad
VDP_setTileMapXY(PLAN_B, TILE_ATTR_FULL(PAL0, 1, 0, 0, MI_TILE), 7, 5);
VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL1, 0, 0, 0, MI_TILE), 7, 5);

//dibuja la tile volteada horizontalmente, verticalmente y luego ambas a la vez
VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL0, 1, 0, 1, MI_TILE), 3, 8);
VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL0, 1, 1, 0, MI_TILE), 5, 8);
VDP_setTileMapXY(PLAN_A, TILE_ATTR_FULL(PAL0, 1, 1, 1, MI_TILE), 7, 8);

while(1)
{
VDP_waitVSync();
}

return 0;
}

DEBUGGEANDO

 

Hay un tile pero lo hemos dibujado varias veces, en varias posiciones, con distintas paletas, prioridades… ¿en qué afecta esto a la memoria?

En el emulador GensKmod>CPU>Debug>Genesis>VDP

Captura

A la izq los distintos ejemplos. A la derecha las 4 paletas cargadas en memoria y la VRAM del VDP. GensKmod nos permite ver en tiempo real todos estos datos, por lo cual es muy útil para ver qué está pasando y si nuestro programa hace lo que queremos.

El tile del ejemplo sólo está una vez en memoria, aunque en pantalla hemos pintado varios. Nuestro tile está en la posición 1, como se esperaba. En la posición 0 hay un tile en negro, que es creado automáticamente por el SGDK para rellenar el fondo. Es negro porque es el primer color de la primera paleta, por tanto no hemos de dar por hecho que el fondo va a ser negro, la paleta podría comenzar con un color azul, siendo entonces el fondo azul.

Podemos pulsar en las distintas paletas y el tile seleccionado se coloreará según la paleta elegida (sólo en el debugger, no en el propio juego).

Debajo de las 4 paletas “reales” GensKmod tiene otra paleta “virtual” con una selección de colores propia, de momento la ignoraremos.

 

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s