Fixed time-step implementation in Box2D

Daniele's picture

If you are interested in how to implement Glenn Fiedler's "fix your timestep" technique, here you will find a brief C++ implementation for Box2D. The technique is needed to keep stable the numerical integration performed by the physics simulation while running the video game with a variable frame-rate.

As Glenn's article has all the details, read it to understand because this technique is useful and because this solution works.

The implementation makes these assumptions:

  • forces are applied for the whole frame, and are preserved for each sub-step (i.e., multiple calls to b2World::Step());
  • to implement low-level physics behaviors (like buoyancy, wind drag, etc.) for which numerical stability must be guaranteed, Physics Controllers are used: special objects that are executed at each sub-step applying impulses to controlled objects;
  • at each sub-step some game logic could be called (e.g. to manage collisions).

Initialization

const float FIXED_TIMESTEP = 1.f / 60.f;
 
 
 
PhysicsSystem::PhysicsSystem ()
	: fixedTimestepAccumulator_ (0),
	  fixedTimestepAccumulatorRatio_ (0)
{
	// ...
 
	world_ = new b2World (gravity, doSleep);
	world_->SetAutoClearForces (false);
 
	// ...
}

In PhysicsSystem's constructor we build the b2World instance. The call to SetAutoClearForces() method inhibits the automatic reset of forces when calling b2World::Step(). We also initialize two auxiliary member variables that will be used to manage the fixed time-step algorithm: fixedTimestepAccumulator_ will contain the elapsed time still left un-processed, fixedTimestepAccumulatorRatio_ is the previous value scaled in the range [0, 1) (it will be used to smooth movements).

Fixed time-step update

The update method uses the following parameters:

  • FIXED_TIMESTEP: the fixed time-step value that will be always passed to b2World::Step().
  • MAX_STEPS: an upper-bound value used to avoid a "spiral of death": the game slows-down, the physics system must processes a longer "frame" performing multiple sub-steps, but this requires more time that will slows-down further the game, and so on until the game will become unresponsive. If the game will need more sub-steps than MAX_STEPS, it will simply progress slowly until the scene becomes simpler and the normal behavior will be restored.

void PhysicsSystem::update (float dt)
{
	// Maximum number of steps, to avoid degrading to an halt.
	const int MAX_STEPS = 5;
 
	fixedTimestepAccumulator_ += dt;
	const int nSteps = static_cast<int> (
		std::floor (fixedTimestepAccumulator_ / FIXED_TIMESTEP)
	);
	// To avoid rounding errors, touches fixedTimestepAccumulator_ only
	// if needed.
	if (nSteps > 0)
	{
		fixedTimestepAccumulator_ -= nSteps * FIXED_TIMESTEP;
	}
 
	assert (
		"Accumulator must have a value lesser than the fixed time step" &&
		fixedTimestepAccumulator_ < FIXED_TIMESTEP + FLT_EPSILON
	);
	fixedTimestepAccumulatorRatio_ = fixedTimestepAccumulator_ / FIXED_TIMESTEP;
 
	// This is similar to clamp "dt":
	//	dt = std::min (dt, MAX_STEPS * FIXED_TIMESTEP)
	// but it allows above calculations of fixedTimestepAccumulator_ and
	// fixedTimestepAccumulatorRatio_ to remain unchanged.
	const int nStepsClamped = std::min (nSteps, MAX_STEPS);
	for (int i = 0; i < nStepsClamped; ++ i)
	{
		// In singleStep_() the CollisionManager could fire custom
		// callbacks that uses the smoothed states. So we must be sure
		// to reset them correctly before firing the callbacks.
		resetSmoothStates_ ();
		singleStep_ (FIXED_TIMESTEP);
	}
 
	world_->ClearForces ();
 
	// We "smooth" positions and orientations using
	// fixedTimestepAccumulatorRatio_ (alpha).
	smoothStates_ ();
}

The algorithm is simple:

  1. using the requested time to consume (input parameter dt) and the previous, unprocessed accumulated time (fixedTimestepAccumulator_), computes the natural number of steps, each of length FIXED_TIMESTEP, that must be simulated; the remainder is stored back in the accumulator (fixedTimestepAccumulator_).
  2. computes the fraction of unprocessed time, respect to FIXED_TIMESTEP, and stores it into fixedTimestepAccumulatorRatio_.
  3. simulates the required number of physics steps.
  4. calls b2World::ClearForces() method to reset applied forces.
  5. smooths positions and orientations of physics objects.

Each single step activates the Physics Controllers, calls b2World::Step() and processes collisions:

void PhysicsSystem::singleStep_ (float dt)
{
	// ...
 
	updateControllers_ (dt);
	world_->Step (dt, velocityIterations, positionIterations);
	consumeContacts_ ();
 
	// ...
}

resetSmoothStates_() and smoothStates_() methods depend on the chosen smoothing algorithm, and are described below.

Smoothing

Smoothing is very important to avoid visual artifacts: due to the variable frame rate, fast moving objects will "flicker" on screen (each time the accumulator is full, additional steps will be performed moving objects apparently "faster"); if running in "slow-motion", objects position will "jump" each time the accumulated virtual time exceeds FIXED_TIMESTEP (as multiple frames are executed without any physics computations).

You can choose between two implementations:

  • interpolation: the smoothed state is computed from the last two known states:
    	state = currentState * alpha + previousState * (1-alpha)

    It's accurate because it always smooths between two computed states; but lags one sub-step (i.e. one FIXED_TIMESTEP; because alpha < 1, currentState is never returned), needs double buffering of smoothed states, "events" (if not cached) will be "anticipated" of one sub-step (they are triggered when computing currentState).
  • extrapolation: the smoothed state is predicted using the last known state and its first derivative:
    	state = currentState + currentStateDerivative * alpha

    It's very efficient to compute; but it will deviate from the real "next" state producing "jumps" when the new state becomes the active one.

You can see the two main problems (interpolation lag and extrapolation error) in the following figure, that shows how an object position is smoothed with the two methods.

Interpolation and extrapolation of features.

In the following, PhysicsComponent is a wrapper class for b2Body objects; used to decouple the game code from all the details of this article.

Extrapolation

I will start with extrapolation because its implementation is easier.

Note that extrapolation is the exact same thing that Dead Reckoning (read also Jesse Aronson's article "Dead Reckoning: Latency Hiding for Networked Games"), and it can become a very complex argument. But if you need a better solution, as we play with very little latency, you can simply use the interpolation technique (see later).

For each smoothed state, PhysicsComponent has one member variable: for the position is used smoothedPosition_, for the orientation is used smoothedAngle_.

void PhysicsSystem::smoothStates_ ()
{
	const float dt = fixedTimestepAccumulatorRatio_ * FIXED_TIMESTEP;
 
	for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
	{
		if (b->GetType () == b2_staticBody)
		{
			continue;
		}
 
		PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
		c.smoothedPosition_ = b->GetPosition () + dt * b->GetLinearVelocity ();
		c.smoothedAngle_ = b->GetAngle () + dt * b->GetAngularVelocity ();
	}
}
 
 
 
void PhysicsSystem::resetSmoothStates_ ()
{
	for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
	{
		if (b->GetType () == b2_staticBody)
		{
			continue;
		}
 
		PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
		c.smoothedPosition_ = b->GetPosition ();
		c.smoothedAngle_ = b->GetAngle ();
	}
}

Interpolation

Interpolation should be the preferred smoothing implementation.

For each smoothed state, PhysicsComponent has one further member variable to store the previous known state: for the position is used previousPosition_, for the orientation is used previousAngle_.

void PhysicsSystem::smoothStates_ ()
{
	const float oneMinusRatio = 1.f - fixedTimestepAccumulatorRatio_;
 
	for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
	{
		if (b->GetType () == b2_staticBody)
		{
			continue;
		}
 
		PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
		c.smoothedPosition_ =
			fixedTimestepAccumulatorRatio_ * b->GetPosition () +
			oneMinusRatio * c.previousPosition_;
		c.smoothedAngle_ =
			fixedTimestepAccumulatorRatio_ * b->GetAngle () +
			oneMinusRatio * c.previousAngle_;
	}
}
 
 
 
void PhysicsSystem::resetSmoothStates_ ()
{
	for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
	{
		if (b->GetType () == b2_staticBody)
		{
			continue;
		}
 
		PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
		c.smoothedPosition_ = c.previousPosition_ = b->GetPosition ();
		c.smoothedAngle_ = c.previousAngle_ = b->GetAngle ();
	}
}

Comments

Hi,

Good stuff! I posted this on the Cocos2D forums also.

Can I ask how I need to manage the removal of objects rom collisions if I am using this method? I currently just call world->Step and then remove anything which has collided immediately after. Does this method adjust this at all?

Also, you have a method called updateControllers, what does this do?

Finally...is there a downloadable project with this implementation? For example, the basic Box2D Cocos2D template project with this implemented would be awesome.

Regards

S

Daniele's picture

Hi Stephen,

Stephen Mackenzie wrote:

Can I ask how I need to manage the removal of objects rom collisions if I am using this method? I currently just call world->Step and then remove anything which has collided immediately after. Does this method adjust this at all?

It works the same way, the call to consumeContacts_() in PhysicsSystem::singleStep_() processes all contacts and, if needed, remove objects. Depending on how your engine works, an alternative could be to disable them and remove them after PhysicsSystem::update (); but I think this could cause inconsistencies on objects state.

Stephen Mackenzie wrote:

Also, you have a method called updateControllers, what does this do?

I attach special physics behaviors (i.e. little physics algorithms, as e.g. buoyancy) to objects. A PhysicsController is a simple interface with a pure virtual update() method. Concrete classes implement that method and their instances are associated to the physics objects on which they must apply the computed impulses. updateControllers() simply call all registered PhysicsController instances. This helps a lot to separate the physics behavior from the game logic. E.g. in Tapsteroids I've implemented the steering behavior used to pilot the missiles to the target using a PhysicsController; then I simply attach an instance of this subclass to the "missile" object and it will intercept the specified target (you can read some details here: http://www.cocos2d-iphone.org/forum/topic/8706).

Stephen Mackenzie wrote:

Finally...is there a downloadable project with this implementation? For example, the basic Box2D Cocos2D template project with this implemented would be awesome.

I don't use templates, so there is no one. But as the implementation is quite intrusive (e.g. you need to wrap Box2D objects with a custom class, PhysicsComponent) I would not recommend to include it as a standard Cocos2D template (unless people want it...). Would be far better to propose to Erin Catto to include native support for this feature into Box2D, this would be a definitive solution.

Regards,
Daniele.

Hi,

Thanks for this. Can I ask how the wrapping of b2Bodies inside PhysicsComponents is managed? i.e are you somehow storing the PhysicsComponent in the b2Body data structure (I assume not as this is where I store my Cocos nodes?). Is there a factory method for creating b2Bodies wrapped in a physicscomponent which allows the previous state to be stored?

Any sample code you can provide on how to wrap the b2Bodies in these components would be greatly appreciated, as this seems the more complex piece to refactor in.

Regards

Stephen

Daniele's picture

This is a very complicated argument, with a lot of code behind it.

My engine is based on an Entity System design, it means that everything in the game is an "entity", and an entity is like a container of "components"; each type of component is managed by an independent "system" (from which the names PhysicsSystem and PhysicsComponent).

So I've a GraphicsComponent that encapsulates a CCNode, and a PhysicsComponent that encapsulates a b2Body. When a GraphicsComponent have to be updated, it reads the position/orientation from the PhysicsComponent associated to the same parent entity.

So, I've factory methods that build the b2Body objects needed by Tapsteroids (until I will be able to move to a full data oriented architecture) and return a PhysicsComponent instance. The b2Body object is passed to the PhysicsComponent's constructor; the PhysicsComponent takes ownership of the b2Body object and the b2Body object stores, in its "user data" field, a pointer that refers back to the associated PhysicsComponent. This allows me to move forward and backward between the two objects. Each component can then accesses its parent entity to retrieve other components if needed (e.g. the GraphicsComponent). In reality my code is more complicate, because there is also the PhysicsSystem and other stuff...

All the game code uses only the interface exposed by PhysicsComponent (e.g. to retrieve the position or velocity of an entity), nowhere (outside the PhysicsSystem, PhysicsComponent and factory methods) there is direct access to the underlying b2Body object.

As you can understand, all this requires a radical shift in how your code is developed, and it's too low-level to be able to share some useful, re-usable sample code (in fact I've excluded all this "details" from the post).

But if you are interested in the Entity System argument (waiting for a new blog post ;) ), I can share some useful links:

http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-...
http://garage.gaspowered.com/?q=su_301
Archives of Sweng-GameDev mailing list (http://lists.midnightryder.com/listinfo.cgi/sweng-gamedev-midnightryder.com)

Regards,
Daniele

Hi,

Thanks for the info. If we wanted to implement the fixed time step, but didnt want to move to a full entity system, we just need a way for a b2Body to track its previous position, velocity etc from its last time step, so we could perhaps even subclass b2Body, or create a simple wrapper?

Regards

Stephen

Daniele's picture

Hi Stephen,

sub-classing don't works with current Box2D implementation as b2Body class misses the virtual destructor. A simpler solution is to rely on b2Body's "user data" field: instead of storing there the associated CCNode, use an intermediate structure containing both the cached physics state and the CCNode.

Daniele

Thanks, or you could just subclass CCSprite etc. CCPhysicsSprite and keep the last physics state in each update

Hi,

Taking your advice I created a stuct (bear in mind I am not a C++ programmer...and barely an Obj-C one). I took the basic Cocos2D sample for Box2D (the falling blocks).

struct PhysicsComponent  {
	float32 previousAngle;
	float32 smoothedAngle;
	b2Vec2 previousPosition;
	b2Vec2 smoothedPosition;
	CCNode* physicsNode;
};

When I create a box2D body and sprite in the demo, I am creating a PhysicsComponent struct and adding it to the body userData, together with the CCSprite.

-(void) addNewSpriteWithCoords:(CGPoint)p
{
	CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);
	CCSpriteSheet *sheet = (CCSpriteSheet*) [self getChildByTag:kTagSpriteSheet];
 
	//We have a 64x64 sprite sheet with 4 different 32x32 images.  The following code is
	//just randomly picking one of the images
	int idx = (CCRANDOM_0_1() > .5 ? 0:1);
	int idy = (CCRANDOM_0_1() > .5 ? 0:1);
	CCSprite *sprite = [CCSprite spriteWithSpriteSheet:sheet rect:CGRectMake(32 * idx,32 * idy,32,32)];
	[sheet addChild:sprite];
 
	sprite.position = ccp( p.x, p.y);
 
	// Define the dynamic body.
	//Set up a 1m squared box in the physics world
	b2BodyDef bodyDef;
	bodyDef.type = b2_dynamicBody;
 
	bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
 
	// wrap everything up into a struct
	PhysicsComponent *physicsTrack = new PhysicsComponent();
	physicsTrack->physicsNode = sprite;
	physicsTrack->previousAngle = bodyDef.angle;
	physicsTrack->previousPosition = bodyDef.position;
	physicsTrack->smoothedAngle = bodyDef.angle;
	physicsTrack->smoothedPosition = bodyDef.position;
	bodyDef.userData = physicsTrack;
 
 
	b2Body *body = world->CreateBody(&bodyDef);
 
 
 
	// Define another box shape for our dynamic body.
	b2PolygonShape dynamicBox;
	dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
 
	// Define the dynamic body fixture.
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &dynamicBox;	
	fixtureDef.density = 1.0f;
	fixtureDef.friction = 0.3f;
 
	body->CreateFixture(&fixtureDef);
 
 
 
}

I changed smoothStates and resetSmoothStates to use this new struct:

void PhysicsSystem::smoothStates_ ()
{
	const float oneMinusRatio = 1.f - fixedTimestepAccumulatorRatio_;
 
	for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
	{
		if (b->GetType () == b2_staticBody)
		{
			continue;
		}
 
		//PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
		PhysicsComponent *c   = (PhysicsComponent*) b->GetUserData();
		c->smoothedPosition =
		fixedTimestepAccumulatorRatio_ * b->GetPosition () +
		oneMinusRatio * c->previousPosition;
		c->smoothedAngle =
		fixedTimestepAccumulatorRatio_ * b->GetAngle () +
		oneMinusRatio * c->previousAngle;
	}
}
 
 
 
void PhysicsSystem::resetSmoothStates_ ()
{
	for (b2Body * b = world_->GetBodyList (); b != NULL; b = b->GetNext ())
	{
		if (b->GetType () == b2_staticBody)
		{
			continue;
		}
 
		//PhysicsComponent & c = PhysicsComponent::b2BodyToPhysicsComponent (* b);
		PhysicsComponent *c   = (PhysicsComponent*) b->GetUserData();
		c->smoothedPosition = c->previousPosition = b->GetPosition ();
		c->smoothedAngle = c->previousAngle = b->GetAngle ();
	}
}

And in my main game tick I am calling singleStep and am reorienting the sprite:

-(void) tick: (ccTime) dt
{
	//It is recommended that a fixed time step is used with Box2D for stability
	//of the simulation, however, we are using a variable time step here.
	//You need to make an informed choice, the following URL is useful
	//http://gafferongames.com/game-physics/fix-your-timestep/
 
 
	// Instruct the world to perform a single step of simulation. It is
	// generally best to keep the time step and iterations fixed.
 
 
	physics->singleStep_(dt);
 
	//Iterate over the bodies in the physics world
	for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
	{
 
		if (b->GetUserData() != NULL) {
 
			//Synchronize the AtlasSprites position and rotation with the corresponding body
			PhysicsComponent *physicsComponent = (PhysicsComponent*)b->GetUserData();
			CCSprite *myActor = (CCSprite*) physicsComponent->physicsNode;
			myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
			myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
		}	
	}
}

It all seems to work...my only concerns are now more related to memory management in terms of how/when do I delete my structs I have created on the heap? How do I coordinate this removal with the removal of the CCSprite which needs to be removed from the main stage, at the same time the struct which has a reference to it is removed.

Any advice appreciated.

Regards

Stephen

sorry I am calling physics->update(dt) not physics->singleStep

Hi,

I subclassed CCSprite and created CCPhysicsSprite, and added properties for the previous and smoothed angles and positions. It works great thanks.

As a test I reduced the animation interval to 1/10 second, and in the original demo - there is quite a lot of penetration in the blocks before collision kicks in, but in the fixed timestep implementation - with a physics interval of 1/60 but an animation interval of 1/10...the penetration of the blocks seems much reduced.

Thanks guys and gals

Regards

i

I have uploaded some videos:

Box2D Cocos2D demo with no fixed time step implementation
http://www.youtube.com/watch?v=6W31aKk84q0

Box2D Cocos2D demo with your fixed time step implementation
http://www.youtube.com/watch?v=EZcgkqEyErQ

Daniele's picture

Hi Stephen,

sorry for my late reply, I've read your comments today. I'm very glad that you have solved your problems and that now you have a nice fixed-timestep implementation! :)

Your videos look great, they show very well the importance of having a well implemented fixed-time step. If you agree, I would like to embed them in the article (of course with credits).

Hi,

Sure, don't worry about credits, you did the hard bit. Hope what I did was a good test, not sure if having a 1/10th second animation interval makes sense with a 1/60th fixed timestep, but it seems to demonstrate quite a significant difference in Box2D behaviour.

I did post a question on Box2D forums, and Eric said he does support fixed time step implementations by providing "force caching"...? This seems a different approach to the interpolation one here?

I posted my hacked classes for Cocos2D in this forum.

http://www.cocos2d-iphone.org/forum/topic/8922.

Thanks again.

Stephen

Daniele's picture

You have done a good test, simulating a big lag. The different behavior of Box2D is evident.

The "force caching" have been added to Box2D on my request, just to implement the fixed time-step algorithm; without it, an implementation wouldn't be possible. It preserves the applied forces (not impulses) between the multiple calls to b2World::Step() done by a single PhysicsSystem::update () call. In this way, if you apply a force before calling PhysicsSystem::update (), you are sure that it will be applied in all computed sub-steps, not only the first one. You can found some other info in this thread: http://www.box2d.org/forum/viewtopic.php?f=4&t=3973&start=0 .

Regards,
Daniele.

Very good article thanks.

It seems that you have one time accumulator for each sub-system. Is this right?
I was reading your posts in the Box2D forum and saw your approach to the problem.
I my small game I have one accumulator for all sub-systems (physics, logic, everything except graphics is done in fixed steps at the same rate. Only the rendering is done every frame.)
What are the advantages of having each system with its own frequency?

Thanks for your help!

Daniele's picture

Hi aeroz!

In my engine only the physics system uses an accumulator. And its value is not accessible to other systems (AI, graphics, sound, etc.).

As a general rule, the "accumulator technique" should be used only when a system can have numerical stability issues (for the physics system is its numerical integration module). If your logic system is quite complex, having an accumulator could help. But usually it's not needed.

In general, having systems running at different frequencies could help the performances: e.g., if your logic system can change behavior only each 10 frames, why running it more often?

If I missed your point, let me know.

Yes, this makes sense.
The only problem with my implementation is that in the game logic I already assume I have a fixed time step with a specific duration. So I do jobs without measuring the time because I already know that they are run every 1/60th sec. Maybe I will reconsider the design. But I also see benefits of having a fixed time step for the logic.
Thanks for sharing your implementation!

Hello!

I have used code presented here in my application that also uses SFML and I have a problem. My current scene contains only 2 rectangles that are suppose to fall down. Falling is handled by box2d.

Before using your code everything seemed to work correctly, surely better than now. After starting simulation boxes are falling extremely slow.

I have placed some tracers in algorithm's code and I have found out that dt values are very small (i.e. 0.000364s, 0.000360s, 0.000407s) and Step function is called very rarely. I think this is OK, but why this simulation is so slow?

I have initialized world with gravity v(0.0f, 10.0f) and I am passing fDeltaTime to main update function from SFML's RenderWindow::GetFrameTime() (time is returend in seconds).

Do you have any clues how to address this issue?

Daniele's picture

Hello Maciej,

Your "dt" values correspond to ~ 2700 FPS, in this case b2World::Step() should be called only 60 times a second (the value of FIXED_TIMESTEP), ie 1 time each ~ 50 calls to PhysicsSystem::update() (depends on the current frame rate). Can you verify those numbers? Otherwise there could be numerical problems with fixedTimestepAccumulator_ or (if you do smoothing) fixedTimestepAccumulatorRatio_, try to trace them (to improve quality, switch them to "double").

But I would not be confident to do comparisons with the results of running Box2D at 2700 Hz!!! I'm quite sure they are far than correct (and this is what is solved by the fixed time-step algorithm).

Let me know if you solve your problem!

OK. I have checked my code once more and I must say that I made a huge mistake that caused me a lot of unnecessary frustration:P

The source of problem.
In my application I am using SFML and Box2D. Both of these libraries are working on completely different units (SFML - pixels BOX2D - meters) and in my application it appears that 1px is 1m. That is why i thought it is working slowly.

I have compared times and position of falling box with precalculated values and everything was OK. I need to be aware of unit differences in both modules. That is all.

BTW: Did you test your code with large amount of sprites? Can you give me any feedback from your tests?
Of course I will test it in my application, but I wan to have something that can be compared to my results :D

Thank you very much for this useful piece of code :)

Daniele's picture

Glad you have solved your problem. Comparison tests with pre-calculated values are always a good thing!

Usually I'm graphics-bounded, so have never tested it in physics-bounded scenarios. What happens is that your physics will move in "slow-motion", because of MAX_STEPS. But if you are physics-bounded, your main bottleneck will always be Box2D (it made a lot more of computations!), not this abstraction layer.

Happy hacking.

Hi.
Just wondering something.
Instead of the interpolation always lagging 1 frame behind, why not just always do one extra physics step.
That way, the "current" state, is actually the future state. And interpolating between the previous state and "current" state, will give you a more accurate result.

Daniele's picture

Hi Terry,

it's an idea, but I think you would only shift the problem: you would see always an old state, and now you would also lag user inputs. Then, the proposed implementation fits well in multi-threading engines: as they use double buffers on all data structures to avoid locking, everything already lags 1 frame.

Anyway, it's an idea that could be tested.

If you're interested how to implement this in Cocos2d-x without extending CCSprite, see this post: http://plaincode.blogspot.com/2012/05/fixed-timestep-in-cocos2d-x-with-b...

Hi Daniele, thanks fot this great tutorial :)

hmm, can you explain more about PhysicsComponent ?? and what is it function, thanks

Daniele's picture

Hi Surya,

PhysicsComponent is simply a wrapper of a b2Body instance, with the addition of all the fields needed to manage and keep track of the smoothing and extrapolation features. Its function is mainly to be able to threat the resulting "b2Body+smoothing+extrapolation" stuff as a single programmable object.

As a practical and minimal example of it, you can look at the comment of Stephen Mackenzie: PhysicsComponent is a simple struct where the b2Body instance is stored into a CCNode object (it's used for the graphics). Conceptually it's the same as to store it directly into the PhysicsComponent structure.

I hope to have been helpful,
Daniele

Hello,

I have had a fixed physics timestep for sometime in my game engine, however, I have only very recently begun trying to solve the temporal aliasing issue. When I implemented this solution into my HTML5 game engine, I saw some improvement but I am still getting some stuttering. I decided to make an extremely simple demo to see if I could identify what is causing the stuttering. I moved the demo over to a JSFiddle to demonstrate:

http://jsfiddle.net/jrmorrill/V726k/

By turning on/off the "Smooth States" checkbox, you can see the benefits gained from the interpolation.

I almost feel as if it's a Box2D setting that's causing the minor glitches. I wasn't able to find the equivalent for world_->SetAutoClearForces (false); in the version of Box2D I am using.

I'm pretty sure you are interpolating in the wrong direction. The lerping should look like this:
state = previous * alpha + current * (1.0f - alpha)