SFML community forums

General => General discussions => Topic started by: albert_lazaro on September 18, 2019, 09:15:06 pm

Title: Setting Frame Limit of the project
Post by: albert_lazaro on September 18, 2019, 09:15:06 pm
Hi, I’m learning SFML with “SFML Game Development” (https://www.amazon.com/SFML-Game-Development-Jan-Haller/dp/1849696845) and there is something I don’t understand about fixed time steps technique to give always the same delta time to the update function:

/*
When we are over the required amount for one frame, we substract
desired length of this frame (TimePerFrame) and update the game.
*/

void Game::run()
{
    sf::Clock clock;
    sf::Time timeSinceLastUpdate = sf::Time::Zero;

    while(mWindow.isOpen())
    {
        processEvents();

        timeSinceLastUpdate += clock.restart();
       
        // collects the user input and computes the game logic.
        while (timeSinceLastUpdate > TimePerFrame)
        {
            timeSinceLastUpdate -= TimePerFrame;
            processEvents();
            update(TimePerFrame);    
        }        
        render();
    }
}

So we accumulate the elapsed time in timeSinceLastUpdate and substract the desired length of this frame (TimePerFrame = 1.f /60.f) and do this until we are below the required amount again ant then render the scene (this is called logic frame rate). With this the frame rate is 60 fps.

With this, if rendering is slow, processEvents()  and update() may be called multiple times before one render() call, so the game occasionally slutters becuase not every update is rendered, but the game doesn’t go slow down. On the other hand fast rendering can lead to call render() multiple times without a logic update in between.

Ok, the problem of this method is that CPU usage is high (about 50% or more).

Then I can use sf::RenderWindow::setFrameLimit(60) that calls sleep() internally but lacks precision, and then is sf::RenderWindow::setVerticalSyncEnabled() that adapts the graphical updates to the refresh rate of the monitor (GPU I think).

My question is about what method do you usually use: and accurate method like first, the setFrameLimit function or the setVerticalSyncEnabled()? And if the answer is the first one, how do you solve the problem of the CPU usage?

Thanks to everyone.
Title: Re: Setting Frame Limit of the project
Post by: Nexus on September 18, 2019, 10:26:55 pm
Hello, and welcome to the SFML forum! I hope that as one of the authors, I can give you a slightly more detailed answer than in the book ;)

In general, as long as your code runs, you will use 100% of one CPU core, or 50% of a dual-core processor -- after all, there are constantly new instructions being processed. The only way how you can decrease CPU utilization is by giving back CPU time to the operating system (or force it to be taken, if other resources are competing). This is typically done using sleep statements (sf::sleep() in SFML) or through blocking I/O (in multiple threads, you may wait for events or incoming network packets).

A very good article about game loops can be found here. It explains the fixed timestamp approach from our book and compares different trade-offs:
https://gameprogrammingpatterns.com/game-loop.html

The sleep's precision depends on which system call is used and how the system is configured. In this StackOverflow answer (https://stackoverflow.com/a/13397866) you'll find an in-depth explanation of the topic. There are also high-precision implementations (e.g. Windows (https://stackoverflow.com/a/54582486) or Linux (http://man7.org/linux/man-pages/man2/nanosleep.2.html)), although they are typically not needed.

So, you have the following options:
Title: Re: Setting Frame Limit of the project
Post by: albert_lazaro on September 22, 2019, 06:30:13 pm
Thanks for the response, I'm a web developer so this is new for me (on web development I don't have this type of problems XD ).

So the idea of make games are simple 2D games for the moment. The first one would be an RPG like Final fantasy I (https://www.youtube.com/watch?v=aXb3q62X7Us).

I think I don't need higher precision (this would not be an AAA game) so I don't want to use 100% CPU. So I'm between using Standard sleep (usually good enough) and try Vsync in the future.

Now I will search for use standard sleep.

PD: I develop on a laptop, so it heads up easily if the usage of CPU is 100%.
Title: Re: Setting Frame Limit of the project
Post by: jamesL on September 24, 2019, 07:12:26 pm

So, you have the following options:
  • VSync (easiest for graphics, aligns refresh rate with monitor)

is VSync really an option ? 

I see a bunch of example SFML and SDL games that set the vsync option, but can't the player disable that globally ?

so relying on that wouldn't work, right ?
Title: Re: Setting Frame Limit of the project
Post by: albert_lazaro on September 29, 2019, 07:35:41 pm
I think Vsync would have to be configurable by the user in a option menu, but you can't be sure it will work 100% of times.

There is more info in the tutorials -> https://www.sfml-dev.org/tutorials/2.0/window-window.php#controlling-the-framerate
Title: Re: Setting Frame Limit of the project
Post by: albert_lazaro on December 04, 2019, 07:28:38 pm
Hi I skipped the loop problem to focus on the book, and now that I had advanced more I want to solve the loop problem because I don't want to burn my computer every time I'm executing my code for testing.

I want to use standard sleep, so in the main loop I have to write the sleep at the end of the outer loop? How many time it has to be sleeping?

void Game::run()
{
    sf::Clock clock;
    sf::Time timeSinceLastUpdate = sf::Time::Zero;

    while(mWindow.isOpen())
    {
        processEvents();

        timeSinceLastUpdate += clock.restart();
       
        // collects the user input and computes the game logic.
        while (timeSinceLastUpdate > TimePerFrame)
        {
            timeSinceLastUpdate -= TimePerFrame;
            processEvents();
            update(TimePerFrame);    
        }        
        render();
        <- here goes sleep ?
    }
}
 

If you see the video of above in this thread, you will see what type of game I want to do, so for this game I don't think it is necessary that the computer is working at 100% of cpu
Title: Re: Setting Frame Limit of the project
Post by: eXpl0it3r on December 05, 2019, 09:54:50 am
SFML already has such a functionality with setFramerateLimit().

You'd sleep the amount of time, that would still make your reach the desired frame time.
Say you want 60fps <=> 16.666ms, now your last frametime was 4ms, so you could in theory sleep 16-4ms = 12ms.
However, sleeping is not a precise action, so you need to consider some slack, if you really want to precise.
(If you want to go crazy, you can also measure the deviation and adjust dynamically)
Title: Re: Setting Frame Limit of the project
Post by: albert_lazaro on December 21, 2019, 08:32:23 pm
I have seen the code of setFrameRateLimit:

void Window::setFramerateLimit(unsigned int limit)
{
    if (limit > 0)
        m_frameTimeLimit = seconds(1.f / limit);
    else
        m_frameTimeLimit = Time::Zero;
}
 

Can I combine it with my game loop? so before the loop starts I set the frame rate to 60 and then the loop is executed.

I don't know if, after the display is executed and the process goes to sleep, the time of clock is counting.