[PJRS] Gestión de eventos en SDL
Esta anotación forma parte de la serie Programando Juegos con Ruby y SDL.
La de hoy creo que va a ser una de las partes más feas de explicar, pero es necesario que sepamos como gestionar los diferentes eventos que puede capturar la librería SDL porque van a ser la forma de obtener información del usuario durante el juego.
Con esta parte ya tendremos una plantilla completa para nuestros desarrollos con Ruby
y SDL
.
En la entrega anterior nos quedó pendiente la gestión de eventos. Para ello vamos a emplear dos objetos principalmente: SDL::Event
(pese a que el autor de SDL Ruby
, Ippei Ohbayashi, recomienda usar SDL::Event2
) y SDL::Key
.
Ya podemos empezar a hablar del bucle del juego, aunque en realidad, y por ahora, solo es un bucle y no un juego :P.
Vamos a emplear una variable que nos indicará cuando se ha dado una de las condiciones de terminación que comentamos en la primera entrega (se pulsa ESC
, el jugador pierde, el jugador abandona, etc.).
Dentro de ese bucle realizaremos la captura de eventos, distinguiendo dos fases:
- Procesar eventos pendientes: tenemos que estar al corriente de los eventos de los que nos va informando
SDL
, se se van almacenando en una cola. Estos eventos serán de distintos tipos (SDL::Event::KEYDOWN
,SDL::Event::KEYUP
,SDL::Event::MOUSEMOTION
, etc.), aunque solo debemos procesar obligatoriamente uno de ellos:SDL::Event::QUIT
(por ejemplo, el usuario cierra la ventana del programa). Para el resto será suficiente con que los quitemos de la cola. - Ver el estado de la teclas: cuando trabajamos con el teclado no nos interesa realmente ver cuando se pulsó o se soltó una tecla, sino si una tecla está pulsada. Esto es algo que los eventos de
SDL
no nos dirán, pero que gracias aSDL::Key
podremos saber (el estado de cada tecla, sin preocuparmos de los eventos que propician los cambios de estado). Hay casos especiales que no se contemplarán aqui. Por ejemplo: si se pulsaESC
, salimos (no nos interesa saber si está pulsada la tecla, solo si se ha pulsado).
Ya podemos empezar a definir nuestro bucle:
# el bucle ******************************* # para procesar eventos ev = SDL::Event.new listo = false while ! listo # primero: eventos inmediatos # mientras hayan eventos, los procesamos while ev.poll != 0 # hay que procesar QUIT if ev.type == SDL::Event::QUIT puts "quit!\n"; listo = true end # si se pulsa ESC, nos vamos if ev.type == SDL::Event::KEYDOWN && ev.keySym == SDL::Key::ESCAPE # se ha pulsado una tecla y # además es ESC! puts "ESC!\n"; listo = true end end # segundo: teclas pulsadas # hay que hacer un scan lo primero de todo SDL::Key.scan # verificamos algunas teclas if SDL::Key.press?(SDL::Key::UP) puts "se pulsa arriba!\n"; elsif SDL::Key.press?(SDL::Key::DOWN) puts "se pulsa abajo!\n"; end if SDL::Key.press?(SDL::Key::RIGHT) puts "se pulsa derecha!\n"; elsif SDL::Key.press?(SDL::Key::LEFT) puts "se pulsa izquierda!\n"; end end
Parece muy sencillo, pero hay algunas cosas jugosas para comentar.
Primero creamos un objeto SDL::Event
, que usaremos todo el tiempo. No hace falta crear un objeto en cada vuelta de bucle, así que la llamada al método constructor la hacemos fuera del while
principal.
En la primera fase, mientras hayan eventos pendientes, los procesamos. Cada vez que se llama al método poll
, se devuelve 0
o 1
dependiendo de si hay o no un evento pendiente, y se saca el evento de la cola para procesarlo. Aunque pueda parecer que con esta estructura el programa se quedará congelado en ese bucle si no dejan de llegar eventos, esto no pasará. El programa es muy rápido procesando la cola y no tendremos problemas para hacer otras cosas además de vaciar la cola ;).
En esta fase lo esencial es verificar el evento SDL::Event::QUIT
, poniendo la variable de terminación del bucle a cierto si es necesario. Podemos verificar que este caso se da cuando se cierra la ventana del programa (he empleado puts
para mostrar mensajes en consola).
Luego verificamos la pulsación de ESC
, mirando si se pulsa una tecla (el tipo de evento) y además si es SDL::Key::ESCAPE
(dato que hay en un evento de ese tipo).
En la segunda fase miramos si alguna tecla interesante está pulsada. Si llamamos al método press?
sin llamar antes a scan
, tendremos problemas (le he mandado un informe de error a Ohbayashi y me ha contestado que estará arreglado para la próxima versión).
Por ahora esta segunda fase tiene poca importancia, solo la he puesto para que jueguemos un poco con ella. Aún así es interesante entender que se puede dar el caso de pulsar, por ejemplo, ARRIBA y DERECHA a la vez, pero no ARRIBA y ABAJO (damos prioridad a ARRIBA en ese caso). He empleado la estructura if ... elsif
de Ruby
, que es muy cómoda para este caso.
Ya tenemos al 50% más o menos el bucle general del juego que describimos en la primera anotación de la serie. Ahora tenemos que empezar a ver fundamentos de animación y técnicas de dibujo, pero eso ya lo dejo para la próxima entrega ;).
Hay 3 comentarios
Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.
por Des, en 2005-12-21 13:58:34 ∞