TUTORIAL DE PROGRAMACIÓN PARA GAME BOY - PARTE #9: Crear Efectos Visuales usando Scan LinesTras un tiempo de inactividad vuelvo a la carga con una pequeña entrada relacionada con la programación para Game Boy. Echadle un ojo al siguiente video.
https://www.youtube.com/watch?v=Cb80ilm2xcY&index=7Cómo creo que ya he comentado por aquí la game boy dibuja en la pantalla linea a linea. En el mundillo estas lineas son conocidas como "scan lines" y en el caso de la gameboy contamos con 160 de ellas (por temas de la resolución de la consola). Pues bien, si interrumpimos a la consola después de pintar cada línea podemos obtener algunos efectos visuales realmente curiosos. En esta pequeña entrada lo que muestro es cómo conseguir una efecto "de ondas" en una imagen que mostramos por pantalla. Para conseguir interrumpir a la consola después de pintar cada línea en pantalla podríamos usar un código como el siguiente:
STAT_REG = 0x08;
disable_interrupts();
add_LCD(LCD_Interrupt);
enable_interrupts();
set_interrupts(LCD_IFLAG);
En la primera línea lo que hacemos es incializar el registro de estado con el valor 0x08 para indicarle a la consola que debe interrumpirse tras pintar cada línea. Posteriormente se deshabilitan todas las interrupciones. Esto es necesario cuando queremos añadir una interrupción nueva para posteriormente volver a habilitarlas. En este caso indicamos que debe invocar a la función
LCD_Interrupt() de la cual hablaremos un poco más adelante. Finalmente fijamos el flag LCD para indicar a la Game Boy que queremos interrumpir el LCD de la consola.
Para conseguir el efecto propuesto en esta entrada vamos a desplazar el eje Y de cada "scan line". Para ello creamos un array que indica a cada línea que posición debe tener.
unsigned char effect[] =
{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08,
0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08,
0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06,
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};
Finalmente definimos la función
LCD_Interrupt():
UBYTE counter;
void LCD_Interrupt(void)
{
SCY_REG = effect[counter];
counter++;
if(counter >= 109)
{
counter = 0;
}
}
El efecto de desplazar la posición Y en el LCD lo conseguimos pasando ell valor actual en el arrray
"effect" en el registro correspondiente
SCY_REG = effect[counter]. Después de esto incrementamos el contador en uno para obtener el siguiente valor del array en la siguiente línea y comprobamos que no nos pasamos del tamaño del array, y en caso de que así sea reseteamos el contador a cero. Y ya está nuestro efecto de ondas conseguido. A continuación pongo el código completo del programa:
#include <gb/gb.h>
#include "batman_3.h"
unsigned char effect[] =
{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08,
0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08,
0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06,
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};
UBYTE counter;
void LCD_Interrupt(void)
{
SCY_REG = effect[counter];
counter++;
if(counter >= 109)
{
counter = 0;
}
}
void main(void)
{
HIDE_SPRITES;
HIDE_BKG;
counter = 0;
STAT_REG = 8;
disable_interrupts();
add_LCD(LCD_Interrupt);
enable_interrupts();
//imagen de fondo
set_bkg_data(0, 0, batman_3_tile_data);
set_bkg_tiles(0, 0, 20, 18, batman_3_map_data);
set_interrupts(LCD_IFLAG);
SHOW_BKG;
SHOW_SPRITES;
while(1)
{
wait_vbl_done();
}
}
Espero volver dentro de poco con una nueva entrada. Hasta entonces:
Saludos.