Core Game Loops in Nim with Unhygenic Templates
Created on 2022-07-21T19:07:46-05:00
Offers a template which handles the core inner loop of a game engine. Uses unhygenic symbol injection to insert functions that may be called within a limited scope. Those functions are themselves templates meaning the entire rig is short-hand which is compiled as the loops would have been written in C anyway.
## Things essential for any game out there. This module also has a few ## submodules for things that didn't fit into any other category: ## ## - ``rapid/game/tilemap`` – tilemap with collision detection import std/monotimes import std/times template runGameWhile*(cond: bool, body: untyped, updateFreq: float32 = 60): untyped = ## Starts a fixed timestep game loop. ## There are two important templates available inside the loop: ## ## - ``update: `` – anything inside the `` runs at a constant ## tick rate of ``updateFreq`` ## - ``draw: `` – calculates the interpolation coefficient ## ` ` and passes it to the `` ## ## There are also a few variables available inside the loop: ## ## - ``time: float64`` – time elapsed since the start of the loop, in seconds ## - ``delta: float64`` – time elapsed since the last frame, in seconds ## - ``secondsPerUpdate: float32`` – time between updates ## ## **Example:** ## ## .. code-block:: nim ## ## import std/os ## ## runGameWhile true: # the condition is usually ``not win.closeRequested`` ## echo (time: time, delta: delta) ## ## # process input here ## ## update: ## # tick your entities here ## ## draw step: ## # draw your entities here ## ## sleep(20) # this is fulfilled by ``frame.finish()``, but we don't have ## # a window in this example block: var startTime = getMonoTime() previousTime = getMonoTime() lag: float32 = 0.0 while cond: let currentTime = getMonoTime() delta {.inject.} = float32(inMilliseconds(currentTime - previousTime).float64 * 0.001) previousTime = currentTime lag += delta let time {.inject.} = inMilliseconds(currentTime - startTime).float64 * 0.001 secondsPerUpdate {.inject.} = 1'f32 / updateFreq template update(updateBody: untyped): untyped {.inject.} = block: while lag >= secondsPerUpdate: updateBody lag -= secondsPerUpdate template draw(stepName, drawBody: untyped): untyped {.inject.} = block: let stepName {.inject.} = lag / secondsPerUpdate drawBody body when isMainModule: import std/os runGameWhile true: echo (time: time, delta: delta) update: echo "running update" draw step: echo "drawing with step ", step sleep(20)