problems with stuttering rolling background, hope some good sammaritan helps

Basically I’m doing a basic game from scratch for fun, right now it is just a character running back and forth, jumping, parsing a heightmap and a scrolling background.

My main problem is that the background rolls very very choppy and I can’t seem to find why, so here’s how my main loop looks like:

double accumTimeMechanics = 0, accumTimeRender = 0;
    mPreviousTime = M_Timer.ticks();

    while (mIsRunning)
    {
        process_events();

        /// current and previous get raw ticks, ticks are not in any time measurement
        auto currentTime = M_Timer.ticks();
        auto elapsedTime = M_Timer.elapsed_time(mPreviousTime, currentTime);
        mPreviousTime = currentTime;

        accumTimeMechanics += elapsedTime;
        accumTimeRender += elapsedTime;

        /// Prevents tunneling. The bigger the accumulated time, the more pixels the objects move per frame, hence we need to cap right before there is
        /// a possibility of the collision system make objects pass through each other undetected. When this threshold is reached, the simulation will slow
        /// down
        if (accumTimeMechanics > MAX_MECHANICS_DELAY) {
            accumTimeMechanics = MAX_MECHANICS_DELAY;
        }

        /// if accumulated time passed the minimum delay, it is time to update Mechanics
        if (accumTimeMechanics > MIN_MECHANICS_DELAY) {
            process_inputs(MIN_MECHANICS_DELAY);
            update_mechanics(MIN_MECHANICS_DELAY);
            play_sounds();

            accumTimeMechanics -= MIN_MECHANICS_DELAY;
        }

        /// the renderer delay by default is half the Mechanics delay (giving 120 FPS), but it can be modified if added to a future "settings" in the game menu
        if (accumTimeRender > MIN_RENDER_DELAY) {
            update_graphics(MIN_RENDER_DELAY);
            accumTimeRender -= MIN_RENDER_DELAY;
        }

        finish_loop();
    }

The clock I use is SDL2’s, and I check to see if my system supports the correct resolution elsewhere.

The player will get movement proportional to the timestep like this:

process_inputs(const double elapsedTime)
{
    ////////////////////////////////// KEYBOARD INPUT /////////////////////////////////
    auto kb = SDL_GetKeyboardState(NULL);

    GPlayer::movX = (-kb[SDL_SCANCODE_A] + kb[SDL_SCANCODE_D]) * GPlayer::speed * elapsedTime;

///
}

The scrolling background is very simply

float leftX, rightX;

    /// sum half the width because player starts at the middle of background
    auto rollingPosX = std::fmod(GPlayer::posX + GGlobals::Width*0.5, GGlobals::Width);

    leftX  = -rollingPosX;
    rightX = GGlobals::Width - rollingPosX;

    SDL_FRect leftRect   = {leftX,   0, GGlobals::Width, GGlobals::Height},
              rightRect  = {rightX,  0, GGlobals::Width, GGlobals::Height};

    draw_background(leftRect, rightRect);

So, all variables involved are doubles, with the exception of the SDL_FRect which casts it to float. But that doesn’t seem to be the problem because integers can also be used, and moving to them doesn’t change the problem.

Am I overlooking something very basic here? The background seems to jump at random, sometimes even more noticeably, like it is trembling a bit, not smooth at all.

If I pass accumulated time directly it also won’t help, because there could be fluctuations in timing anyhow.

I’m not using any multithreading, this is just the most basic possible thing.

I can simplify that loop to get only on global accumTime and render along with the mechanics and other updates, but that also doesn’t help at all.

Hope someone could help shed some light on possible issues.

Thanks folks!

Can I see how you render the character? And what does GPlayer look like? MIN_RENDER_DELAY is unused when you draw the background so it can be the cause, also you’re capping the accumTimeMechanics but not the accumTimeRender?

The renderer time is always smaller than mechanics one, so it doesn’t need capping. Worst case scenario is rendering slowing down to be called together with mechanics.

Character is not the case of the bad background stutter, because if I comment out the player render call the problem persists.

MIN_RENDER_DELAY is unused when you draw the background

Not sure why you think so. That draw call enters when the accumTimeRender is above MIN_RENDER_DELAY

Yes, but you pass MIN_RENDER_DELAY as an argument for update_graphics() right? How do you use it inside update_graphics()? I can’t see it being used when you calculate the rollingPosx.

It is because for that part you don’t need, you only need to know the position of the player to roll the background.

I’ll show you more code but it will get more convoluted and away from the original problem probably.

In update_graphics I simply call

void GAppMain::update_graphics(const double elapsedTime)
{
    update_animations(elapsedTime);
    render(elapsedTime);
}

animations is not pertaining to this problem as scrolling background is not animated.

render() unfolds like this:

void GAppMain::render(const double accumTimeRender)
{
    SDL_RenderClear(GGlobals::Renderer);

    auto sceneTex = M_Cam.get_scene_texture(accumTimeRender, mShowInfoPanel);

    SDL_RenderCopyF(GGlobals::Renderer, sceneTex, NULL, NULL);
    SDL_RenderPresent(GGlobals::Renderer);
}

get_scene_texture() then is this

SDL_Texture* GCamera::get_scene_texture(const double accumTimeRender, const bool showInfoPanel)
{
    SDL_SetRenderTarget(GGlobals::Renderer, mSceneTex);

    auto playerTex = GPlayer::mActiveAnimation->get_animation_frame();

    set_camera(playerTex);

    if (showInfoPanel) {
        draw_InfoPanel(accumTimeRender);
    }

    SDL_SetRenderTarget(GGlobals::Renderer, NULL);

    return mSceneTex;
}

Maybe that’s not the best way of doing things, but this is simply a big blank texture that you draw the other stuff to it (observing order), and that’s it. It is very simple, not sure there is a catch there but maybe you spot some things I messed up!

I think the code above is fine.

Assuming that GPlayer::movX is used like
GPlayer::posX += GPlayer::movX,

I think what you should do to get a smoother rollingPosX is

auto t = 0.5; since render delay is half by default of the mechanics delay
auto prev_x = lerp(GPlayer::posX - GPlayer::movX, GPlayer::posX, t);
rollingPosX = std::fmod(prev_x + GGlobals::Width * 0.5, GGlobals::Width);

I can only guess though.

Lerp is not a bad idea, but I think fundamentally it doesn’t work here because all movX are exactly the same, since I pass MIN_MECHANICS_DELAY which is constant, and player speed is also a constant, and product of both is movX;

Why I do that? because then the problem is transferred to that of smoothing out spikes in the time loop itself, but I tested doing that with a lot of enqueued elapsed times, moving averages etc, and it didn’t help.

Maybe worth thinking on something like above but it doesn’t seem to be the problem neither, I display the accumTimes in infopanel and they do not seem jump significantly judging by eye balling them.

This is just a fundamentally nasty problem but I still suspect it has to be something to do with messed up coordinates or something in SDL, or maybe some trick blurring consecutive textures?

Anyway thank you for you interest and inputs. If you don’t experience this problem in your simulation, please post some code example because that will help.