11-Sprites (II)

Aventuras en Megadrive: Sprites (II)

Vamos a ver un ejemplo bastante completo. Se trata de la pantalla de inicio de Sonic.

En primer lugar descarga este documento:    leccion 06-sprites.zip

Cambia la extensión (borra .doc) y descomprime todo en una carpeta.

Entra en la carpeta RES y examina los archivos .res de los fondos y del sprite de Sonic.

Como verás tenemos 2 planos: fondo1 es el fondo lejano, fondo2 son las palmeras, flores y el suelo. Ambos fondos se referencian en el mismo archivo res. Ambos están en una subcarpeta llamada fondos.

IMAGE fondo1 "fondos/fondo1.png" BEST
IMAGE fondo2 "fondos/fondo2.png" BEST

Captura8

 

En cuanto a Sonic, el archivo de imagen contiene unas cuantas animaciones, no obstante en este ejemplo crearemos un Sonic sin animaciones, para simplificar.

SPRITE sonic_sprite "sprites/sonic.png" 6 6 FAST 1

Como verás indicamos 6×6 tiles, que corresponden al cuadro en rojo, 6 tiles en horizontal y 6 en vertical contando desde la esquina sup izq.  El  ‘1’ es la velocidad de animación, como sólo habrá 1 frame esto es indiferente. Veamos el archivo con una cuadrícula de tiles de 8×8 píxels:

Captura9

Vamos con el main.c, comento en el propio archivo y luego después:

#include <genesis.h>

#include "fondos.h" //carga las 2 imágenes de background
#include "sprites.h" //carga el sprite de Sonic

//Declaramos la función para recoger la entrada del mando
static void handleInput();

//Declaramos una variable (un puntero) para referirnos al sprite
Sprite* mi_sonic;

//Variables que recogen la posición del sprite
u32 posx = 64;
u32 posy = 155;

int main()
{
 //variable para llevar el control de tiles
 u16 ind;

 //pone la pantalla a 320x224
 VDP_setScreenWidth320();

 //inicializa motor de sprites
 SPR_init(0, 0, 0);

 //recoge las paletas de los fondos y los asigna a la primera y segunda paleta del sistema
 VDP_setPalette(PAL0,fondo1.palette->data);
 VDP_setPalette(PAL1,fondo2.palette->data);

 //carga los fondos en el VDP
 ind = TILE_USERINDEX;
 VDP_drawImageEx(PLAN_B, &fondo1, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE);
 ind += fondo1.tileset->numTile;
 VDP_drawImageEx(PLAN_A, &fondo2, TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE);
 ind += fondo2.tileset->numTile;

 //recoje la paleta de sonic y la mete en la 3a paleta del sistema
 VDP_setPalette(PAL2,sonic_sprite.palette->data);

 //añade el sprite de Sonic
 mi_sonic = SPR_addSprite(&sonic_sprite, posx, posy, TILE_ATTR(PAL2, TRUE, FALSE, FALSE));

    //Bucle principal
    while(TRUE)
    {
      //recoje la entrada de los mandos
      handleInput();

      //actualiza el VDP
      SPR_update();

      //sincroniza la Megadrive con la TV
      VDP_waitVSync();
     }

return 0;
}

//Funcion handleInput() recoge la entrada del mando (sólo izq,dcha)
//actualiza la posición de Sonic, sumando o restando a la variable posx
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);
  //si pulsamos derecha...
  if (value & BUTTON_RIGHT)
    SPR_setPosition(mi_sonic, posx++, posy);
}

 

Para empezar no hemos respetado lo que dijimos en la entrada de INPUT. Mal hecho, porque tal y como está hecho el código, vamos a entrar en la función handleInput() siempre, se pulsen o no los mandos. De forma que perdemos tiempo de proceso para nada.

No obstante lo he puesto para que veáis que hay otras formas de hacer las cosas, en este caso más rudimentaria pero válida, al ser un ejemplo muy simple.

Como ejercicio, sería interesante que probarais a cambiar la prioridad, de forma que el plano de las palmeras quede por delante de Sonic. Como pista diré que hay que hacer dos cambios en el código.

DEBUGEANDO

En la entrada anterior dijimos que internamente la MD está manejando más de un sprite, ya que el máximo por HW para un sprite son 4×4 tiles y en la spritesheet tenemos sprites de 6×6 tiles. ¿Cuántos usa realmente la MD?

Vamos a verlo con GensKmod:  CPU > Debug > Genesis > VPD – Sprites

Nos aparece la tabla de Sprites en VRAM. Decir que la tabla de sprites se actualiza en tiempo real, es muy útil.

 

Captura11

Como no creo que se vea bien, pongo una sola captura:

Captura12

COLUMNA NUM

  • Tiles en VRAM. Hay 80 en total (del 0 al 79).
  • El tile 0 está reservado por el sistema como tile transparente.

En este caso Tenemos 5 tiles en VRAM. Del tile NUM 00 al tile NUM 04.

El tile 01 es el que tengo seleccionado en la captura, se ve parte del sprite de Sonic, 4×4 tiles = 32×32 píxels (columna Size), es decir, el tamaño máximo por HW. Como el sprite de Sonic es más grande (recordemos, 6×6 tiles), el SGDK utiliza más tiles.

Los tiles 02, 03 y 04 son precisamente dichos tiles.

Por tanto cuando diseñemos personajes o añadamos sprites como decorado, habremos de chequear esta tabla para ver si la llenamos, porque de hacerlo los sprites que no estén incluidos simplemente no aparecerán en pantalla.

 

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.

Los primeros sprites saldrán siempre encima de los últimos.

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.

El último sprite de la lista debe apuntar necesariamente al sprite 00.

Así, el sprite 04 apunta al sprite 00.

Variando el link, podremos cambiar qué se pinta primero y por tanto qué queda por debajo y qué por encima.

Para que nos entendamos si el sprite 00 y el sprite 01 están ambos en la misma posición, el sprite 00 sale por encima si el link del sprite 00 apunta al 01 y así sucesivamente.

A parte, la prioridad. Recordemos el gráfico que puse en el post 06:

GenesisPlanes

Si el sprite 00 y el sprite 01 están ambos en la misma posición, y el sprite 01 tiene prioridad, el sprite 01 sale por encima. Links aparte. El sprite 01 estaría en el plano “Sprite High” del gráfico anterior, y el sprite 00 estaría en el plano “Sprite Low”.

 

Podemos variar manualmente el link “al vuelo” para conseguir efectos interesantes, utilizando SPR_setDepth()/SPR_setZ()

SPR_setDepth(sprite, link)/SPR_setZ(sprite, link): Ambas hacen lo mismo, le ponen al sprite indicado la profundidad indicada. Podemos utilizar la macro SPR_MIN_DEPTH para asegurarnos que aparece por encima de todo.

Recordar que un link más bajo se ve por encima de un link más alto.

 

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).

 

 

Anuncios