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.