Search code examples
c++opengleventscamerasdl

Non instantaneous/jerky movement using SDL2 & OpenGL


I've been working on a little 3D engine trying to fix up the camera and make it less jerky. I've been using SDL for the input and while it works it's doing this thing where if I press and hold a button it will instantly move once then pause and then start moving properly making the movement feel unresponsive.

I recorded a GIF of it and while it may be slightly hard to see what's happening hopefully it'll give some idea:

gif

Moving forward and then right would be like:

w wwwwwwwwwwwwwwww a aaaaaaaaaaaaaaaaaaaaa

The important code is here but feel free to ask for more if necessary:

//Poll events
    SDL_Event event;
    while (m_EngineState != EngineState::EXIT)
    {
        m_last = m_current;
        m_current = SDL_GetPerformanceCounter();
        deltaTime = (double)((m_current - m_last) * 1000 / SDL_GetPerformanceFrequency());

        while (SDL_PollEvent(&event))
        {
            switch (event.type) {
            case SDL_QUIT:
                m_EngineState = EngineState::EXIT;
                break;

            case SDL_MOUSEMOTION:
                break;

            case SDL_KEYDOWN:
                m_Keys[event.key.keysym.sym] = true;
                break;
            case SDL_KEYUP:
                m_Keys[event.key.keysym.sym] = false;
                break;
            }
            ProcessEvents();
        }

void Engine::ProcessEvents()
{
    if (m_Keys[SDLK_w])
    {
        m_Camera->MoveForward(5.0f*(deltaTime*0.001));
    }
    if (m_Keys[SDLK_s])
    {
        m_Camera->MoveForward(-5.0f*(deltaTime*0.001));
    }
    if (m_Keys[SDLK_d])
    {
        m_Camera->MoveRight(5.0f*(deltaTime*0.001));
    }
    if (m_Keys[SDLK_a])
    {
        m_Camera->MoveRight(-5.0f*(deltaTime*0.001));
    }
}

void Camera::MoveForward(float amount)
{  
    m_pos += m_forward * amount;
}

void Camera::MoveRight(float amount)
{
    m_pos += glm::cross(m_forward, m_up) * amount;
}

Solution

  • Do not use SDL_PollEvent with the SDL_KEYDOWN and SDL_KEYUP events, it is subject to OS keyboard repeat rates. Which is great for typing, but not for camera/player controls. Use SDL_GetKeyboardState(NULL) in stead to query the current state of the keys.

    For example:

    Uint8* keystate = SDL_GetKeyboardState(NULL);
    
    if (keystate[SDL_SCANCODE_W])
    {
      m_Camera->MoveForward(5.0f*(deltaTime*0.001));
    }
    
    if (keystate[SDL_SCANCODE_S])
    {
      m_Camera->MoveForward(-5.0f*(deltaTime*0.001));
    }