-
Notifications
You must be signed in to change notification settings - Fork 2
Limiting frame rate
While the web has many excellent articles on why it is important to not let graphical / physics operations run as fast as computers processing speed allows but rather limit how objects move, collide etc. depending on time, something known as delta time. Delta time can be simplified to phrase: “time difference since last frame”. Because this program only displays graphics and doesn’t have anything physics related, like particles bouncing and colliding, there is no need to build very elegant solution, such as what is presented here. Still, this wiki aims to point why it is important to program animation based on time, rather than computer cycles.
To truly comprehend what frame rate limiting does it is important to know what terms frame and frame rate mean in a context of a graphical computer program or computer game. A frame is single iteration of the game loop. Game loop presented in the Particle Fire Simulation revision program changes the color values of each particle created at the beginning of the program, updates the position of particles, applies post processing effect called box blur to them and finally updates all the previous changes to the screen for end user to see. This process usually happens multiple times a second so that the movement seems natural to human eye, thus the term frame rate means how many frames per second (fps for short) program is displaying. So, to put it simply in a context of a computer program; frame rate is the frequency of how many times in a single second game loop is executed.
Then why limit frame rate? Since one frame is equal to one execution of game loop, it means that if there is nothing limiting how fast the program is executed, the program will run as fast as possible and, depending how resource intensive the program is, use all the computing power of end user’s computer to run a single program. To prevent this from happening programmers, or the end users of program itself, may want to limit how many times game loop iterates in a second by delaying the execution of game loop. Computer games usually perform at 30 or 60 frames per second, but since there are also cases where faster frames are needed such as end users with faster monitors. For this reason it is usually good idea to have a setting for limiting frame rate instead of hardcoded limit set by the program, since it may lead to programs where frame rate limit the also limits game objects movement. The goal of more modern games is to have game logic to be independent from how fast game loop is executed. This can be achieved by making the movement constant, time based, so to speak.
Now it is time to dwell deeper in the code and start with number one, most important thing to do when creating programs with movement, such as games: making sure that movement is constant and not depend on how fast, or slow, the computer executes the game loop. For the sake of a simple example a game is being designed so that enemy objects appear in front of the player object. These enemies move towards the player. Player then has one second time to react and swing sword to defeat enemies. Here is a first version of a game loop for moving one enemy object to players position:
//Game loop runs as long as variable quit is false.
while (!quit) {
//Create an enemy object from enemy class with default constructor at position 0.
Enemy enemy1;
//Move enemy1 object towards player position, which is at 600 position.
if(enemy1.position <= 600){
enemy1.position += 10;
}
//the loop continues.. takes input from player and such
}On this example enemy object movement happens on every iteration of game loop until position is at 600 units where player is located. Programmers and test user Y’s computer is executing the program at 60 loops per second (or frames per second, fps) meaning that the enemy will move 600 units per second and is at players position after one second, sounds fine since one second reaction for the player to react is how the program is designed. Then comes along test user X, whose computer executes the game at 30 fps, the enemy will only move 300 units per second. Thus giving player more time to react, since enemy is only at halfway of the required 600 units position after one second of movement. Finally test user Z has a very fast computer with monitor that is capable of displaying whopping 120 frames per second! This user’s computer can easily run this game at 120 fps. Since enemy movement is dependable on frame rate this user reports that game is way too hard and there is no time to react to enemy moving towards player. Which is true, since double the frame rate from 60 fps means that this user has only 0.5 seconds to react, half the time that is designed for the game.
How can this be fixed? The solution is to make the game movement separate from frame rate. Here is a simple solution that works for games, with smaller scope and programs that display only graphics. This solution can have problems on some cases, like when computer is too fast. Still it represents the idea how to make movement not depend on computing power, but rather on time itself:
double lastTime = 0;
//Game loop runs as long as variable quit is false.
while (!quit) {
//Create an enemy object from enemy class with default constructor at position 0.
Enemy enemy1;
//Move enemy1 object towards player position, which is at 600 position.
if(enemy1.position <= 600){
//GetTime is a method that returns time how long the program has been running in milliseconds
double currentTime = GetTime();
//Calculate the difference between current time and last time, called delta time
double deltaTime = currentTime - lastTime;
//Multiply position with deltaTime-variable
enemy1.position += 0.6 * deltaTime;
//Store currentTime to lastTime value
lastTime = currentTime;
}
//the loop continues.. takes input from player and such
}Now the movement happens constantly and not on the speed of the computer. Setting position to update by 0.6 makes sure that it truly takes only one second to reach player, no more, no less. Calculations to proof this; example if deltaTime is around 1 millisecond(ms) then enemy position updates by 0.6 per loop. This means that it takes 1000 loops to reach position 600, since (600 position / 0.6 movement per loop) * 1ms of delta = 1000ms = 1 second to reach the player. If deltaTime is around 2.3ms then position updates by 1.38 per loop it takes 435 loops to reach position 600, since (600 / 1.38 movement per loop) * 2.3ms of average delta = 1000ms = 1 second to reach the player. Of course programs rarely perform exactly at same speed on each loop, but using delta time makes sure that even these cases movement is constant, thought it might appear somewhat jerky to user if there is huge fluctuation in performance.
Now that the movement is independent from how fast the programs loop executes, next up is setting up frame rate limiter, so that programmer or end user may choose how fast the program performs. For further reading about delta time and framesteps recommendation is Gaffer On Games’ excellent article by Glenn Fiedler, or another one by Koen Witters and also this and this. These source give more in depth view about things like physics and constant game speed independent of variable fps.
Previous header proved why it is important to separate game loops execution speed from objects movement. Since limiting frame rate is not the best solution for making movement constant, it is rather used to limit speed of game loop and save precious computer resources to another operations that user may want to do while using the program. After all modern operating system are designed around multitasking. Starting up with a code how frame limiter can be implemented example:
//Set up desired frame rate to target_fps-variable
target_fps = 60;
//Another game loop example. Game loop runs as long as variable quit is false.
while (!quit) {
double LoopStartingTime = GetTime();
//Move characters, update screen etc..
//Limit frames per second
if ((1000 / target_fps) > GetTime() - LoopStartingTime) {
Delay(1000 / target_fps - (GetTime() - LoopStartingTime));
}
}Since frame rate can be set, there needs to be variable that holds the value, for that reason target_fps is initialized to value 60 before the loop begins. Again game loops run as long as quit is false, and after all the game loops operations, such as updating position of characters, creating particles etc. are done it is time to start limiting framerate. Reminder that GetTime-function returns value of how long the program has been running since the beginning of the program in milliseconds, while Delay function delays execution of program by amount of milliseconds entered. First if statement checks if there is really necessary to limit anything since on some cases program is performing at the speed that it is intended. In the case of target_fps having value 60, the the if statement is following: if 16,667ms is larger than result of GetTime() subtracted by currentTime the statement is true. If the statement is true, then the time the program needs to delayed is the time 16,667ms minus the difference between current time and loop start time. Delaying basically stops program from running for set amount of milliseconds before continuing execution.
A reminder that these are not based on any one solution so mileage may vary on different graphical libraries. Even though this program itself uses SDL-library, the concept presented here are not depended on the graphics library. Any graphics library, that has ability to calculate how long the library has been running and do delaying, can be used, but there might be some parts that need tweaking when using with graphic library of choice. To better view how these are implemented please refer to this wiki-page and of course the repo itself