Does Box2D physics rely on frame rates?

I am doing 2D scrolling for Android and am thinking of using Box2D for physics. I would like to know if, when using Box2D, if the device's frame rate drops from 60fps (limitation on Android) to, for example, 30fps, the physics will slow down with it?

To develop, I'm going to use real-time online multiplayer, so the frame rate cannot be relied upon to be constant. Therefore, if one of the devices in a multiplayer game runs at 60 frames per second, and the other at 30 frames per second, and the object must move at a speed of 10 meters per second, it will move at a speed of 5 meters per second on a slower device?

I would like to use Box2D, so if this is the case, is there a way to work around it?

+2


source to share


3 answers


I think there are really two questions to your question.

1) If you change the speed of physical time during simulation.

NO you shouldn't. ... You can iterate over the engine many times during a game loop time step (call the function multiple times Step(...)

with the same step values).

From section 2.4 of the Box2D 2.3.0 manual:

The time step of a variable produces variable results, making it difficult to debug. So don't tie the time step to the frame rate (unless you really need to).

2) How can I connect two physics simulators in real time and subordinate them to physics update cycles to each other.

There was once a genre game called Age of Empires. He boasted that thousands of AI units were battling each other in real time on the 28.8 network. It worked so well, someone wrote an article on how they did it:

I adapted the technique and code below for my refresh loop so that I can control the frame rate of two games playing against each other on two different iPads.

void GameManager::UpdateGame()
{
   const uint32 MAXIMUM_FRAME_RATE = Constants::DEFAULT_OBJECT_CYCLES_PER_SECOND();
   const uint32 MINIMUM_FRAME_RATE = 10;
   const uint32 MAXIMUM_CYCLES_PER_FRAME = (MAXIMUM_FRAME_RATE/MINIMUM_FRAME_RATE);
   const double UPDATE_INTERVAL = (1.0/MAXIMUM_FRAME_RATE);

   static double lastFrameTime = 0.0;
   static double cyclesLeftOver = 0.0;

   double currentTime;
   double updateIterations;

   currentTime = CACurrentMediaTime();
   updateIterations = ((currentTime - lastFrameTime) + cyclesLeftOver);

   if(updateIterations > (MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL))
   {
      updateIterations = MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL;
   }

   while (updateIterations >= UPDATE_INTERVAL)
   {
      //      DebugLogCPP("Frame Running");
      updateIterations -= UPDATE_INTERVAL;
      // Set the random seed for this cycle.
      RanNumGen::SetSeed(_cycleManager->GetObjectCycle());
      // Dispatch messages.
      _messageManager->SendMessages();
      // Update all entities.
      _entityManager->Update();
      // Update the physics
      _gameWorldManager->Update(Constants::DEFAULT_OBJECT_CYCLE_SECONDS());
      // Advance the cycle clock.
      _cycleManager->Update();
   }

   cyclesLeftOver = updateIterations;
   lastFrameTime = currentTime;
}

      



This piece of code contains the number of iterations performed, balanced between the upper and lower maximum. One of the key notes is that the actual call to this function does not occur if the message from the other player has not been received in a timely manner. This effectively dehydrates two physical systems.

3) PART THAT YOU (CAN) REALLY KNOW

If you plan on using Box2D on both devices to run physics on your own, you will almost certainly see them diverge after a short time. I ran my game on iPad 2 and iPad 3 and noticed that after a few seconds they parted (collisions happen in one, but not in the other). This is because the rounding behavior in floating point numbers differs from several factors. For a few quick calculations, no problem. But small discrepancies creep into low-order bits and accumulate as values ​​are continuously looped through the integrators (as you would see, for example, in physics simulations). Double precision helps a little, but not in the end.

A few simple tests of viewing a specific bouncing ball in the area of ​​bouncing balls on multiple processors (e.g. iPad 2 vs iPad 3 for the same code) will show this. The bugs creep in after a couple of seconds of movement, and suddenly your speed / position is enough to matter.

Fixed-point math is a solution, but it also leads to its own insanity. At one point Box2D had a fixed point version, but this time.

I even played around with the fixed point version of Box2D, but was distracted by another project (Space Spiders Must Die!). Someday...

This may not be a problem for your particular situation (i.e. you are not running an independent simulation or running it as if it works as expected), and if it doesn't, don't worry.

You can see a lot of other Box2D stuff on my blog (but not this game ... not there yet).

Was this helpful?

+3


source


Found the answer in the Box2D manual.

"2.4 Simulation of the world (Box2D)



..... We also don't like that the time step has changed a lot. Variable time step gives variable results, making it difficult to debug. So don't tie the time step to the frame rate (unless you really need to) ...

This way the physics doesn't change with the frame rate, but they can if you want them to.

+1


source


There are two things you need to consider.

The frame rate does not affect the speed of moving objects. even if your frame rate is 10 frames per second, your body will still move at 10 meters per second.

What really changes is the number of position and speed iterations that you can effectively perform with that frame rate and collision detection accuracy.

In slower footage, we often saw bodies tunnel through others and collisions fail in one way or another.

In this case, the fix would be to use a fixed time interval even in cases where there is an incoherent frame rate. The code we are using for this is as follows

float maximumStep = 1.0f/60.0f;
float progress = 0.0;

// TODO: Tune it further to prevent DEATH!
while (progress < dt)
{
    float step = min((dt-progress), maximumStep);
    // Since we do not have any post collision dynamics therefore we can get away with a one step process for velocity / position iterations.
    GameState::sharedInstance()->box2dWorld->Step(step, 8, 8);
    progress += step;
}

      

Pay attention to TODO here to prevent DEATH. While this approach ensures that physics processing runs at a fixed frame rate and there is absolutely no crash on collision, BUT you have to make sure you don't fall into the time loop mentioned above.

We tweak things by setting the maximum step value to a LARGEST value which results in consistent physics. This is done by testing to see which collision values ​​start to fail and rotate the maximum step at that point.

You also need to tweak the number of iterations of position and speed (the numbers mentioned in the Step function to the correct values ​​based on your game. Each game should tweak this according to its own needs. Works for you.

+1


source







All Articles