Keyboard problems whilst trying to apply Box2D physics

I’ve set out to create a really simple platformer game using SDL and Box2D. I’ve used SDL to make numerous times before, but this is the first time I’ve tried to incorporate Box2D into my engine. I’m having issues with the player movement however. I’ve been following the Box2D physics tutorials found here. My aim is to have my player character run left, right and be able to jump. Like Mario or any other platformer! However… using methods similar to the tutorials I follow my character ends up shooting across the screen too quickly when movement keys are pressed or when jumping flies too high and just not looking like a nice jump!

What I am aiming to achieve is so a player can move left, right and jump using Box2D like what you would expect in a normal game. My current input engine has a function which returns whether a keyboard button is being pressed, however for every single frame the button is held, I’m applying that much impulse to my player. Thus my character is whizzing about my screen far too fast. What I want to be able to do is hold a button down and have the player move… normally?

This is my current input code. Like I said, it uses SDL to gather input and records which button is down.

bool CInput::Update()
{
for( int i = 0; i < NUM_BUTTONS; ++i )
{
    m_buttonsDown[i] = false;
}

// Use events to check for keypresses and mouse events
while( SDL_PollEvent( &Event ))
{
    switch( Event.type )
    {
        case SDL_QUIT:
        {
            return false;
            break;
        }

        case SDL_KEYDOWN:
        {
            switch( Event.key.keysym.sym )
            {
                case SDLK_w: case SDLK_UP:
                {
                    m_buttons[BUTTON_W] = true;
                    m_buttonsDown[BUTTON_W] = true;
                    break;
                }

                case SDLK_s: case SDLK_DOWN:
                {
                    m_buttons[BUTTON_S] = true;
                    m_buttonsDown[BUTTON_S] = true;
                    break;
                }

                case SDLK_a: case SDLK_LEFT:
                {
                    m_buttons[BUTTON_A] = true;
                    m_buttonsDown[BUTTON_A] = true;
                    break;
                }

                case SDLK_d: case SDLK_RIGHT:
                {
                    m_buttons[BUTTON_D] = true;
                    m_buttonsDown[BUTTON_D] = true;
                    break;
                }

                default:
                    break;

            }
            break;
        }

        case SDL_KEYUP:
        {
            switch( Event.key.keysym.sym )
            {
                case SDLK_w: case SDLK_UP:
                {
                    m_buttons[BUTTON_W] = false;
                    break;
                }

                case SDLK_s: case SDLK_DOWN:
                {
                    m_buttons[BUTTON_S] = false;
                    break;
                }

                case SDLK_a: case SDLK_LEFT:
                {
                    m_buttons[BUTTON_A] = false;
                    break;
                }

                case SDLK_d: case SDLK_RIGHT:
                {
                    m_buttons[BUTTON_D] = false;
                    break;
                }

                default:
                    break;

            }
            break;
        }


return true;
}

I then implemented a method to test just when the button is initially pressed. However when I tried this method to apply impulse to the player, I had to continually hammer the button for the player to move any great distance.

bool CInput::WasButtonPressed( Buttons button )
{
if(m_buttons[button] && m_buttonsDown[button])
{
    return true;
}

return false;
}

I know I need to have a method which lets me know that a keyboard button is being held, but to not apply impulse for every frame. I’m just short of the answer unfortunately.

Also, this is the method I’m using to update the player’s position. It’s also called every frame in my update loop.

b2Vec2 velocity = m_Box2DBody->GetLinearVelocity();
float desiredVelocity = 0.f;

if( INPUT.WasButtonPressed( CInput::BUTTON_A ))
    desiredVelocity = b2Max( velocity.x - 0.05f, -1.f );

if( INPUT.WasButtonPressed( CInput::BUTTON_D ))
    desiredVelocity = b2Min( velocity.x + 0.05f, 1.f );

if( INPUT.WasButtonPressed( CInput::BUTTON_W ))
{
    float mass = m_Box2DBody->GetMass();
    float jumpImpulse = mass * 1.f;
    m_Box2DBody->ApplyLinearImpulse( b2Vec2( 0.f, jumpImpulse ), m_Box2DBody->GetWorldCenter());
}

float changeInVelocity = desiredVelocity - velocity.x;
float mass = m_Box2DBody->GetMass();
float impulse = mass * changeInVelocity;

m_Box2DBody->ApplyLinearImpulse( b2Vec2( impulse, 0.f ), m_Box2DBody->GetWorldCenter());
}

I’m not entirely sure if I need to find a better method to gather input, maybe a better method to fix my timestep, or maybe even the way I’m moving my character. For a better demonstration I’ve recorded the current behaviour of my game below. As you can see, it’s very juddery and quick movement. I’ve struggled with this for weeks now, and I think I’ve got myself so worked up on the problem I can’t see the forest for the trees. Any help on addressing the issue of input and how to process it would be greatly appreciated. I know I need to have a method which lets me know that a keyboard button is being held, but to not apply impulse for every frame. I’m just short of the answer unfortunately.

View My Video

OK… so after playing around with a couple of things, I decided to change the way I regulate framerate. I’ve tried a couple of methods such as can be found here or ultimately limit the timestep without using delays. None have worked. So I implemented the method as demonstrated here, and thankfully it has sorted out my crazy physics problem. However, I’ve always struggled with the concept of limiting timesteps, particularly with using SDL_Delay. Is this an acceptable method or is it frowned upon? I’ve read so many articles which argue that we shouldn’t be delaying the program but limiting it’s update and it’s a topic which has confused me. So… although using SDL_Delay has achieved what I was after and solved my problem, is this actually the right way to do it?

I don’t see any problems using SDL delay it would be the same as delaying the loop with if statement for x amount of seconds. heres another thread about timers http://forums.libsdl.org/viewtopic.php?t=8142

I think the only thing that should be on a timer is the step function. ex: world->Step(ftime, 10, 10); where time is my updated time, should be called in the main loop at all time and that should regulate your game speed according to your time step implementation. Well it will update anything you add to you box2d world> OK… so after playing around with a couple of things, I decided to change the way I regulate framerate. I’ve tried a couple of methods such as can be found here or ultimately limit the timestep without using delays. None have worked. So I implemented the method as demonstrated here, and thankfully it has sorted out my crazy physics problem. However, I’ve always struggled with the concept of limiting timesteps, particularly with using SDL_Delay. Is this an acceptable method or is it frowned upon? I’ve read so many articles which argue that we shouldn’t be delaying the program but limiting it’s update and it’s a topic which has confused me. So… although using SDL_Delay has achieved what I was after and solved my problem, is this actually the right way to do it?