AnteriorPosterior

6. Vamos a imitar "getch"

  Curso: Introducción a los gráficos en C con SDL

6. Vamos a imitar "getch"


Uno de los problemas con los que se suele encontrar quien empieza con SDL es echar en falta una función sencilla como "getch", que permita esperar hasta que se pulse una tecla, y saber qué tecla se ha pulsado.

Esto no es algo que se pueda usar en cualquier juego: muchas veces debemos mover algo aunque el usuario no pulse ninguna tecla, y no podemos permitirnos que el programa se quede parado.

Pero en otras ocasiones, (por ejemplo, una pantalla de bienvenida) sí puede ser útil tratar de imitar "getch()" para que nuestro fuente sea más sencillo.

Una forma de conseguirlo podría ser ésta, basándonos en el ejemplo 3:

 1: /*******************************************
2: * Introduccion a SDL - 6 *
3: * Curso de C, Nacho Cabanes *
4: *******************************************/

5:
6: #include <stdlib.h>
7: #include <SDL/SDL.h>
8:
9: int nSDL_getch() {
10: SDL_Event suceso;
11:
12: /* Imitacion de "getch()" para SDL */
13: while (1) { /* Repetimos indefinidamente */
14: while (SDL_PollEvent(&suceso)) { /* Comprobamos sucesos */
15: if (suceso.type == SDL_KEYDOWN) /* Si es tecla pulsada */
16: return suceso.key.keysym.sym; /* La devolvermos */
17: }
18: }
19: }
20:
21: int main(int argc, char *argv[])
22: {
23: SDL_Surface *screen;
24: SDL_Surface *fondo;
25: SDL_Surface *protagonista;
26: SDL_Rect destino;
27: int i, j;
28: int xProt = 320, yProt= 400;
29: int terminado = 0;
30: int tecla;
31:
32:
33: /* Tratamos de inicializar la biblioteca SDL */
34: if (SDL_Init(SDL_INIT_VIDEO) < 0) {
35: printf("No se pudo inicializar SDL: %s\n", SDL_GetError());
36: exit(1);
37: }
38:
39: /* Preparamos las imagenes a mostrar */
40: fondo = SDL_LoadBMP("fondo.bmp");
41: protagonista = SDL_LoadBMP("protag.bmp");
42: /* El protagonista debe tener contorno transparente */
43: SDL_SetColorKey(protagonista, SDL_SRCCOLORKEY,
44: SDL_MapRGB(protagonista->format, 0, 0, 0));
45:
46: /* Si todo ha ido bien, hacemos algo:
47: entrar a modo grafico y cambiar el título de la ventana */

48: screen = SDL_SetVideoMode( 640, 480, 16, SDL_HWSURFACE );
49: if(screen == NULL) {
50: printf( "Error al entrar a modo grafico: %s\n", SDL_GetError() );
51: SDL_Quit();
52: return -1;
53: }
54:
55: /* Titulo de la ventana */
56: SDL_WM_SetCaption( "Hola mundo 6!", "Hola Mundo 6!" );
57:
58: /* Parte repetitiva: hasta que se elija terminar */
59: while(terminado == 0) {
60:
61: /* Dibujamos la imagen de fondo */
62: /* Como tiene 207 x 211 pixeles, la repetimos varias veces */
63: for (i=0; i<3; i++)
64: for (j=0; j<3; j++) {
65: destino.x=207*i;
66: destino.y=211*j;
67: SDL_BlitSurface(fondo, NULL, screen, &destino);
68: }
69:
70: /* Dibujamos el protagonista */
71: destino.x=xProt;
72: destino.y=yProt;
73: SDL_BlitSurface(protagonista, NULL, screen, &destino);
74:
75: /* Actualizamos la pantalla */
76: SDL_Flip(screen);
77:
78: /* Esperamos una tecla */
79: tecla = nSDL_getch();
80:
81: /* Y vemos cual ha sido */
82: if (tecla == SDLK_ESCAPE) { terminado = 1; }
83: if (tecla == SDLK_UP) { yProt -= 2; }
84: if (tecla == SDLK_DOWN) { yProt += 2; }
85: if (tecla == SDLK_LEFT) { xProt -= 3; }
86: if (tecla == SDLK_RIGHT) { xProt += 3; }
87:
88: /* Y esperamos 50 ms antes de repetir */
89: SDL_Delay( 50 );
90: }
91:
92: /* Finalmente, preparamos para salir */
93: SDL_Quit();
94: return 0;
95: }

Eso sí, esta forma de trabajar tiene un par de problemas:
  • Sólo lee una pulsación por tecla, sin hacer caso si la mantenemos pulsada.
  • No comprobamos los demás tipos de sucesos, de modo que no se podría abandonar el programa pulsando la X de la ventana.
La segunda limitación es algo más seria, pero la primera se puede evitar si usamos la función "SDL_EnableKeyRepeat(inicial, repeticion)" para indicar si queremos que comience a repetirse después de un cierto tiempo, y que a partir de entonces continúe cada instante.

Por ejemplo, para que la pausa inicial fueran de 20 milésimas de segundo y el intervalo de repetición fuera el mismo, haríamos en el cuerpo de nuestro programa, antes de la parte repetitiva:

  /* Permitimos que nuestro "getch" repita cada 20 ms */
  SDL_EnableKeyRepeat(20, 20);

/* Titulo de la ventana */
  SDL_WM_SetCaption( "Hola mundo 7!", "Hola Mundo 7!" );
...

De igual modo, otra rutina "nuestra" que puede ser interesante (si nuestro programa maneja pocas pulsaciones de teclas), es crear una función que imite el "keypressed" de Turbo C: que nos diga si se ha pulsado una tecla o no, sin llegar a detener el programa.

Es muy parecido al "getch" que hemos creado, pero sin el "while(1)" que hace que se repita indefinidamente, así:

/*** Funcion alternativa a keypressed() ***************/
int nSDL_keypressed() {
SDL_Event suceso;

while (SDL_PollEvent(&suceso)) { /* Comprobamos sucesos */
if (suceso.type == SDL_KEYDOWN) /* Si es tecla pulsada */
return suceso.key.keysym.sym; /* La devolvemos */
}
/* Si no hay tecla pulsada, devolvemos 0 (falso) */
return 0;
}


Actualizado el: 06-06-2006 02:15

AnteriorPosterior