Kyle Lambert

Development Blog

FIXED TIME-STEP GAME LOOP

Jul 30, 2025

Interpolation and extrapolation graphic

Image source.

For the majority of simple games I've made, using delta-time in the update function was enough. The games had relatively fixed frame-rates and if there were collision boxes, they were big enough to survive delta-time jumps. However, for the schmup I'm making, I decided it would be best to go with a fixed time-step loop. My reasoning was that, due to the nature of a schmup; high-speed, high-precision, and small hit-boxes, it's critical for near-pixel-perfect simulation.

With fixed time-steps and a little bit of math, I can guarantee that hit-boxes won't be missed on variable frame-rates. Additionally, by using interpolation, I can also guarantee that what the player sees is as close to the actual game state as possible. I can't stress enough how important this is for a schmup. Bullets will be flying at high-speed towards hit-boxes only a few pixels wide. If the player is getting hit without seeing a hit, or vise versa, it could completely ruin the gaming experience. The simulation needs to be predictable and the visuals need to match as closely as possible.

double accumulator = 0.0;
double prevTimeSec = GetTime();

while (!WindowShouldClose()) {
    double currTimeSec = GetTime();
    double frameTimeSec = currTimeSec - prevTimeSec;

    // Avoid spiral of death.
    if (frameTimeSec > 0.25) frameTimeSec = 0.25;

    prevTimeSec = currTimeSec;
    accumulator += frameTimeSec;

    Input();

    // Fixed update loop intervals.
    int loops = 0;
    while (accumulator >= SKIP_TICKS && loops < MAX_FRAMESKIP) {
        Update(SKIP_TICKS);
        accumulator -= SKIP_TICKS;
        loops++;
    }

    double alpha = (double)(accumulator / SKIP_TICKS);
    Interpolate(alpha);

    Draw();
}
            

As you can see in this code example, the flow of logic for each individual frame is as follows:

  1. Calculate the elapsed time between the start of last frame and the start of this frame.
  2. If the elapsed time is greater than 0.25 seconds, set it to 0.25 to avoid The Spiral of Death.
  3. Increment our accumulator by the elapsed time.
  4. Run the update function with a fixed delta-time, subtracting it from the accumulator, until we either run out of elapsed time or hit a maximum threshold.
  5. Calculate the interpolation factor (the fraction of time that has passed since the last logic update, divided by the fixed update interval).
  6. Execute the interpolation function to produce and intermediary "draw state".
  7. Draw the frame based on the interpolated draw state.

For now this works perfectly and I can adjust both the frame-rate and update-rate independently. I am slightly concerned though at the added complexity due to interpolation. Because of this, I have to keep track of a separate state, the "draw state". This way, when there's not enough time to run another update loop, I can still draw the frame where objects would be if it did update. This keeps the visuals smooth while making the simulation (update calculations) more reliable with fixed steps.

Here is an example data structure used to test the game loop:

struct Device {
    Vector2 prevPos;
    Vector2 currPos; // Normally all you need is this.
    Vector2 rendPos;
};
            

This structure tracks the location of a ball moving across the screen. Normally, without interpolation, you just have one position which is incremented by delta-time or fixed-step during the update. However, with the addition of interpolation, I now have to track both the previous position and the render position. That function looks like this:

void Interpolate(double alpha) {
    device.rendPos.x = device.prevPos.x + (device.currPos.x - device.prevPos.x) * alpha;
    device.rendPos.y = device.prevPos.y + (device.currPos.y - device.prevPos.y) * alpha;
}
            

In conclusion, I'm glad I have my game loop implemented, since it is the backbone of my game. However, I will be reevaluating it in the future after I have added more systems that will prove the viability of this strategy.

DESIGN DOCUMENT TO THE RESCUE

Jul 28, 2025

Design document

Just like with any business application, it's critical to have some form of written specification about what you're making. Even without knowing the full design of the game yet, I made a design document with what I do have.

Design documents are LIVING! They are supposed to change over the course of production. However, changes should be made carefully and consciously. One of the benefits of having a design document is that it helps in keeping the vision together. Scope creep can be detrimental to a project. By constantly changing the parameters in which we are working, the milestones are constantly put off and deadlines never met.

To aid me in writing a design document, I decided to use AI. One of the best use cases for Large Language Models is obviously language! I began by writing a long paragraph of all the details I wanted to include in the document. Next I gave it to AI to format into a document for me. The result was surprisingly close to what I had envisioned. Once more, I could tell the AI to format the document into any of my choosing - PDF, Markdown, HTML, even DOCX!

With a design document in-hand, I am now ready to start developing the game. I don't have a name for it yet. Maybe once the story is fleshed out a bit more, an appropriate name will jump out at me.

SCHMUPS - HUMBLE BEGINNINGS

Jul 25, 2025

College project

"Shmups" (Shoot 'em ups) is a subgenre of action games started by popular arcade game Space Invaders. The first shmup I ever created was during a group project back at college in 2013. It was a two-player game with 4 waves and a boss battle at the end. Each player controlled a unique ship with special effects such as being able to rotate the gun arms for wider or more narrow bullet patterns. As a game programmer, I took a liking to the genre of schmups because they are relatively easy to make as a solo developer, are extremely engaging with potential for mastery, and are very extensible so you can have as few or many levels or features as you desire.

The goals I have for the schmup I'm making are very simple:

  1. Successfully implement core mechanics, demonstrating an understanding of the genre as well as proficiency in game development.
  2. Introduce a captivating story that leaves the player wanting more.
  3. Make it fun!

Currently, there's no design document. All I have is a fuzzy idea of what I want. If there's one thing I've learned from over a decade of programmer analysis work, it's that some kind of specification, even if very basic, makes a world of difference. That will be my next task.

Stay tuned for more!