Game Loop: Difference between revisions

From C# Gamedev Wiki
No edit summary
No edit summary
Line 68: Line 68:


==Independent Update and Draw==
==Independent Update and Draw==
It is clear that game logic should be fixed step for a consistent experience, but ideally game rendering should be able to run independently at the display's refresh rate.  To achieve this the <code>Update()</code> must be able to run independently of <code>Draw()</code>, a separation many programmers are familiar with (back end / front end, model / view, etc.).
Ideally game logic should be fixed step for a consistent experience, but game rendering should be able to run independently at the display's refresh rate.  To achieve this <code>Update()</code> must be able to run independently of <code>Draw()</code>, a separation many programmers are familiar with (back end / front end, model / view, etc.).
 
===Frame Interpolation===
The easiest way to implement this separation is with Frame Interpolation.


[[Category:Basics]]
[[Category:Basics]]

Revision as of 14:49, 9 June 2024

A game loop is a continuous loop that handles both running game logic and renders the game to the player.

Simple Game Loop

In the simplest example of a game loop, the game updates and draws at the same rate.

void GameLoop()
{
    while (true)
    {
        Update(); // updates game logic (handle input, physics, collision, interaction, etc.)
        Draw(); // renders game to player (images, sounds, 3d models, text, etc.)
    }
}

In practice game loops may have a lot more code. They may wait a certain amount of time between passes, do less processing on certain passes than others, contain exit logic, etc.

This was a common way to design video games when they were first made, and came with the following pros and cons:

  • Pros
    • Even when the game slows down, physics and game logic are still processed in a consistent manner.
  • Cons
    • If either the Update() or the Draw() took too much time, the game would slow down.
    • Game may not run at full speed on weaker hardware.
    • Different versions of the game must be made in order to run at different framerates.
      • Many old games had NTSC versions which ran at 60 fps and PAL versions which ran at 50 fps.
      • Game physics may not be consistent between versions.

Timesteps

There are two main types of timesteps:

  • Fixed Step - the game loop processes equal intervals of game time
  • Variable Step - the game loop processes varying intervals of game time based on how much real time has passed

While simple game loops originally all used fixed timesteps, some began to use variable timesteps as a way to address known issues:

// time of last iteration through game loop
DateTime lastTime;

void GameLoop()
{
    lastTime = GetRealTime();
    while (true)
    {
        // calculate elapsed real time
        var time = GetRealTime();
        var dt = time - lastTime;
        
        Update(dt); // updates game logic (handle input, physics, collision, interaction, etc.)
        Draw(dt); // renders game to player (images, sounds, 3d models, text, etc.)
        
        lastTime = time;
    }
}

This solved a few important issues but introduced new issues as well:

  • Pros
    • Game runs at full speed on weaker hardware.
    • If either the Update() or the Draw() took too much time, the game would keep running at full speed.
    • One version of the game can run at different framerates.
  • Cons
    • When the game slows down
      • Physics and game logic are not processed in a consistent manner.
      • Player inputs may be dropped.

Independent Update and Draw

Ideally game logic should be fixed step for a consistent experience, but game rendering should be able to run independently at the display's refresh rate. To achieve this Update() must be able to run independently of Draw(), a separation many programmers are familiar with (back end / front end, model / view, etc.).

Frame Interpolation

The easiest way to implement this separation is with Frame Interpolation.