Author

Topic: Does anyone here know anything about timestep and FPS limiting in programming? (Read 1080 times)

legendary
Activity: 1540
Merit: 1000
Thanks for that foxpup that explanation was awesome, I'll start experimenting now and see what happens.
legendary
Activity: 4494
Merit: 3178
Vile Vixen and Miss Bitcointalk 2021-2023
In this code:
void Game::run()
{
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
while (mWindow.isOpen())
{
processEvents();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
processEvents();
update(TimePerFrame);
}
render();
}
}
"TimePerFrame" is a constant that you should set to whatever your game needs, eg if you need a constant framerate of 50 fps, you should set it to 20 (assuming the clock returns values in milliseconds; I think it does, but I'm not very familiar with SFML).

Then, with every iteration of the loop, it looks at how long it's been since the last time the game state was last updated, and if it was longer than 20 ms (or whatever you set for TimePerFrame), it runs the update() function (possibly multiple times, if your render framerate is slower than your game framerate, so it needs to update multiple times per frame).

The update() function is where you do your actual updating of the game state, eg incrementing the position of moving objects, applying health damage, whatever it is you need to happen in your game.

Finally, after all that, render() is where you put your actual rendering (screen drawing) code. A more advanced version of this code (which you should not attempt until you get the basics working) would have render() take timeSinceLastUpdate as an argument, and use it to do interpolation of moving objects (ie, don't draw them where they are, but where they will be timeSinceLastUpdate milliseconds from now; this allows for smoother animation, but since you're only drawing them in a different position instead of actually moving them, rounding errors will not accumulate).

One major problem with this code that you need to be aware of is that it will livelock (the technical term for what is referred to in the article as the "spiral of death") if TimePerFrame is less than the time it takes to run the update() function. Don't set TimePerFrame too low!
legendary
Activity: 1540
Merit: 1000
So I'm progressing through my learning when it comes to programming and I can get basic stuff up and working but I really want to get my stuff all working smoothly, I have example source code and explanations of timestep ( The annoying lag etc. in games ) and limiting of frames per second. I understand the mechanics they've explained behind how it all works but I'm having trouble seeing how I could implement it into my own code freely like I do with all the basic stuff, I think I need a more basic English explanation of what's going on because I see that many of the functions C++ or SFML involve a lot of classes and named objects or they are commands that I'm confusing with classes because I keep trying to find out where they've been declared.

Perhaps I need to take a look at some of these commands individually so I know for sure what they do? I think that's what's happening, anyway, here's the code I'm working with, I'd appreciate any help you can give me fixing this will mean I'll be able to make my games nice and smooth and optimise them properly and we all know the games industry needs a lot more of that Cheesy.

My code

Quote

#include
#include
#include

int main()
{

    sf::RenderWindow window(sf::VideoMode(800, 600), "");

    int healthstats = 1;


    sf::Font arial;
    if ( !arial.loadFromFile ( "arial.ttf" ) )
    { }

    sf::RectangleShape health ( sf::Vector2f ( healthstats, 5 ) );
    health.setFillColor ( sf::Color::Cyan );
    health.setPosition ( 20, 10 );


while (window.isOpen())
{
    if ( sf::Keyboard::isKeyPressed ( sf::Keyboard::A ) )

    {
        health.setScale ( healthstats, 5 );
        healthstats = healthstats - 1;
    }

    else if ( sf::Keyboard::isKeyPressed ( sf::Keyboard:: D ) )
    {
        health.setScale ( healthstats, 5 );
        healthstats = healthstats + 1;
    }

sf::Event event;
while (window.pollEvent(event))
{

if (event.type == sf::Event::Closed)
window.close();
}
        window.clear();
        window.draw ( health );
        window.display();

    }
    return 0;
}



Example code for fixing timestep and lag from book

Quote

void Game::run()
{
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
while (mWindow.isOpen())
{
processEvents();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
processEvents();
update(TimePerFrame);
}
render();
}
}


An article an SFML book I bought linked me to, to help explain things better:

http://gafferongames.com/game-physics/fix-your-timestep/


Example source code from article

Quote

    double t = 0.0;
    const double dt = 0.01;

    double currentTime = hires_time_in_seconds();
    double accumulator = 0.0;

    State previous;
    State current;

    while ( !quit )
    {
         double newTime = time();
         double frameTime = newTime - currentTime;
         if ( frameTime > 0.25 )
              frameTime = 0.25;     // note: max frame time to avoid spiral of death
         currentTime = newTime;

         accumulator += frameTime;

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

         const double alpha = accumulator / dt;

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

         render( state );
    }

Jump to: