comportamiento extraño del SDL_GetKeyState

Consulte acerca de programas, técnicas, algoritmos etc.

comportamiento extraño del SDL_GetKeyState

Notapor maije » Mié Dic 19, 2007 5:48 pm

hola a todos
tengo el siguiente problema: estoy haciendo un juego tipico de avioncitos y resulta que quiero que los avioncitos se muevan en diagonal y que el programa reconozca varias teclas pulsadas al tiempo. pues bien, la unica forma que he encontrado para hacerlo es "sacando una foto al teclado" con su estado actual y que me diga si una tecla esta apretada o no lo esta, en cada caso, incremento o decremento una variable y asi se mueve todo bonito.
el problema es que cuando pulso una tecla, despues otra direccion y suelto la ultima direccion, se me queda parado en vez de seguir moviendose en la direccion del principio, me explico con un ejemplo:

si pulso [derecha, arriba] se mueve en diagonal superior derecha
si pulso [izquierda, abajo] se mueve en diagonal inferior izquierda
si pulso [izquierda, abajo, suelto abajo] deberia moverse en diagonal inferior izquierda y luego seguir moviendose a la izquierda no??? pues no, se queda parado.
si pulso [izquierda, abajo, suelto izquierda] se mueve en diagonal inferior izquierda y luego sigue hacia abajo con normalidad, atendiendo a la orden que he dado.

no se si se ha entendido bien, el caso general es que si presiono una tecla y luego otra, se mueve en diagonal, pero al soltar la segunda que aprete para seguir con mi movimiento, se detiene. esto no pasa si presiono una tecla, luego otra y luego suelto la primera que presione...que se mueve correctamente en la direccion de la segunda.

aqui os pego mi codigo a ver si encontrais el fallo:

Código: Seleccionar todo
#include <stdio.h>
#include <stdlib.h>
#include <SDL.h>
#include <SDL_image.h>

#define SCREEN_HEIGHT 600
#define SCREEN_WIDTH 800
#define COLOR_DEPTH 24
#define VELOCIDAD 4

int main(int argc, char *argv[]) {
   SDL_Surface *image, *screen;
   SDL_Rect dest, anterior;
   SDL_Event evento;
   int done = 0;
   Uint8 *keys;

   atexit(SDL_Quit);

   // Iniciar SDL
   if (SDL_Init(SDL_INIT_VIDEO) < 0) {
      printf("No se pudo iniciar SDL: %s\n",SDL_GetError());
      exit(1);
   }

   // Activamos modo de video
   screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_DEPTH, SDL_HWSURFACE);
   if (screen == NULL) {
      printf("No se puede inicializar el modo gráfico: \n",SDL_GetError());
      exit(1);
   }

   // Cargamos gráfico
   image = IMG_Load("images\\avion.bmp");
   if ( image == NULL ) {
      printf("No pude cargar gráfico: %s\n", SDL_GetError());
      exit(1);
   }

   //Permitimos el uso de teclas presionadas
   SDL_EnableKeyRepeat(10, 10);

   //Quitamos el color de trasparencia
   SDL_SetColorKey(image, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(image->format,255,0,0));

   // Definimos donde dibujaremos el gráfico y lo copiamos a la pantalla.
   dest.x = (SCREEN_WIDTH / 2) - (image->w / 2);
   dest.y = (SCREEN_HEIGHT / 2) - (image->h / 2);
   dest.w = image->w;
   dest.h = image->h;

   //Copiamos la imagen a la pantalla oculta en el doble buffer
   SDL_BlitSurface(image, NULL, screen, &dest);
   
   // Mostramos la pantalla
   SDL_Flip(screen);

   //bucle de espera activo
   while(done == 0) {
      
      //Bucle de espera inactivo
      while ( SDL_PollEvent(&evento) ) {
         if ( evento.type == SDL_KEYDOWN ) {//|| evento.type == SDL_KEYUP) {
            SDL_FillRect(screen,&dest,SDL_MapRGB(screen->format,0,0,0));
            keys=SDL_GetKeyState(NULL);
            //aqui esta el conflicto. la impresion de 1 y 0 lo hace bien
printf("arriba:%i\nabajo:%i\nderecha:%i\nizquierda:%i\n",keys[SDLK_UP],keys[SDLK_DOWN],keys[SDLK_RIGHT],keys[SDLK_LEFT]);
            if (keys[SDLK_UP] == 1) {dest.y -= VELOCIDAD;}
            if (keys[SDLK_DOWN] == 1) {dest.y += VELOCIDAD;}
            if (keys[SDLK_LEFT] == 1) {dest.x -= VELOCIDAD;}
            if (keys[SDLK_RIGHT] == 1) {dest.x += VELOCIDAD;}
            
            switch (evento.key.keysym.sym) {
               case SDLK_ESCAPE:
                  done = 1;
                  break;
            }

         }   
      }

      //Copiamos la imagen a la pantalla oculta en el doble buffer
      SDL_BlitSurface(image, NULL, screen, &dest);
      //Intercambiamos las pantallas, la dibujada y la obsoleta
      SDL_Flip(screen);
   }
   
   // liberar superficie
   SDL_FreeSurface(image);
   
   return 1;
}


**NOTA: de momento solo estoy usando C a pelo

para que este codigo funcione teneis que agregar las librerias, la dll y al carpeta include de SDL (no hace falta incluir la SDL_image porque todavia no cargo mas que un bmp aunque aparezca incluida en mi codigo). tambien debeis tener una carpeta en el directorio de vuestro proyecto llamada image que contenga avion.bmp

muchas gracias de antemano
atentamente
maije
maije
 
Mensajes: 20
Registrado: Lun Dic 17, 2007 6:20 pm

Notapor rcaf » Jue Dic 20, 2007 2:26 am

Hola:

Primero una aclaración, sí estas usando la SDL_image, ya que llamas a la función IMG_Load. Por lo tanto si hay que enlazar la biblioteca SDL_image.

El problema se debe a que estás cambiando la posición del avión dentro del loop de eventos.

Te dejo el código revisado, modificado y funcionando. Elimine algunas lineas de código y reoderné otras.

Código: Seleccionar todo
#include <stdio.h>
#include <stdlib.h>
#include <SDL.h>

#define SCREEN_HEIGHT 600
#define SCREEN_WIDTH 800
#define COLOR_DEPTH 24
#define VELOCIDAD 4

int main(int argc, char *argv[])
{
   SDL_Surface *image, *screen;
   SDL_Rect dest;
   SDL_Event evento;
   int done = 0;
   Uint8 *keys;

   atexit(SDL_Quit);

   // Iniciar SDL
   if (SDL_Init(SDL_INIT_VIDEO) < 0)
   {
      printf("No se pudo iniciar SDL: %s\n",SDL_GetError());
      exit(1);
   }

   // Activamos modo de video
   screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_DEPTH, SDL_HWSURFACE);
   if (screen == NULL)
   {
      printf("No se puede inicializar el modo gráfico: \n",SDL_GetError());
      exit(1);
   }

   // Cargamos gráfico
   image = SDL_LoadBMP("images\\avion.bmp");
   if ( image == NULL )
   {
      printf("No pude cargar gráfico: %s\n", SDL_GetError());
      exit(1);
   }

   //Quitamos el color de trasparencia
   SDL_SetColorKey(image, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(image->format,255,0,0));

   // Definimos donde dibujaremos el gráfico y lo copiamos a la pantalla.
   dest.x = (SCREEN_WIDTH / 2) - (image->w / 2);
   dest.y = (SCREEN_HEIGHT / 2) - (image->h / 2);
   dest.w = image->w;
   dest.h = image->h;

   //bucle de espera activo
   while(done == 0)
   {     
      //Bucle de espera inactivo
      while ( SDL_PollEvent(&evento) )
      {
           if(evento.type == SDL_QUIT) done=1;
      }
     
      keys=SDL_GetKeyState(NULL);

      if (keys[SDLK_ESCAPE]) done=1;
     
      if (keys[SDLK_UP]) dest.y -= VELOCIDAD;
      if (keys[SDLK_DOWN]) dest.y += VELOCIDAD;
      if (keys[SDLK_LEFT]) dest.x -= VELOCIDAD;
      if (keys[SDLK_RIGHT]) dest.x += VELOCIDAD;

      // Limpiamos la pantalla
      SDL_FillRect(screen, 0, 0);
     
      //Copiamos la imagen a la pantalla oculta en el doble buffer
      SDL_BlitSurface(image, NULL, screen, &dest);

      //Intercambiamos las pantallas, la dibujada y la obsoleta
      SDL_Flip(screen);
   }
   
   // liberar superficie
   SDL_FreeSurface(image);
   
   return 1;
}



Saludos!
Roberto Albornoz Figueroa
Mi Blog
Wiki
Avatar de Usuario
rcaf
 
Mensajes: 71
Registrado: Jue Ago 10, 2006 4:35 am
Ubicación: Concepción, Octava Región. Chile

Notapor maije » Jue Dic 20, 2007 3:05 pm

muchas gracias

efectivamente. encontre el error esta mañana comparando mi codigo con otro programa de ejemplo de esta veb, precisamente hecho por ti: Car.exe, y ya lo cambie. ahora estoy preparando el juego orientadolo a objetos un poco mas bonito y con la deteccion de colisiones ya implementada y el intercambio del grafico del avion por uno de explosion, un numero n de aviones enemigos al tiempo en pantalla, etc... todavia me falta la parte de animaciones internas de los graficos, que de momento son estaticos, el movimiento de los aviones y la generacion de mapas aleatorios por los que transcurra el juego. cuando termine de implementarlo bien, pegare en la web el codigo para que entre todos podamos refinarlo un poco y si quereis colgarlo como ejemplo, estara a vuestra disposicion.

gracias de nuevo y un saludo
maije
 
Mensajes: 20
Registrado: Lun Dic 17, 2007 6:20 pm


Volver a General

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado

cron