Trouble with SDL keyboard movement

Started by
12 comments, last by The Rug 18 years, 6 months ago
#include <SDL/SDL.h>

// things for the window

const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const char* WINDOW_CAPTION = "Pong Clone";


void Paddle1()
{
     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");
     
     SDL_Rect source; 
     source.x = 0;
     source.y = 1;
     source.w = 25;
     source.h = 100;
     
     
     SDL_Rect dest;
     dest.x = 75;
     dest.y = 100;
     dest.w = 100;
     dest.h = 100;
     
     
     SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);
     SDL_Flip(SDL_GetVideoSurface());
     
     bool keysheld[323];

     SDL_Event event;
     if(SDL_PollEvent(&event))
     {
          if(event.type==SDL_KEYDOWN)
          {
               keysheld[event.key.keysym.sym] = true;
          }
          if(event.type==SDL_KEYUP)
          {
               keysheld[event.key.keysym.sym] = false;
          }
     }
     if(keysheld[SDLK_UP])
     {
           dest.y -=2;
     }
     if(keysheld[SDLK_DOWN])
     {
          dest.y+=2;
          if(dest.y+dest.h > WINDOW_HEIGHT)
          {
               dest.y=600 - dest.h;
          }
     }
}




void Paddle2()
{
     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");
     
     SDL_Rect source; 
     source.x = 0;
     source.y = 1;
     source.w = 25;
     source.h = 100;
     
     
     SDL_Rect dest;
     dest.x = 700;
     dest.y = 100;
     dest.w = 100;
     dest.h = 100;
     
     
     
     SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);
     SDL_Flip(SDL_GetVideoSurface());
}

void Ball()
{
     SDL_Surface* bitmap=SDL_LoadBMP("ball.bmp");
     
     SDL_Rect source; 
     source.x = 0;
     source.y = 1;
     source.w = 40;
     source.h = 40;
     
     
     SDL_Rect dest;
     dest.x=WINDOW_WIDTH/2;
     dest.y=WINDOW_HEIGHT/2;
     dest.w=WINDOW_WIDTH/2;
     dest.h=WINDOW_HEIGHT/2;
     
     
     
     SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);
     SDL_Flip(SDL_GetVideoSurface());
}

void Game()
{
    
     Paddle1();
     Paddle2();
     Ball();
}

void Shortcut_to_start()
{     
     SDL_Init( SDL_INIT_VIDEO );
     SDL_Surface* screen=SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
     SDL_WM_SetCaption( WINDOW_CAPTION, 0 );
    
    
    SDL_Event event;
    bool gamerunning = true;
    
    
    while(gamerunning)
    {
       Game();
       
       if(SDL_PollEvent(&event))
       {
          if(event.type == SDL_QUIT)
          {
             gamerunning = false;
          }
          if(event.type == SDL_KEYDOWN)
          {
          SDLKey keypressed = event.key.keysym.sym;
          
          
             switch(keypressed)
             {
                case SDLK_ESCAPE: gamerunning = false;
                break;
             }
          }
       }
    }
    
    
    SDL_Quit();
}
     

int main(int argc, char **argv)
{
    Shortcut_to_start();
    
    return 0;
}
The pictures are still and the only button that will work is Escape, which exits the program. Thanks if you know what I need to fix
Advertisement
Whenever you call SDL_PollEvent, the event gets taken off the event queue. No matter what kind of event it is. So since you call it in two different places (Paddle1() and main()), sometimes main() will pop off the event and sometimes Paddle1() will pop it off. What happens when main pops off the SDLK_UP or SDLK_DOWN keydown events, or when Paddle1() pops off the SDLK_ESCAPE event?
{[JohnE, Chief Architect and Senior Programmer, Twilight Dragon Media{[+++{GCC/MinGW}+++{Code::Blocks IDE}+++{wxWidgets Cross-Platform Native UI Framework}+++
You really need to unify your event handling. Right now you're getting keypress events scattered between two different polls so you're undoubtedly losing some.

To solve this, you need to make it so you only have one place where you're polling for events. You can buffer the keystates in an array like you're doing, but do it with a global so that all the functions have access to the current keystates:

// global!! :Dbool keys[SDLK_LAST];// in main game loopSDL_Event event;while (SDL_PollEvent(&event)) {    if (event.type = SDL_QUIT) {         gamerunning = false; }    if (event.type == SDL_KEYDOWN) {         keys[event.key.keysym.sym] = true; }    if (event.type == SDL_KEYUP) {         keys[event.key.keysym.sym] = false; }}// and then you can take that out of the paddle code, which // would then becomes just the check to see if the up/down// keys are currently being held 

Hope that helps

EDIT: Beaten :(
#include <SDL/SDL.h>// things for the windowconst int WINDOW_WIDTH = 800;const int WINDOW_HEIGHT = 600;const char* WINDOW_CAPTION = "Pong Clone";// dont know why i need this!bool keys[SDLK_LAST];void Paddle1(){     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 25;     source.h = 100;               SDL_Rect dest;     dest.x = 75;     dest.y = 100;     dest.w = 100;     dest.h = 100;               SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());          bool keysheld[323];     if(keysheld[SDLK_UP])     {           dest.y -=2;     }     if(keysheld[SDLK_DOWN])     {          dest.y+=2;          if(dest.y+dest.h > WINDOW_HEIGHT)          {               dest.y=600 - dest.h;          }     }}void Paddle2(){     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 25;     source.h = 100;               SDL_Rect dest;     dest.x = 700;     dest.y = 100;     dest.w = 100;     dest.h = 100;                    SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());}void Ball(){     SDL_Surface* bitmap=SDL_LoadBMP("ball.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 40;     source.h = 40;               SDL_Rect dest;     dest.x=WINDOW_WIDTH/2;     dest.y=WINDOW_HEIGHT/2;     dest.w=WINDOW_WIDTH/2;     dest.h=WINDOW_HEIGHT/2;                    SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());}void Game(){         Paddle1();     Paddle2();     Ball();}void Shortcut_to_start(){          SDL_Init( SDL_INIT_VIDEO );     SDL_Surface* screen=SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);     SDL_WM_SetCaption( WINDOW_CAPTION, 0 );            SDL_Event event;    bool gamerunning = true;            while(gamerunning)    {       Game();              if(SDL_PollEvent(&event))       {          if(event.type == SDL_QUIT)          {             gamerunning = false;          }          if(event.type == SDL_KEYDOWN)          {          SDLKey keypressed = event.key.keysym.sym;                                 switch(keypressed)             {                case SDLK_ESCAPE: gamerunning = false;                break;             }          }       }    }            SDL_Quit();}     int main(int argc, char **argv){    Shortcut_to_start();        return 0;}


All right, I still dont really understand, also i had taken out the poll from my game loop and it still dosn't work (im confused)
Okay, what we're doing is using a single event poll to make sure that we don't accidentially lose any events (keypresses) because we already got them and didn't do anything with them (what your original code did). To do this, we're going to make sure that, no matter what the event is, we get the information we need and save it for later.

In this case, we're going to do that by buffering the state of every key in a global variable so that every function can "see" it.

First: change the polling in the game loop to this:
      if(SDL_PollEvent(&event))       {          if(event.type == SDL_QUIT)          {             gamerunning = false;          }          if(event.type == SDL_KEYDOWN)          {             keys[event.key.keysym.sym] = true;          }          if(event.type == SDL_KEYDOWN)             keys[event.key.keysym.sym] = false;          }       }       if (keys[SDLK_ESCAPE] == true) {          gamerunning = false; }    }

The reason why its not working is because you are still polling for events in two places. First take out the declaration of the array of keystates in Paddle1, since we moved that out to global so it was actually saved between each pass. (it was being deleted each time after Paddle1 returned)
void Paddle1(){     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 25;     source.h = 100;               SDL_Rect dest;     dest.x = 75;     dest.y = 100;     dest.w = 100;     dest.h = 100;               SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());          //bool keysheld[323]; // ***TAKE THIS LINE OUT***

And because we're doing all our event stuff in one place, we don't want to have another loop to steal events. So we're going to have to take that out:
     /*SDL_Event event;     if(SDL_PollEvent(&event))     {          if(event.type==SDL_KEYDOWN)          {               keysheld[event.key.keysym.sym] = true;          }          if(event.type==SDL_KEYUP)          {               keysheld[event.key.keysym.sym] = false;          }     }*/     if(keys[SDLK_UP])     {           dest.y -=2;     }     if(keys[SDLK_DOWN])     {          dest.y+=2;          if(dest.y+dest.h > WINDOW_HEIGHT)          {               dest.y=600 - dest.h;          }     }}

If you want a more detailed explanation of exactly why polling in two places doesn't work, I'll be happy to give one.
#include <SDL/SDL.h>// things for the windowconst int WINDOW_WIDTH = 800;const int WINDOW_HEIGHT = 600;const char* WINDOW_CAPTION = "Pong Clone";// dont know why i need this!bool keys[SDLK_LAST];bool keysheld[323];void Paddle1(){     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 25;     source.h = 100;               SDL_Rect dest;     dest.x = 75;     dest.y = 100;     dest.w = 100;     dest.h = 100;               SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());     if(keys[SDLK_UP])     {           dest.y -=2;     }     if(keys[SDLK_DOWN])     {          dest.y+=2;          if(dest.y+dest.h > WINDOW_HEIGHT)          {               dest.y=600 - dest.h;          }     }}void Paddle2(){     SDL_Surface* bitmap=SDL_LoadBMP("Paddle.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 25;     source.h = 100;               SDL_Rect dest;     dest.x = 700;     dest.y = 100;     dest.w = 100;     dest.h = 100;                    SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());}void Ball(){     SDL_Surface* bitmap=SDL_LoadBMP("ball.bmp");          SDL_Rect source;      source.x = 0;     source.y = 1;     source.w = 40;     source.h = 40;               SDL_Rect dest;     dest.x=WINDOW_WIDTH/2;     dest.y=WINDOW_HEIGHT/2;     dest.w=WINDOW_WIDTH/2;     dest.h=WINDOW_HEIGHT/2;                    SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());}void Game(){         Paddle1();     Paddle2();     Ball();}void Shortcut_to_start(){          SDL_Init( SDL_INIT_VIDEO );     SDL_Surface* screen=SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);     SDL_WM_SetCaption( WINDOW_CAPTION, 0 );            SDL_Event event;    bool gamerunning = true;            while(gamerunning)    {       Game();              if(SDL_PollEvent(&event))       {          if(event.type == SDL_QUIT)          {             gamerunning = false;          }          if(event.type == SDL_KEYDOWN)          {             keys[event.key.keysym.sym] = true;          }          if(event.type == SDL_KEYDOWN)             keys[event.key.keysym.sym] = false;          }       }       if (keys[SDLK_ESCAPE] == true) {          gamerunning = false; }            SDL_Quit();}     int main(int argc, char **argv){    Shortcut_to_start();        return 0;}


Ok i follwed the directions and tried to understand, here is what i came up with and it still dosnt move.
Uhh, I have no idea what they mean. But there is an easier way. Have this:
Uint8 *Keys;Keys = SDL_GetKeyState(NULL);if (Keys[SDLK_UP]) // or whatever    // whatever

Just like in my example, check for key presses with Keys[...].

About the keypresses all over the place, yes it true. Have something like this game pump:
// sample game pumpwhile(MyGameIsRunningBool == true){    MyUpdateGameFunction(); // Includes all keypresses and events    MyDrawEverythingFunction(); // Draws all the graphics}

This was just an example. The idea is not to check for keypresses all over the place.

-DBZ-
-----------------------------....::::DRAGON BALL Z::::....C<<"+"<<"+"; // Go C++ !!!-----------------------------
If you do use that method, just be aware that you have to call SDL_PumpEvents(); each pass to update the key states. SDL_PumpEvents is called for you when you use SDL_PollEvent or SDL_WaitEvent, which is why you don't need it when using those functions.
#include "SDL/SDL.h"const int WINDOW_WIDTH = 800;const int WINDOW_HEIGHT = 600;const char* WINDOW_TITLE = "SDL Start";SDL_Event event;bool gamerunning = true;void Paddle1(){     //DRAW     SDL_Surface*bitmap=SDL_LoadBMP("paddle.bmp");          SDL_Rect source;     source.x = 0;     source.y = 1;     source.w = 25;     source.h = 100;          SDL_Rect dest;     dest.x = 75;     dest.y = 50;     dest.w = 75;     dest.h = 50;          SDL_BlitSurface(bitmap, &source, SDL_GetVideoSurface(), &dest);     SDL_Flip(SDL_GetVideoSurface());          //MOVE     }void Game(){     Paddle1();}void Init(){   SDL_Init( SDL_INIT_VIDEO );   SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0,       SDL_HWSURFACE | SDL_DOUBLEBUF );   SDL_WM_SetCaption( WINDOW_TITLE, 0 );    SDL_Event event;   while (gamerunning)   {      if (SDL_PollEvent(&event))      {         Game();         if (event.type == SDL_QUIT)         {            gamerunning = false;         }         if (event.type == SDL_KEYDOWN)         {            SDLKey keyPressed = event.key.keysym.sym;                  switch (keyPressed)            {               case SDLK_ESCAPE:                  gamerunning = false;                  break;            }         }      }    }   SDL_Quit();}int main(int argc, char **argv){   Init();   return 0;}


All right, thank you and sorry you guys, but there is too much information thrown at me, so pardon me as I paste a whole new code with less waste as the first, now my question is, What do I need add, Where and Why :-D
First, you need a gamerunning variable declared, not just used. That said, game() should be outside of the polling events. Then it lookds pretty nice. Though I suggest you have an update() function like this:
while(gamerunning){    update();}

Which would get all the input, instead of throwing it in the loop like that.
Other than that, good start. Good luck.
-----------------------------....::::DRAGON BALL Z::::....C<<"+"<<"+"; // Go C++ !!!-----------------------------

This topic is closed to new replies.

Advertisement