Lección 05 – Sprites (II) Animados

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.

Captura9

Cada fila define una animación completa. Podemos tener hasta 16 filas por sprite.

sonic

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:

captura30

Vamos a ver las distintas columnas

captura31

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:

GenesisPlanes

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:

https://github.com/danibusvlc/aventuras-en-megadrive