Aventuras en Megadrive: Sprites (II)
Recordar que todo esto están basados en los ejemplos del SGDK,
carpeta sample > sprite
Vamos a partir del ejemplo correspondiente de mi github.
ANIMANDO
Si examinas la carpeta RES, el archivo de imagen del sprite de Sonic (sonic.png), contiene unas cuantas animaciones, una por fila. Si además examinamos el archivo sprites.res:
SPRITE sonic_sprite "sprites/sonic.png" 6 6 FAST 1
Indico al SGDK que el sprite tiene 6×6 tiles (corresponden al cuadro en rojo de la captura). Son 6 tiles en horizontal y 6 tiles en vertical contando desde la esquina sup izq. El ‘1’ es la velocidad de animación.
‘FAST’ es el tipo de compresión, lo veremos más adelante.
Cada fila define una animación completa. Podemos tener hasta 16 filas por sprite.
Para referirnos a una fila en concreto definiremos estas macros al principio del código:
#define ANIM_STAND 0 #define ANIM_WAIT 1 #define ANIM_WALK 2 #define ANIM_RUN 3 #define ANIM_BRAKE 4 #define ANIM_UP 5 #define ANIM_CROUNCH 6 #define ANIM_ROLL 7
Toma nota que no hace falta declarar las que no usemos
Después, dentro del código, utilizaremos esta función para cambiar el sprite a la animación que nos interese:
SPR_setAnim(sprite, animacion);
Veamos un poco del código, en concreto la parte de mover el sprite:
[..] static void handleInput() { //variable donde se guarda la entrada del mando u16 value = JOY_readJoypad(JOY_1); //si pulsamos izquierda... if (value & BUTTON_LEFT) { SPR_setPosition(mi_sonic, posx--, posy); SPR_setHFlip(mi_sonic, TRUE); SPR_setAnim(mi_sonic, ANIM_RUN); } //si pulsamos derecha... if (value & BUTTON_RIGHT) { SPR_setPosition(mi_sonic, posx++, posy); SPR_setHFlip(mi_sonic, FALSE); SPR_setAnim(mi_sonic, ANIM_RUN); } [..........] //si no pulsamos if ((!(value & BUTTON_RIGHT)) && (!(value & BUTTON_LEFT))) { SPR_setAnim(mi_sonic, ANIM_STAND); } } [..]
Aquí encontramos la parte en la que movemos el sprite, si nos movemos hacia la izquierda, invertimos el sprite para que mire hacia el lado izquierdo, si nos movemos a la derecha, lo ponemos tal cual está en el archivo de imagen. Para ello uso la función
SPR_setHFlip(sprite, TRUE | FALSE );
Si no se detecta que pulsamos DERECHA o IZQUIERDA, cambio la animación del sprite también.
Además he añadido esta función para alterar la prioridad del sprite.
SPR_setPriorityAttribut(sprite, TRUE | FALSE );
Hay que tener en cuenta que hay un fondo (las plantas y palmeras) con sus tiles marcadas con PRIORIDAD, así que Sonic saldrá por detrás cuando no tenga y por delante cuando sí tenga prioridad (por defecto la tiene).
Cambiaremos de prioridad pulsando A y B.
[..] //si pulsamos A... if (value & BUTTON_A) { SPR_setPriorityAttribut(mi_sonic, FALSE); } //si pulsamos B... if (value & BUTTON_B) { SPR_setPriorityAttribut(mi_sonic, TRUE); } [..]
DEBUGEANDO
La MD maneja por HW sprites de hasta 4×4 tiles (32×32 píxels). El sprite de Sonic son 6×6 tiles, excedemos este límite. Esto es posible gracias al SGDK que nos automatiza utilizar meta-sprites: Varios sprites hardware, comportándose como si fuese uno.
Pero… ¿cuántos sprites HW usa internamente la MD al usar un meta-sprite?
Vamos a verlo. Crea el bin. Con GensKmod: CPU > Debug > Genesis > VPD – Sprites
Nos aparece la tabla de Sprites. Se actualiza en tiempo real, es muy útil. Si pulsamos en las distintas filas veremos el sprite abajo, si hacemos scroll a la derecha aparecen campos extra:
Vamos a ver las distintas columnas
Columna NUM
- Indica los sprites HW presetes en VRAM. Hay 80 en total (del 0 al 79).
- El sprite 0 está reservado por el sistema como sprite transparente.
En este caso tenemos 5 tiles en VRAM. Del tile NUM 00 al tile NUM 04.
El sprite de Sonic es más grande que el máximo sprite HW (4×4 vs 6×6 tiles), el SGDK utilizara varios sprites HW para crear nuestro sprite de Sonic. Los tiles 01, 02, 03 y 04 son precisamente dichos sprites. El SGDK ha utilizado 4 entradas (obviamos la entrada 0) de la tabla para crear nuestro meta-sprite.
Es buena costumbre ir comprobando esta tabla a medida que vayamos añadiendo sprites en nuestro juego. Si la llenamos, los sprites que no «entren» en la tabla simplemente no aparecerán en pantalla. Aparecerá el famoso parpadeo o flickering.
Columnas Ypos, Xpos
Posición en pantalla (x, y) según los valores del mapa de sprites de la MD.
Por tanto el punto (0,0) del SGDK saldrá en GensKmod como (128,128).
COLUMNA Size
Tamaño del Sprite (en tiles).
COLUMNA Link
El link le indica al VDP en qué orden debe pintar los sprites en pantalla.
Dentro de un mismo plano, y a igual prioridad,
los primeros sprites saldrán siempre por encima de los últimos.El último sprite de la lista debe apuntar necesariamente al sprite 00.
En la MD cada sprite lleva asociado qué sprite se pinta después. En este caso, el sprite 00 apunta al sprite 01. El sprite 01 apunta al 02. El sprite 02 apunta al 03. El sprite 03 apunta al 04. Finalmente el sprite 04 apunta al sprite 00.
Cuando creamos un sprite, el SGDK le asigna automáticamente el último link y enlaza el sprite anterior con el recien creado, y el recien creado con el sprite 00.
Variando el link, podremos cambiar qué se pinta primero y por tanto qué queda por debajo y qué por encima. El SGDK nos da herramientas para hacerlo.
A parte, la prioridad. Recordemos:
Si sprite 01 y sprite 02 están en la misma posición, y el sprite 02 tiene prioridad, el sprite 02 tapa al 01. El sprite 02 estaría en el plano «Sprite High», el sprite 01 en «Sprite Low».
Podemos variar manualmente el link «al vuelo» para conseguir efectos interesantes, utilizando SPR_setDepth()
SPR_setDepth(sprite, link): Pone el sprite indicado a la profundidad indicada.
Podemos utilizar la macro SPR_MIN_DEPTH para asegurarnos que aparece por encima de todo, al asignarle el mínimo link posible.
También podemos utilizar -fix32ToInt(posY) en el segundo campo para dar más prioridad a los elementos que estén en la zona «baja» de la pantalla.
COLUMNA Pal
Paleta utilizada (del 0 al 3).
COLUMNA Tile
Es complicado. Lo dejo para más adelante.
COLUMNA Flags
3 cifras que indican PRIORIDAD / VFLIP / HFLIP:
- Prioridad: Puede ser 0 o P (indica prioridad).
- VFLIP: Puede ser 0 o V (indica espejado vertical).
- HFLIP: Puede ser 0 o P (indica espejado horizontal).
GITHUB
El código de esta lección, y de todas las demás, lo podrás encontrar en mi github: