11
\$\begingroup\$

I have created a cube in opengl using SDL. Now I am trying to move the camera in X direction if user presses left or right arrow keys and Y direction if user presses up or down arrow keys. Right now the camera moves by a fixed amount in a particular direction if the key gets pressed once. It doesn't matter how long does a person hold the key down, it moves by that fixed amount only. I want the camera to move continuously as long as the key is pressed.

Below is the code for keyboard polling.

        while ( SDL_PollEvent( &event ) )
        {
            switch( event.type )
            {
            case SDL_ACTIVEEVENT:
                if ( event.active.gain == 0 )
                isActive = FALSE;
                else
                isActive = TRUE;
                break;              
            case SDL_VIDEORESIZE:
                surface = SDL_SetVideoMode( event.resize.w,
                            event.resize.h,
                            16, videoFlags );
                if ( !surface )
                {
                    fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) );
                    Quit( 1 );
                }
                resizeWindow( event.resize.w, event.resize.h );
                break;
            case SDL_KEYDOWN:
                handleKeyPress( &event.key.keysym );
                break;
            case SDL_QUIT:
                done = TRUE;
                break;
            default:
                break;
            }
        }

And below i have mentioned the keypress handler function

void handleKeyPress( SDL_keysym *keysym )
{
    switch( (keysym->sym) ){
        case SDLK_ESCAPE:
            Quit(0);
            break;
        case SDLK_LEFT:
              eye[0] -= 0.1;
              break;
            case SDLK_RIGHT:
              eye[0] += 0.1;
              break;
            case SDLK_UP:
              eye[1] -= 0.1;
              break;
            case SDLK_DOWN:
              eye[1] += 0.1;
              break;
            default:
              break;
      }

    return;
}

What changes should I make in my code to handle continuous keystroke detection?

Note: The following code does the required job but I don't understand why

if ( ( SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ) ) )
{
        fprintf( stderr, "Setting keyboard repeat failed: %s\n",
             SDL_GetError( ) );
        Quit( 1 );
}
\$\endgroup\$
1
  • \$\begingroup\$ Please consider reviewing some of the questions you've asked and accepting the answers. \$\endgroup\$
    – user1430
    Nov 9, 2011 at 15:55

4 Answers 4

20
\$\begingroup\$
void Main::processInput()
{
    Uint8* keystate = SDL_GetKeyState(NULL);

    //continuous-response keys
    if(keystate[SDLK_LEFT])
    {
    }
    if(keystate[SDLK_RIGHT])
    {
    }
    if(keystate[SDLK_UP])
    {
    }
    if(keystate[SDLK_DOWN])
    {
    }

    //single-hit keys, mouse, and other general SDL events (eg. windowing)
    while(SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_MOUSEMOTION:
            break;

            case SDL_QUIT:
            case SDL_KEYDOWN:
                if(event.key.keysym.sym == SDLK_ESCAPE)
                    done = true; //quit
            break;
        }
    }
}

Usage:

Main::Main()
{
    //set up SDL etc.
    //set up timing variables etc.
    timeStepMs = 1000.f / yourUpdateFrequency; //eg. 30Hz
    //set up game world etc.

    //main loop, run like the wind!
    while(!done)
    {

        timeLastMs = timeCurrentMs;
        timeCurrentMs = SDL_GetTicks();
        timeDeltaMs = timeCurrentMs - timeLastMs;
        timeAccumulatedMs += timeDeltaMs;

        while (timeAccumulatedMs >= timeStepMs)
        {
              processInput();
              //update world: do ai, physics, etc. here
              timeAccumulatedMs -= timeStepMs;
        }
        render(); //render update only once
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ You should call SDL_PumpEvents() before SDL_GetKeyState(), otherwise you're operating on last frame's key state. Alternatively, call SDL_GetKeyState() after the SDL_PollEvents() loop. \$\endgroup\$ Jun 11, 2012 at 2:24
  • \$\begingroup\$ while(SDL_PollEvent(&event)) where is event defined? \$\endgroup\$
    – joncodo
    Dec 21, 2012 at 15:08
  • 1
    \$\begingroup\$ @JonathanO How about this ;) \$\endgroup\$
    – Engineer
    Dec 22, 2012 at 13:19
  • \$\begingroup\$ @NickWiggill: +1 Thanks, the idea helped me do the same in GLFW :) \$\endgroup\$
    – legends2k
    Mar 2, 2014 at 11:17
  • 4
    \$\begingroup\$ For those using SDL2: This is a good solution but you have to use SDL_GetKeyboardState() rather than SDL_GetKeyState() and key code constants SDL_SCANCODE_x rather than SDLK_x. See e.g. cs.umb.edu/~bazz/cms/index.php?id=sdl-sdl2-migration-experience \$\endgroup\$ Mar 18, 2016 at 9:42
3
\$\begingroup\$

If you're using SDL version 1.x, use SDL_GetKeyState() to determine whether a key is up or down.

If you're using SDL version 2.x, use SDL_GetKeyboardState() to determine whether a key is up or down.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Please don't answer with just a link to another site. gamedev.stackexchange.com/questions/how-to-answer \$\endgroup\$
    – thedaian
    Nov 9, 2011 at 19:49
  • \$\begingroup\$ Fair enough - it's just frustrating that this question has come up about 3 times and it's right in the docs. I don't think we should be essentially duplicating external documentation. \$\endgroup\$
    – Kylotan
    Nov 9, 2011 at 20:34
  • 1
    \$\begingroup\$ Agreed, though your answer would have been better as a comment instead of a full answer in that case. \$\endgroup\$
    – thedaian
    Nov 9, 2011 at 20:53
  • \$\begingroup\$ The page you were looking for couldn't be found. There is a reason why posting ONLY a link is considered bad. \$\endgroup\$ Oct 24, 2015 at 20:16
1
\$\begingroup\$

I don't know exactly how to do it in SDL, but in pseudo code this is the approach

bool[] isKeyDown
bool[] isKeyPressed

public void Check(){
    foreach Key k in Keys
        if(k.isDown && !isKeyDown[k]){
               isKeyDown[k] = true;
               isKeyPressed[k] = true;
        }        
        else if(k.IsDown && isKeyDown[k]){
            isKeyPressed[k] = false;
        }    
        else{
            isKeyDown[k] = false;
            isKeyPressed[k] = false;
        }
    }
}     

This way isKeyPressed[k] is true and only true the first time k was pressed, you can use that for menu navigation. Alternatively isKeyDown[k] is true the entire time that k was pressed.

Now I'm pretty confident that SDL has a way to request the current key state, but if you can only repsond to events you just clear isKeyPressed[k] at the start of every game loop, make isKeyPressed[k] and isKeyDown[k] true on every KeyDown event and make isKeyDown[k] false on every KeyUp event.

\$\endgroup\$
1
\$\begingroup\$

You're going to want it to read SDL_KEYUP and SDL_KEYDOWN. You can either have it so it sets a boolean to true when the key is pressed and to false when the key is unpressed and then have it check the booleans and perform an action if true, or you can do something like this...

if(SDL_PollEvent(&event)) {
    if(event.type==SDL_KEYDOWN) {
        switch(event.key.keysym.sym) {
            case SDLK_UP:    yVel-=2; break;
            case SDLK_DOWN:  yVel+=2; break;
            case SDLK_LEFT:  xVel-=2; break;
            case SDLK_RIGHT: xVel+=2; break;
        }
    }
    if(event.type==SDL_KEYUP) {
        switch(event.key.keysym.sym) {
            case SDLK_UP:    yVel+=2; break;
            case SDLK_DOWN:  yVel-=2; break;
            case SDLK_LEFT:  xVel+=2; break;
            case SDLK_RIGHT: xVel-=2; break;
        }
    }
}

And then simply add the x/yVel to the x/y position of what you want to move...

x+=xVel;
y+=yVel;
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .