Skip to content

Commit 76ea201

Browse files
authored
Cap main loop elapsed time instead of resetting it (#3178)
This change adjusts the way the main loop handles the game logic updates falling significantly behind real time. There are three main ways this can occur: a single, very slow operation (like loading a level); consistently slow game logic updates; and consistently slow rendering. By limiting the maximum number of logic steps per frame to 4, the main loop couples rendering and game updates together, making it practical to treat them being slow in the same way. Previously, when the `elapsed_time` difference between real-ish time and game time grew too large (> 8 steps), it would be reset to zero. This works OK for transient slow operations, but when the game logic or rendering runs just a bit slower than real time, the `elapsed_time` difference would slowly grow until hitting the threshold, be reset to zero, and then repeat, leading to a sort of sawtooth pattern. The number of game steps run in each loop iteration is roughly proportional to `elapsed_time` (with an upper limit), so the number of game steps per drawn frame would also have a sawtooth pattern (like 1,2,3,3,4,4,1...), perceivable as periodically shaky motion of the rendered scene. By capping the `elapsed_time` to a fixed value, instead of resetting it, this change eliminates the sawtooth pattern, making the game run more evenly. (It also now runs faster, when logic or render is slow, because the main loop can consistently use 3 or 4 steps per frame.) The cost is that, on normal transient lag spikes (startup, level load, sector switch) there may be multiple steps for the frame instead of zero; however, such lag spikes are rare, concealed by loading screens or safe regions, and do not occur during critical moments of game play.
1 parent 85b5864 commit 76ea201

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

src/supertux/screen_manager.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -556,11 +556,12 @@ void ScreenManager::loop_iter()
556556
g_real_time += 1e-9f * static_cast<float>(nsecs);
557557
last_time = now;
558558

559-
if (elapsed_time > seconds_per_step * 8) {
560-
// when the game loads up or levels are switched the
561-
// elapsed_ticks grows extremely large, so we just ignore those
562-
// large time jumps
563-
elapsed_time = 0;
559+
float max_elapsed_time = 4 * seconds_per_step;
560+
if (elapsed_time > max_elapsed_time) {
561+
// when the game loads up or levels are switched the elapsed_ticks grows
562+
// extremely large, so we just reduce those large time jumps to what can
563+
// be processed within a single frame.
564+
elapsed_time = max_elapsed_time;
564565
}
565566

566567
bool always_draw = g_debug.draw_redundant_frames || g_config->frame_prediction;

0 commit comments

Comments
 (0)