Timing & Game Loop Design

TIMER resets at midnight; handle the wrap for long-running programs:

26.1 Measuring time

TIMER resets at midnight; handle the wrap for long-running programs:

start = TIMER                           ' seconds since midnight (SINGLE)
FOR i = 1 TO 10000000: NEXT
PRINT "Elapsed:"; TIMER - start; "seconds"

t# = TIMER(.001)                        ' QB64: request millisecond accuracy
PRINT DATE$, TIME$                      ' "mm-dd-yyyy", "hh:mm:ss"
elapsed = TIMER - start
IF elapsed < 0 THEN elapsed = elapsed + 86400   ' crossed midnight

26.2 Waiting

wait for a keypress wait n seconds or until a key is pressed wait s seconds (fractions allowed, e.g., 0.25), not interrupted by keys (QB64) cap a loop's frequency, sleeping the remainder of each frame (QB64) ON TIMER(n) GOSUB label + TIMER ON call a handler every n seconds (event trapping)

Old programs used empty FOR loops for delays (FOR d = 1 TO 5000: NEXT) — this runs at different speeds on different computers. Never do it in new code.

26.3 The game loop

Every real-time program follows the same pattern:

Two ways to keep speed consistent:

Fixed frame rate with _LIMIT 60 and per-frame movement (x = x + 3). Simple; slows down if the computer can't keep up.

Delta time: measure the seconds since the last frame and scale movement (x = x + speed * dt). Consistent speed at any frame rate.

Initialize
DO
    Process input     (keyboard, mouse, gamepad)
    Update            (move objects, physics, AI, collisions, scoring)
    Render            (clear, draw world, draw HUD, _DISPLAY)
    Regulate timing   (_LIMIT or delta time)
LOOP UNTIL quitting
Shutdown
' Delta-time movement
prevT# = TIMER(.001)
DO
    nowT# = TIMER(.001)
    dt# = nowT# - prevT#: prevT# = nowT#
    IF dt# < 0 THEN dt# = dt# + 86400          ' midnight wrap
    IF dt# > 0.1 THEN dt# = 0.1                 ' clamp after pauses (window dragging, breakpoints)
    x = x + 200 * dt#                            ' 200 pixels per second
    ' ... render ...
    _LIMIT 240
LOOP

26.4 Game states with SELECT CASE

FreeBASIC: Timer (double precision), Sleep ms (milliseconds!), ScreenSync waits for vertical retrace, and Sleep 1, 1 yields CPU time in loops. VB.NET: Stopwatch for precise timing, System.Windows.Forms.Timer for UI events, Await Task.Delay(ms) for asynchronous waits; game loops typically run in Application.Idle or a game framework.

CONST STATE_TITLE = 1, STATE_PLAY = 2, STATE_OVER = 3
state = STATE_TITLE
DO
    SELECT CASE state
        CASE STATE_TITLE
            ' draw title; if Enter pressed then reset the game and state = STATE_PLAY
        CASE STATE_PLAY
            ' input, update, render; if lives = 0 then state = STATE_OVER
        CASE STATE_OVER
            ' show score; if Enter pressed then state = STATE_TITLE
    END SELECT
    _DISPLAY
    _LIMIT 60
LOOP UNTIL quitRequested