Can Box2D physics be made deterministic?

I’ve been working on a very simple game which depends in part on the determinism of the physics engine.  Right now, I’m getting anything but.  In particular, if I drop a ball from the same location on to the same set of static objects multiple times (i.e., after resetting the coordinates of the dynamic object), I get different results, sometimes dramatically different if the objects are interacting near a corner.

I tried to improve the behavior by using the physics.setTimeStep call, to no avail.  There’s a rather old thread on the subject as well, but it didn’t end with anything useful.

http://developer.coronalabs.com/node/15627

Thanks in advance!

Here’s a small complete program that shows the problem.  If you click the rectangle, it will restart the simulation.  Note that if you do it a bunch of times in a row, the bounce will happen quite differently from time to time.  Any ideas how to make this work?

local physics = require( "physics" ) physics.start() physics.setGravity(0,9.8) local function make\_ball (x,y) local ball = display.newCircle(0,0,10) physics.addBody( ball, { density=0.3, friction=0, bounce=0} ) ball.isSleepingAllowed = false ball:setFillColor(1,0,0) local function on\_restart() ball.x = x ball.y = y ball:setLinearVelocity(0,0) end on\_restart() Runtime:addEventListener("level-restarted",on\_restart) end -- A button for restarting the level local function make\_restart() local restartb = display.newRect( 30, 30, 40, 40) local function restart\_level(event) if event.phase == "began" then Runtime:dispatchEvent({name="level-restarted"}) end end restartb:addEventListener( "touch" , restart\_level ) end local function setup() make\_restart() make\_ball(200,20) local rect = display.newRect(200,200,2,2) physics.addBody(rect, "static", {bounce = 0.8}) end setup()

Yeeeaaahhh no.

Sorry, but the nature of the Box2D physics engine is such that it is not possible to setup a scene in exactly the same way every time and have the same result. It sounds like a nice idea, but there are actually many benefits to the way it is and it is clearly described by the creator, Erin Catto, as a realistic 2D physics engine.

If you want a level of prediction, the closest you can really do is either have the engine running, record the positions (and maybe velocity values, etc) of all the objects and then play them back using non-physics display objects or just work out the positions the hard way.

Many people have worked on calculating trajectory of arrows, dead weights etc and it’s a popular subject in the maths and physics forums. I’ve tried myself with an amount of success:

http://springboardpillow.blogspot.co.uk/2012/04/sample-code.html

Figured it out.  In fact, the issue was not non-determinism.  It was just that there are variables we forgot to reset: the angle of the object (it was a ball, so it wasn’t visually obvious unless you were in hybrid mode), and the angular velocity.  Setting those both back to zero fixes the non-determinism entirely (at least as far as we could tell.)

For what it’s worth, Box2d is (according to the Box2d FAQ) fully deterministic within a given platform/binary.  Because of the vagaries of floating point, it is not deterministic between platforms.

Be aware that if you are resetting physics bodies that their internal Box2D values will continue to play a role in their mass, energy and position values even if you reset them. The only way to truly reset a Box2D physics object is to destroy it and create a new one.

Here’s a small complete program that shows the problem.  If you click the rectangle, it will restart the simulation.  Note that if you do it a bunch of times in a row, the bounce will happen quite differently from time to time.  Any ideas how to make this work?

local physics = require( "physics" ) physics.start() physics.setGravity(0,9.8) local function make\_ball (x,y) local ball = display.newCircle(0,0,10) physics.addBody( ball, { density=0.3, friction=0, bounce=0} ) ball.isSleepingAllowed = false ball:setFillColor(1,0,0) local function on\_restart() ball.x = x ball.y = y ball:setLinearVelocity(0,0) end on\_restart() Runtime:addEventListener("level-restarted",on\_restart) end -- A button for restarting the level local function make\_restart() local restartb = display.newRect( 30, 30, 40, 40) local function restart\_level(event) if event.phase == "began" then Runtime:dispatchEvent({name="level-restarted"}) end end restartb:addEventListener( "touch" , restart\_level ) end local function setup() make\_restart() make\_ball(200,20) local rect = display.newRect(200,200,2,2) physics.addBody(rect, "static", {bounce = 0.8}) end setup()

Yeeeaaahhh no.

Sorry, but the nature of the Box2D physics engine is such that it is not possible to setup a scene in exactly the same way every time and have the same result. It sounds like a nice idea, but there are actually many benefits to the way it is and it is clearly described by the creator, Erin Catto, as a realistic 2D physics engine.

If you want a level of prediction, the closest you can really do is either have the engine running, record the positions (and maybe velocity values, etc) of all the objects and then play them back using non-physics display objects or just work out the positions the hard way.

Many people have worked on calculating trajectory of arrows, dead weights etc and it’s a popular subject in the maths and physics forums. I’ve tried myself with an amount of success:

http://springboardpillow.blogspot.co.uk/2012/04/sample-code.html

Figured it out.  In fact, the issue was not non-determinism.  It was just that there are variables we forgot to reset: the angle of the object (it was a ball, so it wasn’t visually obvious unless you were in hybrid mode), and the angular velocity.  Setting those both back to zero fixes the non-determinism entirely (at least as far as we could tell.)

For what it’s worth, Box2d is (according to the Box2d FAQ) fully deterministic within a given platform/binary.  Because of the vagaries of floating point, it is not deterministic between platforms.

Be aware that if you are resetting physics bodies that their internal Box2D values will continue to play a role in their mass, energy and position values even if you reset them. The only way to truly reset a Box2D physics object is to destroy it and create a new one.