TUTORIAL 2: CONTROL DEL PADEn este tutorial nos vamos a centrar en algo fundamental para un juego como sería la lectura de la pulsación de los botones. Como podréis comprobar, se hace de forma muy sencilla
Como en el anterior tutorial, creamos la carpeta
"02_pad" en
"C:\gbdk\examples" y dentro de esta los ficheros
"main.c" y
"compile.bat".
Empezamos con el
main.c:
#include <gb/gb.h>
Enlazamos a la librería del kit GBDK, esto de aquí en adelante lo haremos siempre.
#include <gb/drawing.h>
Enlazamos a unas rutinas muy interesantes del kit que nos permiten desde dibujar texto, formas geometricas, imagenes...
void main(){
Creamos la función Main, que es el punto de entrada a nuestro programa, esto tampoco lo volveré a comentar en el futuro.
UBYTE keys = 0;
Cremos una varible unsigned byte (que podrá contener valores de 0 a 255) donde guardaremos las lecturas de los botones.
gotogxy(1, 1);
gprintf("GAMEBOY PAD TEST");
Gracias a las funciones de drawing.h, podemos usar unas funciones de texto más potentes que incluso nos permiten situarnos en posiciones especificas de la pantalla.
gotogxy(1, 1);
gprintf("GAMEBOY PAD TEST");
gotogxy(1, 2);
gprintf("----------------");
gotogxy(1, 4);
gprintf("Start : 0");
gotogxy(1, 5);
gprintf("Select: 0");
gotogxy(1, 6);
gprintf("Up : 0");
gotogxy(1, 7);
gprintf("Down : 0");
gotogxy(1, 8);
gprintf("Left : 0");
gotogxy(1, 9);
gprintf("Right : 0");
gotogxy(1, 10);
gprintf("A : 0");
gotogxy(1, 11);
gprintf("B : 0");
Dibujamos el texto que nos indicará si se ha pulsado un botón en concreto.
while(1){
Otra vez creamos un bucle infinito, recordad que no debemos llegar al final del programa
NUNCA.
wait_vbl_done();
Aquí llegamos a algo interesante, básicamente sincronizamos con el
blanqueo vertical... ¿y eso en cristiano que quiere decir? ¿Os suena lo de los 60 fps en los juegos? Con esto hay que remontarse a los tiempos de las televisiones de tubo. Un haz de electrones iba dibujando la imagen linea a linea, de arriba a abajo, hasta llegar abajo y así otra vez... hasta hacerlo 60 veces por segundo en una televisión NTSC y 50 en una PAL, básicamente porque tenía más lineas que dibujar. Lo que hace esta instrucción, es esperarse hasta que se haya dibujado la imagen completa, bloqueándonos voluntariamente para que nuestro código se ejecute 60 veces por segundo. ¿Recordáis que pasaba en juegos de PC muy antiguos que al pasar de un 286 a 386 por ejemplo se hacían injugables por su aumento de velocidad? Pues esto era porque no sincronizaban su tasa de frames con el refresco de la pantalla. En GAME BOY toma más relevancia aún porque, si habéis leído la documentación como os puse de deberes... sabréis que mientras el controlador del LCD está trabajando, no es posible acceder a la memoria de vídeo de la consola (VRAM), por lo que para acceder a esta para cargar o modificar datos (sprites, tiles, fondos...) hay que esperar a que termine el dibujado en el LCD. Todas esas operaciones ES OBLIGATORIO hacerlas
DESPUÉS de "wait_vbl_done();". Disponemos de un tiempo limitado antes de que vuelva a empezar el dibujado del LCD, si nos excedemos, bajaremos de esos 60 fps, ¡así que ojo con lo que ponemos aquí!
keys = joypad();
Usamos esta función de las GBDK para leer el estado de los botones y guardar el resultado en la variable que creamos al principio. Aunque he colocado estas instrucciones detrás de "wait_vbl_done();", no sería necesario porque no acceden a VRAM, podrían ponerse delante y no pasar nada.
if( keys & (J_START)){
gotogxy(9, 4);
gprintf("1");
}
else{
gotogxy(9, 4);
gprintf("0");
}
Ahora simplemente comprobamos los valores obtenidos con las constantes de los botones definidas en la librería, que son:
J_START
J_SELECT
J_B
J_A
J_DOWN
J_UP
J_LEFT
J_RIGHT if( keys & (J_SELECT)){
gotogxy(9, 5);
gprintf("1");
}
else{
gotogxy(9, 5);
gprintf("0");
}
if( keys & (J_UP)){
gotogxy(9, 6);
gprintf("1");
}
else{
gotogxy(9, 6);
gprintf("0");
}
if( keys & (J_DOWN)){
gotogxy(9, 7);
gprintf("1");
}
else{
gotogxy(9, 7);
gprintf("0");
}
if( keys & (J_LEFT)){
gotogxy(9, 8);
gprintf("1");
}
else{
gotogxy(9, 8);
gprintf("0");
}
if( keys & (J_RIGHT)){
gotogxy(9, 9);
gprintf("1");
}
else{
gotogxy(9, 9);
gprintf("0");
}
if( keys & (J_A)){
gotogxy(9, 10);
gprintf("1");
}
else{
gotogxy(9, 10);
gprintf("0");
}
if( keys & (J_B)){
gotogxy(9, 11);
gprintf("1");
}
else{
gotogxy(9, 11);
gprintf("0");
}
Repetimos para el resto de botones y ya hemos terminado. Para abreviar podríamos crear un #define al principio del código juntando "gotogxy" con "gprintf" y haciendo la llamada de esta forma:
#define gprintf_XY(str,x,y); gotogxy(x, y); gprintf(str);
gprintf_XY(( keys & (J_LEFT)) ? "1" : "0", 9, 8);
El código completo quedaría de la siguiente forma:
#include <gb/gb.h>
#include <gb/drawing.h>
void main(){
UBYTE keys = 0;
gotogxy(1, 1);
gprintf("GAMEBOY PAD TEST");
gotogxy(1, 2);
gprintf("----------------");
gotogxy(1, 4);
gprintf("Start : 0");
gotogxy(1, 5);
gprintf("Select: 0");
gotogxy(1, 6);
gprintf("Up : 0");
gotogxy(1, 7);
gprintf("Down : 0");
gotogxy(1, 8);
gprintf("Left : 0");
gotogxy(1, 9);
gprintf("Right : 0");
gotogxy(1, 10);
gprintf("A : 0");
gotogxy(1, 11);
gprintf("B : 0");
while(1){
// sincroniza con el blanqueo vertical para dibujar los graficos y pone los contadores (timers)
wait_vbl_done();
// lee el pad
keys = joypad();
// si se pulsa start
if( keys & (J_START)){
gotogxy(9, 4);
gprintf("1");
}
else{
gotogxy(9, 4);
gprintf("0");
}
// ETC...
if( keys & (J_SELECT)){
gotogxy(9, 5);
gprintf("1");
}
else{
gotogxy(9, 5);
gprintf("0");
}
if( keys & (J_UP)){
gotogxy(9, 6);
gprintf("1");
}
else{
gotogxy(9, 6);
gprintf("0");
}
if( keys & (J_DOWN)){
gotogxy(9, 7);
gprintf("1");
}
else{
gotogxy(9, 7);
gprintf("0");
}
if( keys & (J_LEFT)){
gotogxy(9, 8);
gprintf("1");
}
else{
gotogxy(9, 8);
gprintf("0");
}
if( keys & (J_RIGHT)){
gotogxy(9, 9);
gprintf("1");
}
else{
gotogxy(9, 9);
gprintf("0");
}
if( keys & (J_A)){
gotogxy(9, 10);
gprintf("1");
}
else{
gotogxy(9, 10);
gprintf("0");
}
if( keys & (J_B)){
gotogxy(9, 11);
gprintf("1");
}
else{
gotogxy(9, 11);
gprintf("0");
}
}
}
Ahora como en el tutorial anterior, abrimos el fichero
compile.bat y escribimos lo mismo.
lcc -o rom.gb main.c
pause
bgb.exe rom.gb
Y ya tenemos la rom lista para grabarla en nuestro flash y comprobar el resultado.
DEBERESEsta lección ha sido muy sencillita así que con que la entendais sobra. Lo que si os pido es que os leais las secciones "1.0 Important Notes" y "1.5 Sprites" del fichero "gbdok.txt" que está dentro de la carpeta DOC ya que son las funciones que usaremos en el próximo tutorial sobre sprites. Tambien seria interesante que fuerais a la carpeta "include\gb" y vierais los prototipos de las funciones contenidos en "drawing.h". Puede que alguna os resulte de utilidad, pero yo no las voy a usar en los tutoriales porque no me parecen interesantes dentro de un juego por su forma de trabajar, utilizando la VRAM completa simulando un FRAMEBUFFER.