Do not understand box2d Step() and update interval when using cocos2d-x?

Hi!

When you simulate the physics in box2d, you are using Step().

But in the user manual it is used in a for loop like this and not as something that will be running all the time:

float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
///////////////////////////////////////
for (int32 i = 0; i < 60; ++i)
{
world.Step(timeStep, velocityIterations, positionIterations);
b2Vec2 position = body->GetPosition();
float32 angle = body->GetAngle();
printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
}
Here, the float32 timeStep is always the same.

But when you are doing it in a scheduled updater function i see some do it like this:

void Level::update(float dt)
{
  // get current time double
  currentTime = getCurrentTimeInSeconds();
  if (!lastTickTime)
    lastTickTime = currentTime;
  
  // determine the amount of time elapsed since our last update
  double frameTime = currentTime - lastTickTime;
  accumulator += frameTime;
  
  // update the world with the same seconds per update
  while (accumulator > kSecondsPerUpdate)
  {
    accumulator -= kSecondsPerUpdate;
    
    // perform a single step of the physics simulation
    world->Step(kSecondsPerUpdate, 8, 1);
  }
  lastTickTime = currentTime;
}

And this

void HelloWorld::update(float dt){
   int positionIterations = 10;  
   int velocityIterations = 10;

   deltaTime = dt;
   world->Step(dt, velocityIterations, positionIterations);  

    world->ClearForces();
    world->DrawDebugData();        
}   

In both examples they are running the Step function with an interval that is updating/changing all the time and isn’t dt getting bigger and bigger all the time or at least changing.

So my question is - Why are they not using a constant value in the last two examples when the one from the user manual is and why? When do i have to do what??

Really hope you get me. :slight_smile:

Thank you!

3 Likes

The user manual version seems to be a simple example of simulating only 1 second of physics time.

The accumulator example is the standard approach to simulate physics at a fixed interval within a variable frame interval. I.e. Each frame we run all the physics steps that would have happened. e.g. if Frame interval = 0.2s and Physics interval = 0.1s, step will be called twice each frame with dt = 0.1.

The final example looks incorrect to me, assuming HelloWorld::update() is called by the scheduler it will have a variable dt, making the box2d simulation unstable.

Thank you! I will try to figure that this out tomorrow :smile:

I’ll give you the bottom line right now, always run physics simulations with a fixed timestep

timeStep = 1.0f/60.0f;

You will get a lot more stable physics simulations. It’s a really really really bad idea to use the delta timestep in the physics simulation.

1 Like

Can you expand on that? I’ve used the timestep quite happily for ages!

@Maxxx
Here’s some good reads on the topic:

http://gafferongames.com/game-physics/fix-your-timestep/
http://gamedev.stackexchange.com/questions/1589/when-should-i-use-a-fixed-or-variable-time-step

The glaring issue with using a fixed time step is desynchronization with the frame interval, leading to objects appearing jittery at runtime. This is usually solved by interpolating to or extrapolating physics state to derive render state.

Unity examples:
http://docs.unity3d.com/ScriptReference/Rigidbody-interpolation.html
http://docs.unity3d.com/ScriptReference/RigidbodyInterpolation.Extrapolate.html
http://answers.unity3d.com/questions/767134/physics-what-is-interpolate-extrapolate-discrete-c.html

How do you know if that setup of the frame interval and physics interval is good?

And i saw a tutorial where the function was scheduled and used as this accumulator way like this:

const float kUpdateInterval = 1.0f / 60.0f;
const double kSecondsPerUpdate = 0.1;

this->schedule(schedule_selector(Level::update), kUpdateInterval);

What the 1/60 as interval
And in the update function:

 world->Step(kSecondsPerUpdate, 8, 1);

And kSecondsPerUpdate is bigger than kUpdateInterval…Should’t it have been the opposite?
I still do not quite get this I think :frowning:
Thank you so much Again!

The tutorial you mention is taking advantage of the fact that cocos2d-x’s scheduler does the accumulation internally. By passing a non-zero interval to schedule() you can have the scheduler use an accumulator to call the function as few or as many times as necessary to keep in sync with the frame interval.

CCScheduler.cpp

// if _interval == 0, should trigger once every frame
float interval = (_interval > 0) ? _interval : _elapsed;
while (_elapsed >= interval)
{
    trigger(interval);
    _elapsed -= interval;
    _timesExecuted += 1;

    if (!_runForever && _timesExecuted > _repeat)
    {
        cancel();
        break;
    }

    if (_elapsed <= 0.f)
    {
        break;
    }
}

Lets assume frame interval is 1/60s

  • If the physics interval is 1/30s, step() will be called twice in every frame
  • If the physics interval is 1/20s, step() will be called three times over two frames (once in the first and twice in the second)
  • If the physics interval is 1s, step will be called once every 60 frames

Hope this helps

Wow, thank you so much!

Uhh one more thing!
I did the following:
Added variables for intervals

const float kUpdateInterval = 1.0f / 60.0f;
const double kSecondsPerUpdate = 0.1;

Started scheduling the update function with the interval of kUpdateInterval

	this->schedule(schedule_selector(HelloWorld::update), kUpdateInterval);

Then here is the definition of update(float dt)

void HelloWorld::update(float dt)
{
	// get current time double
	currentTime = getCurrentTimeInSeconds();
	if (!lastTickTime)
		lastTickTime = currentTime;

	// determine the amount of time elapsed since our last update
	double frameTime = currentTime - lastTickTime;
	accumulator += frameTime;

	// update the world with the same seconds per update
	while (accumulator > kSecondsPerUpdate)
	{
		accumulator -= kSecondsPerUpdate;

		// perform a single step of the physics simulation
		world->Step(kSecondsPerUpdate, 1, 22);
	}
	lastTickTime = currentTime;
}

THEN I have an issue - It runs very laggy as you can see in this short video:
https://nichlaspro-gmail.tinytake.com/sf/NjQzNTUxXzMxMzAwNTM

The red box is using the built-in physics and runs very smooth. I want the effect on the box2d affected objects. how?
What can I do to make this laggy box run as smooth as the red box?

Update:
So I thought changing the physics interval value kSecondsPerUpdate to a smaller value but that just ended up in the box falling down faster but still as laggy as before… :frowning:
Thank you.

First. your iteration variables seem a bit off:

http://www.box2d.org/manual.html
“The suggested iteration count for Box2D is 8 for velocity and 3 for position.”

world->Step(kSecondsPerUpdate, 8, 3);

Second, you don’t need to explicitly define a frame interval, you should use an interval of 0 with the scheduler, i.e. called once per rendered frame. (you can Node::scheduleUpdate() to simplify this).

Thirdly, because of the desynchronization between frame and physics intervals, in order to achieve a smooth visualisation you need to interpolate or extrapolate physics space to render space every frame. I posted about this before but here it is again :smiley:

The glaring issue with using a fixed time step is desynchronization with the frame interval, leading to objects appearing jittery at runtime. This is usually solved by interpolating to or extrapolating physics state to derive render state.

Unity examples:
http://docs.unity3d.com/ScriptReference/Rigidbody-interpolation.html
http://docs.unity3d.com/ScriptReference/RigidbodyInterpolation.Extrapolate.html1
http://answers.unity3d.com/questions/767134/physics-what-is-interpolate-extrapolate-discrete-c.html

1 Like