18 mayo 2005

Leyendo los botones

Cuando hicimos el port del juego Snake, ya tuvimos que implementar la lectura de los botones para poder manejar la serpiente y reiniciar la partida. Ahora vamos a entrar un poco más en profundidad en este tema.

La Gameboy Advance posee 10 botones, como ya se ha comentado. El manejo de estas entradas se hace mediante dos registros de Entrada/Salida, que son los siguientes:

REG_KEYS (0x0400:0130)

Cada bit del 0 al 9 hace referencia a cada uno de los botones:

REG_KEYS[0] -> A
REG_KEYS[1] -> B
REG_KEYS[2] -> Select
REG_KEYS[3] -> Start
REG_KEYS[4] -> Derecha
REG_KEYS[5] -> Izquierda
REG_KEYS[6] -> Arriba
REG_KEYS[7] -> Abajo
REG_KEYS[8] -> R
REG_KEYS[9] -> L

El valor de cada bit es 1 si el botón no está pulsado y 0 si lo está, de forma que REG_KEYS = 0x03FF en estado de "reposo".

REG_KEYCNT (0x0400:0132)

Este registro se usa para controlar las "interrupciones del teclado". Tiene la misma configuración que REG_KEYS pero añadiendo dos bits:

REG_KEYCNT[0] -> A
REG_KEYCNT[1] -> B
REG_KEYCNT[2] -> Select
REG_KEYCNT[3] -> Start
REG_KEYCNT[4] -> Derecha
REG_KEYCNT[5] -> Izquierda
REG_KEYCNT[6] -> Arriba
REG_KEYCNT[7] -> Abajo
REG_KEYCNT[8] -> R
REG_KEYCNT[9] -> L
REG_KEYCNT[E] -> I
REG_KEYCNT[F] -> Op

I activa o desactiva las interrupciones del teclado. Op determina la forma de calcular si lanzar la interrupción o no. Si vale 0, se aplicará una operación OR a los botones indicados, mientras que si vale 1, aplicará una operación AND.

Ejemplo: si cargamos en este registro el valor binario 1100000000001111 (0xC00F), conseguiremos que se genere una interrupción cuando los botones A, B, Select y Start se presionen simultáneamente.

Bien, ya tenemos todo para leer las pulsaciones de los botones, pero nos falta algo muy importante. Hasta ahora sabemos cuándo un botón está pulsado o no. Realmente esta no es la información que necesitamos, sino que lo lógico es saber si un botón ha cambiado de estado. ¿Por qué? Imaginemos el botón Start con su función típica de activar la pausa del juego. Leemos el estado de los botones y detectamos que Start fue pulsado. Entramos en el estado "pausa", del que saldremos cuando detectemos nuevamente que Start está pulsado. El problema es que el microprocesador de la Gameboy Advance ejecuta código mucho más rápido de lo que imaginamos. Por tanto, una pequeña pulsación de Start por nuestra parte puede implicar muchas pausas/continuaciones. De hecho, podemos considerar que el estado en el que quedará el juego tras soltar el botón es totalmente aleatorio.

Resumiendo, lo que nos interesan son los cambios de estado de los botones. Y podemos conseguir esa información mediante estas funciones:
void LeerBotones()
{ bot_ant= bot_act; bot_act= REG_KEYS; }

u16 BotonCambio(u16 boton)
{ return (bot_act^bot_ant) & boton; }

u16 BotonMantiene(u16 boton)
{ return ~(bot_act|bot_ant) & boton; }

u16 BotonPulsado(u16 boton)
{ return (~bot_act&bot_ant) & boton; }

u16 BotonSoltado(u16 key)
{ return (bot_act&~bot_ant) & boton; }

Lo que haremos será llamar a LeerBotones() cada ciclo de nuestro programa, y de esa forma podremos saber si un botón en concreto ha cambiado de estado.

Por ejemplo, BotonPulsado(KEY_START) devolverá 1 si se pulsó el botón Start, y 0 en caso contrario. Este valor lo devolverá una única vez. Hasta que no soltemos y volvamos a pulsar el botón, la función no volverá a devolver 1.

Con estos conocimientos podemos hacer prácticamente todo en cuanto a lectura de botones. Hemos aprovechado para añadir a nuestra serpiente el clásico botón de pausa (Start).

Código fuente.
ROM.

1 Comentarios:

Anonymous Anónimo dijo...

yo tengo un robot sr1 (super rrobotica . com)y tiene una funcion de ultrasonidos.es un rrobot autonomo y semicontrolado desde un programa windows el programa tiene alante atras,bueno esas cosas y un lector de ultrasonido tipo radar y me gustaria saber como hacerlo y controlarlo con la game boy

4:05 p. m.  

Publicar un comentario

<< Home