Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am developing a game using SDL, and am unable to do continuous motion for my object when a key is held down.

I'm calling SDL_PollEvent() to retrieve all events during a frame, and passing each resulting SDL_Event structure into this function:

void Avatar::handle_input(SDL_Event keyInput){
if( keyInput.type == SDL_KEYDOWN )
{
    //Adjust the velocity
    switch( keyInput.key.keysym.sym )
    {
    case SDLK_LEFT: Move(1); break;
    case SDLK_RIGHT: Move(2); break;
    }
}

The problem is that when I hold down the right or left arrow keys, the avatar only moves once instead of moving continuously for as long as I hold down the key. How can I make the motion continue for as long as the key is held down?

share|improve this question
    
    
I have added a comment on Trevor's reply. I don't think this will help me in my situation. –  Vabs Feb 18 '13 at 5:59
add comment

3 Answers

up vote 10 down vote accepted

An SDL_KEYDOWN event is only sent when the key is first pressed. You will receive an SDL_KEYUP event when it's released.

You'll want to handle moving in code which gets called every frame, not in response to an event. Inside Avatar::handle_input, you'll instead want to set variables to tell you whether each key is up or down, and update those variables as you receive SDL_KEYDOWN and SDL_KEYUP events for those keys.

share|improve this answer
    
I will clarify a bit further. The avatar in my code moves if I press the key and release it and repeat this. But I want the motion to work even if I am keeping the key pressed. I read how events work in SDL but that was not much helpful. Won't the SDL_KEYDOWN event will be called if I keep the key pressed and move the avatar. –  Vabs Feb 18 '13 at 5:56
    
As I said above, no, SDL_KEYDOWN is only sent when the key changes from 'up' to 'down'. (Similarly, SDL_KEYUP is only sent when it changes from 'down' to 'up'). SDL is only notifying you when a key's state actually changes. If you want to know whether the key is up or down at other times, then you really need to keep track of the most recent status you were informed of (using variables, as I explained in the answer above). –  Trevor Powell Feb 18 '13 at 6:16
add comment

An event is simply that - an event, and tells you when something has happened, not what the current state is. So you only get one keydown event, when the key first goes down, then a key up event when the key is released again.

For continuous motion, you have 2 choices:

  1. Use the events to set your game's internal state. This is the example that Petr Abdulin gives in one answer here, which is an example of what Trevor Powell tells you in another answer.
  2. SDL does actually provide a system for tracking which keys are in which state, and you can check this every frame if you want to implement continuous motion during key presses without tracking key states yourself. The function is called SDL_GetKeyState and the documentation is here. You can make these checks in your movement handling function and they should work as you expect.
share|improve this answer
add comment

Trevor is correct, you actually need something like this:

// define vars somewhere
bool left_down;
bool right_down;

void Avatar::handle_input(SDL_Event keyInput)
{
    //If a key was pressed
    if( keyInput.type == SDL_KEYDOWN )
    {
        //Adjust the velocity
        switch( keyInput.key.keysym.sym )
        {
        case SDLK_LEFT: left_down = true; break;
        case SDLK_RIGHT: right_down = true; break;
        }
    }

    if( keyInput.type == SDL_KEYUP )
    {
        //Adjust the velocity
        switch( keyInput.key.keysym.sym )
        {
        case SDLK_LEFT: left_down = false; break;
        case SDLK_RIGHT: right_down = false; break;
        }
    }
}

// somewhere in the `update` function of game loop
update(/*...*/)
{
    if(left_down)
    {
        Move(1);
    }

    if(right_down)
    {
        Move(2);
    }
}

The code above does illustrates principle, but is hardly a way to implement it in a nice way. The better way is to have a keys array, which you can address like keys[SDLK_LEFT] and some universal utility functions.

More info is available directly from SDL docs.

share|improve this answer
    
Good answer, but you shouldn't need your own keys array, as SDL provides this for you (as I mentioned in my answer). –  Kylotan Feb 18 '13 at 8:11
    
@Kylotan thanks for additional info, I just never worked with SDL :) –  Petr Abdulin Feb 18 '13 at 8:51
3  
Don't put the "if(left_down)" and "if(right_down)" in that function; it needs to go somewhere else, somewhere which gets called precisely once per frame. That event handler function will be called once for each event that comes in during the frame, which could be none, or could be twenty or more. Your movement speed will vary wildly with the code arranged that way. :) –  Trevor Powell Feb 18 '13 at 11:15
    
Thanks for the help guys. @PetrAbdulin you code did give me insight on my problem. –  Vabs Feb 18 '13 at 14:10
    
@TrevorPowell that is correct, thanks, I fixed the bug in code example. –  Petr Abdulin Feb 18 '13 at 15:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.