You'd think a game loop wouldn't be a hard thing.
while(true) {
process_input();
update_game_logic();
render();
}
That can be adequate for a lot of simple games, but the cool thing to do is to decouple the update calls from the render calls, update on a fixed (sim) clock, and render as often as you can, using a very lightweight interpolation inside the render loop to smooth the trajectories between update calls.
In particular, I'm using a version from Robert Nystrom's "Game Programming Patterns", which looks like this in my language:
loop {
float currentTime = get_current_time();
float elapsedTime = currentTime - previousTime;
previousTime = currentTime;
lag = lag + elapsedTime;
sdl_tick_input();
if (sdl_quit_signalled() == 1) {
break;
}
while (lag >= SECONDS_PER_UPDATE) {
update();
lag = lag - SECONDS_PER_UPDATE;
updates = updates + 1;
}
float alpha = lag / SECONDS_PER_UPDATE;
draw(alpha);
renders = renders + 1;
}
The nice thing about this is that the updates are always at a fixed rate, so the simulations don't go unstable, and you still get to render as often as your machine is capable of. I could stick an artificial delay in there to keep the frame rate from going too high (rarely a problem, but if I wanted to conserve battery power on portable devices (phones, tablets, laptops) it might be worth considering.
Several bits that I ran into along the way that I need to clean up:
- I'm being sloppy about pointers within my compiler. I just throw an extra load() to dereference the pointer, and things seem to work out, but it feels super sloppy.
- I'm getting a segmentation fault about 13 seconds into the run. Don't know why that is, but it's reproducible. Which is a nice thing for a crash bug.
- I've got user-defined data types (let's call them "structs"). But if I create them at global scope, they don't get linked properly. Gotta figure that out.
I was hoping to get the ship to fly around with simulated intention by this point. That's soon, but not yet, I guess.