Box2D Forums

It is currently Thu Sep 09, 2010 6:25 am

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Frame rate independent movement and b2World::Step
PostPosted: Sat Jan 24, 2009 11:34 am 
Offline

Joined: Fri Jan 23, 2009 8:37 pm
Posts: 3
Hi,

I am trying to get frame rate independent movement (FRIM) on my Box2D project, however, surprisingly I get slower speeds on a machine with more horsepower than one with less, I am very familiar with ODE, and in it to get FRIM what we usually do is set a static step size, then use the time delta between frames to iterate the step function until the sum of the steps is greater or equal to the delta time.

I tried this same approach with B2D, what I described above is what I get, if I just iterate 60 times as in the example and documentation, then the movement is not frame independent (faster on faster computers).

Anyway, is there a way to get FRIM I am not aware of?

This is my code (msdelta is the delta time since last frame in milliseconds, from SDL_GetTicks(), everything else is self explanatory I think, but let me know if there is any questions):
Code:
void Map::Step(Uint32 msdelta)
{
  const Uint32 millistep = 16;
  const float timeStep = 0.016f; // 16 milliseconds ~= 60Hz
  const int iterations = 10;
  Uint32 acumulator = 0;
  while(acumulator<msdelta)
  {
    world->Step(timeStep,10);
    acumulator+=millistep;
  }
}


Am I right in assuming b2World::Step takes the time step in seconds?

Thanks in advance :)


Top
 Profile  
 
 Post subject: Re: Frame rate independent movement and b2World::Step
PostPosted: Sat Jan 24, 2009 11:55 am 
Offline

Joined: Mon Jan 07, 2008 10:51 am
Posts: 1908
That's not right... you are throwing away the fractional steps. Suppose Step were called ever 1ms because you are on a super fast machine, then Box2D would be doing a 16ms step every 1ms.

Try something like:

Code:
Uint32 accumulator = SDL_GetTicks();

void Map::Step()
{
  const Uint32 millistep = 16;
  const float timeStep = 0.016f; // 16 milliseconds ~= 60Hz
  const int iterations = 10;
  Uint32 ticks = SDL_GetTicks();
  while(acumulator<ticks)
  {
    world->Step(timeStep,10);
    accumulator +=millistep;
  }
}


or

Code:
void Map::Step(Uint32 msdelta)
{
  const Uint32 millistep = 16;
  const int iterations = 10;
  Uint32 accumulator = 0;
  while(accumulator<msdelta)
  {
    const Uint32 currentstep = min (msdelta - acumulator, millistep);
    world->Step(currentstep/1000, 10);
    accumulator +=currentstep ;
  }
}


PS this article is often recommended:
http://gafferongames.wordpress.com/game ... -timestep/


Top
 Profile  
 
 Post subject: Re: Frame rate independent movement and b2World::Step
PostPosted: Sat Jan 24, 2009 4:08 pm 
Offline

Joined: Thu Jan 22, 2009 3:37 pm
Posts: 8
I suspect that you are applying a force/impulse between each call to Step(). On a faster machine:
  • Force applied
  • Time step
  • Force applied
  • Time step
  • Force applied
  • Time step
On a slower machine:
  • Force applied
  • Time step
  • Time step
  • Force applied
  • Time step
On the slower machine, fewer forces are applied within the same amount of real time.
(Of course, I could be wrong, as I don't know the rest of your code)


Top
 Profile  
 
 Post subject: Re: Frame rate independent movement and b2World::Step
PostPosted: Sat Jan 24, 2009 7:11 pm 
Offline

Joined: Sat Jan 24, 2009 10:04 am
Posts: 40
This might be helpful:
http://gafferongames.wordpress.com/game ... -timestep/


Here's the gist of his code:
Code:
    float t = 0.0f;
    const float dt = 0.01f;

    float currentTime = time();
    float accumulator = 0.0f;

    State previous;
    State current;

    while (!quit)
    {
         float newTime = time();
         float deltaTime = newTime - currentTime;
         currentTime = newTime;

         accumulator += deltaTime;

         while (accumulator>=dt)
         {
              previousState = currentState;
              integrate(currentState, t, dt);
              t += dt;
              accumulator -= dt;
         }

         const float alpha = accumulator / dt;

         State state = currentState*alpha + previousState*(1.0f-alpha);

         render(state);
    }

Dan


Top
 Profile  
 
 Post subject: Re: Frame rate independent movement and b2World::Step
PostPosted: Sat Jan 24, 2009 9:49 pm 
Offline

Joined: Fri Jan 23, 2009 8:37 pm
Posts: 3
Wow, I was not expecting so many replies this soon.

Boris:

The first block of code you posted doesn't seem right, SDL_GetTicks() returns the amount of time since the initialization of the SDL library in ms, so you'd be doing the stepping since the time you first set the accumulator variable until the current time, I'll try the second one, though dynamic step size seems discouraged, I think you may be right on that one, perhaps I should set accumulator as static and carry the remainder ticks over.

This is what my game loop looks like:

Code:
void SideScroller::MainLoop()
{
  Uint32 time;
  while(1)
    {
      // SDL keyboard input handling goes here
      time = SDL_GetTicks();
      Step(time - lasttime); // currently this member function just calls the Map::Step function I already posted
      lasttime = time; // lasttime is a member variable that holds the ticks since the last loop
      Render(); // renders the scenegraph
    }
}


goffrie:

Right now all I've done is set some "ground" boxes, gravity and drop a box, nothing else, there is probably more calls as necessary as you pointed out because I am not carrying over the remainder as Boris pointed out.

Dan:

Thanks, I'll definitely take a look :)

Thank you all.


Top
 Profile  
 
 Post subject: Re: Frame rate independent movement and b2World::Step
PostPosted: Sun Jan 25, 2009 5:46 am 
Offline

Joined: Mon Jan 07, 2008 10:51 am
Posts: 1908
The Get_Ticks thing was just to demonstrate making it a static variable. As you've grasped, you'd need to set it at the start of simulation, not the start of program.


Top
 Profile  
 
 Post subject: Re: Frame rate independent movement and b2World::Step
PostPosted: Mon Jan 26, 2009 10:34 am 
Offline

Joined: Fri Jan 23, 2009 8:37 pm
Posts: 3
Alright, my code now looks like this:

Code:
void Map::Step(Uint32 msdelta)
{
  const Uint32 millistep = 16;
  const float timeStep = float(millistep)/1000; // 16 milliseconds ~= 60Hz
   const int iterations = 10;
  static Uint32 acumulator = 0;
  acumulator += msdelta;
  while(acumulator>=millistep)
  {
    world->Step(timeStep,10);
    acumulator-=millistep;
  }
}


It works now, Thank you very much everyone :mrgreen:


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: Exabot [Bot] and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group