# Limiting framerate with a fixed timestep

UPDATE:

I still need help determining how MAX_UPDATES works. I want my game to be designed in such a way that if the user can't run the game at full speed, it slows down so that no updates are missed.. can someone help me understand that part of the code? Also, how can I calculate an accurate realtime fps?

double frametime = 1000000./60, remainingTime = 0;
const unsigned int MAX_UPDATES = 10;

void Game::gameLoop(sf::RenderWindow &window)
{
remainingTime += clock.restart().asMicroseconds();
while (remainingTime >= frametime)
{
remainingTime -= frametime;
{
update();
}
}
render(window);
}

Hi I'm learning how to create a 2d platformer in C++ using the SFML2 library. My current goal is limiting the game's framerate. SFML2 has a window.setFramerateLimit(unsigned int limit) function for the window however I have found it to be imprecise due to it using sf::sleep. Therefore I'm attempting to implement my own solution. I want my game to used a fixed timestep and be framerate dependent as in the future when I implement attacks I want them to be based on frame data.

Since the game loop wont always execute exactly when a frame is supposed to happen, I create a delta variable that will account for the extra time spent starting the frame to start the next frame earlier by that same amount.

Does this all look right?

double frametime = 1000000./60, delta = 0;
void Game::gameLoop(sf::RenderWindow &window)
{
t = clock.getElapsedTime().asMicroseconds();
if (t + delta >= frametime)
{
clock.restart();
delta = t + delta - frametime;
update();
}
render(window);
}

edit: double shouldn't have f suffix doh

• double frametime = 1000000.f/60 why are you casting as floats? if you use a double, it should be double frametime = 1000000.0/60.0... Jul 27 '16 at 21:23
• doh, didn't mean to put that Jul 28 '16 at 0:10
• Calculating the FPS should be asked for a different question (or you know, you could just Google the answer). Jul 30 '16 at 21:50

While your setup should roughly work, it still locks updates and framerate. So if your framerate drops below 60 fps you won't be able to do 60 updates per second anymore. This essentially defeats the whole purpose, unless you really can always stay above 60 fps (which you shouldn't assume, even for simple games).

Whenever I want a fixed framerate in SFML I'm doing something like this:

static const sf::time frameTime = sf::milliseconds(10); // 100 updates per second
static const unsigned int maxUpdates = 10; // Maximum number of updates between draws

sf::Clock updateTimer; // Initialized or reset right before the main loop starts
sf::Time remainingTime;

sf::Time deltaTime = updateTimer.restart(); // Get the time difference and reset

update(deltaTime); // Do non-critical time based updates where you don't need exact ticks (e.g. visible particles)

remainingTime += deltaTime; // Add up the time we haven't updated yet

// Now update as long as the time passed is longer than one frame
while (remainingTime > frameTime) {
remainingTime -= frameTime;

if (updates++ < maxUpdates) // Ensure we don't get stuck if we can't reach our intended number of updates per second
update(); // Do one game logic tick
}

Just let me explain maxUpdates in case you're not sure what it's for:

Imagine a scenario where you want to do 100 updates per second and the current machine only barely handles 90 updates per second. You'll be stuck with an overhead of 10 updates per second, which will inevitable stack up and kill your framerate, making the game unresponsive. By limiting the number of updates between drawing calls you ensure the game keeps running, but it will inevitably slow down, if performance is too bad (which at this point won't matter anymore, because the game should be stuttering anyway).

• I'm not quite understanding the maxUpdates part. I revised my code in a way such as yours but I'm still confused. My game is going to be a fighter which relies on frame by frame attacks so I don't want updates to be skipped right? Jul 30 '16 at 21:44
• In that case this whole approach is flawed. The trouble begins if you need the game to call update more than it can in real time process, as Mario very well explains. See Fix your timestep for more explanations. Jul 30 '16 at 21:51
• That was the first resource I checked out. Don't I want to follow a fixed time step? Since my game is going to be a 2d fighter with moves that follow frame patterns, isn't the best way to handle this to have the game run locked at 60 fps and to slow down if it doesn't reach 60 fps? I feel as if out of sync updates wouldn't work. What approach do I need to follow? Jul 30 '16 at 22:48
• Stop thinking in classic console terms. Back then you essentially had one frame and one update per frame. Everything ran at a fixed time step. For modern PC gaming that's no longer the case. You'd have your fps/refresh rate at one rate (e.g. 60hz, 120hz, 144hz, etc.) and you'd have your update rate. The classic "frame perfect gameplay" is still possible, you just no longer lock it to visual updates. So if you're doing 30 updates per second in your game logic, you'll be able to create frame perfect gameplay that runs at 30 fps but renders at whatever the system supports. Jul 31 '16 at 9:12
• maxUpdates is there to avoid a backlog. Going back to my previous comment. Let's assume you want 30 updates/frames per second. If the system is so slow it can't keep up, you're running into problems. Let's assume the game now does those 30 updates but it takes 1.5 seconds to do so. Now one (visual) frame is drawn and the next update starts: Since 1.5 seconds passed since the last update, it would now try to run 45 updates, which would take like 2 seconds already. Then once again the game is drawn. Next time the game will do 60 updates since 2 seconds passed since the last update start, etc. Jul 31 '16 at 9:17

I wrote a similar block of code into in my game, no problem on Windows, Mac, Linux, Android and low end platform.

Then I presume it's very correct for small games. Take care: Be precise can over consume the resources (do you really need it?). Prefer work with integer and not floating value (for performance reason, eg: Raspberry pi 1, no hardware float acceleration).