The Doom Loop and Tics

The Doom Loop and Tics

Doom is organized around a discrete simulation clock. The source does not update the world once for every rendered frame; instead, its game state advances in tics, and rendering is a presentation step layered around that progression. The central loop can be approached through linuxdoom-1.10/d_main.c, d_net.c, g_game.c, and p_tick.c.

Doom input, tic simulation, and display flow

The tic boundary

Input is collected into a ticcmd_t, whose definition is in d_ticcmd.h. The game layer consumes those commands through the game ticker, while the play simulation updates thinkers, players, movers, and world state. The important architectural point is that a render frame is not the authoritative unit of simulation. Rendering may occur whenever the display loop permits, but game rules are expressed in the discrete tic progression.

This arrangement supports demos and network synchronization because the meaningful input is compact and ordered. A replay need not record a screen image or every object transform; it records the command stream that drives the same deterministic simulation. The next state is consequently modeled as

$$ S_{t+1}=\operatorname{Tick}(S_t,\operatorname{cmd}_t). $$

The formula is abstract, but it corresponds directly to the separation between command construction, G_Ticker, and the play tickers.

Reading the loop

Begin in d_main.c to establish the display and main-loop context, then follow D_DoomLoop and the net/game calls into d_net.c. g_game.c owns the high-level game state transitions and tic command handling, while p_tick.c manages the thinker list that advances active world objects. This division explains why a feature may have one entry point in game code and another update function in play code: the former chooses what the game is doing, while the latter advances what exists in the level.