How to fix Jittery Side Scrolling with Box2D

I have dynamically generated terrain that scrolls to the side that I made using this tutorial:

However, as the terrain scrolls to the left it occasionally jumps and is just not smooth at all. The performance is running at 55-60 fps and 4 draw calls, so I’m confused as to what the issue could be.

My update method looks like this:

void GameScreen::update(float dt)
{
static double UPDATE_INTERVAL = 1.0f / 60.0f;
static double MAX_CYCLES_PER_FRAME = 5;
static double timeAccumulator = 0;

timeAccumulator += dt;
if (timeAccumulator > (MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL))
{
	timeAccumulator = UPDATE_INTERVAL;
}

int32 velocityIterations = 3;
int32 positionIterations = 2;
while (timeAccumulator >= UPDATE_INTERVAL)
{
	timeAccumulator -= UPDATE_INTERVAL;
	_world->Step(UPDATE_INTERVAL, velocityIterations, positionIterations);
	_world->ClearForces();
}

    float offset = player->getPosition().x;
terrain->setOffsetX(offset);

}

Where the terrain is scrolled by the offset. Anyone have any suggestions? I’ll provide more information if needed.

The problem is that, for the most frames, the world update only runs once. The remainder keeps getting added to the accumulator until the value in the accumulator is greater than or equal to 2/60. In that case the world update runs twice and you get the occasional jumps, because your world is one frame ahead of the view. You can try this hypothesis by having a console output every time the world update runs twice.

A possible fix is to make the update interval much shorter, so the world won’t get ahead by 1/60 seconds.

In my opinion, the problem is that you do not use the interpolation. Have a look at this article http://www.unagames.com/blog/daniele/2010/06/fixed-time-step-implementation-box2d

I tried lowering the update interval and it didnt do much. I’m looking at the interpolation implementation that dotsquid posted and it all makes sense except I’m confused what the PhysicsComponent in the code is exactly.

variable time step will mess up your physics which will result to this jittery effect.
always implement a fixed time step.

I implemented interpolation and changed the update code. The jitter is even worse. Here’s what my code looks like:

static double UPDATE_INTERVAL = 1.0f / 60.0f;
static double MAX_CYCLES_PER_FRAME = 5;
static double timeAccumulator = 0;
static double timeAccumulatorRatio = 0;

void GameScreen::smoothStates()
{
	const float oneMinusRatio = 1.0 - timeAccumulatorRatio;

	for (b2Body* b = _world->GetBodyList(); b != NULL; b = b->GetNext())
	{
		if (b->GetUserData() == "Terrain")
		{
			terrain->setPositionX(timeAccumulatorRatio * b->GetPosition().x + (oneMinusRatio * prevTerrainX));
		}
	}
}

void GameScreen::resetStates()
{
	for (b2Body* b = _world->GetBodyList(); b != NULL; b = b->GetNext())
	{
		if (b->GetUserData() == "Terrain")
		{
			prevTerrainX = b->GetPosition().x;
			terrain->setPositionX(prevTerrainX);
		}
	}
}

void GameScreen::update(float dt)
{
	timeAccumulator += dt;
	const int nSteps = floor(timeAccumulator / UPDATE_INTERVAL);
	
	if (nSteps > 0)
    {
        timeAccumulator -= nSteps * UPDATE_INTERVAL;
    }

	timeAccumulatorRatio = timeAccumulator / UPDATE_INTERVAL;

	const int nStepsClamped = min(nSteps, MAX_CYCLES_PER_FRAME);

	int32 velocityIterations = 3;
	int32 positionIterations = 2;

	for (int i = 0; i < nStepsClamped; i++)
    {
        this->resetStates();
        _world->Step(UPDATE_INTERVAL, velocityIterations, positionIterations);
    }

	_world->ClearForces();
	this->smoothStates();
}

Is there something wrong in my code?

1 Like

Did you figure out how to solve this ?

For start, try using fixed timestep ( 1/60 ) and check the results.

Hi, I have this same problem, I’ve even tried everything they say but it still does not work out.

I share a video of what is happening.

Regards!

If you have a fixed timestep of 1/60 box2d and you step the world every 1/30 of a second then box2d “thinks” that 1/60 of a second went buy which is wrong. What you want to do is to calculate the actual elapsed time between two frames and step the world not once but so many times that the actual difference is very small.

Also you dont want to set positions to the bodies directly. Rather interpolate to the next position.