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??
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.
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.
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
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
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;
}
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…
Thank you.
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
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.