Loading...
Searching...
No Matches
gameloop.h File Reference

Opt-in game loop framework — write your update, the engine runs the VBlank synchronisation. More...

#include <snes/types.h>
#include <snes/scene.h>

Go to the source code of this file.

Typedefs

typedef Scene GameLoopConfig
 Game loop callbacks. Alias for Scene from <snes/scene.h>.
 

Functions

void gameLoopRun (const GameLoopConfig *cfg)
 Run the OpenSNES game loop. Never returns.
 

Detailed Description

Opt-in game loop framework — write your update, the engine runs the VBlank synchronisation.

One of the three "framework opt-ins" promised by PHILOSOPHY.md (alongside scene_2d and the asset bundle convention). This module exists to remove a single repetitive piece of SNES boilerplate:

while (1) {
// ... your update logic
}
void WaitForVBlank(void)
Wait for next VBlank period.

If that loop is the only thing standing between your main() and the work you actually want to write, drop in the framework:

static void onInit(void) {
// ... rest of your hardware init
}
static void onUpdate(void) {
u16 pad = padPressed(0);
// ... your per-frame logic
}
int main(void) {
GameLoopConfig cfg = { .init = onInit, .update = onUpdate };
gameLoopRun(&cfg);
return 0; // never reached — gameLoopRun never returns
}
int main(void)
Entry point — initialize audio, display controls, run transport loop.
Definition main.c:37
void consoleInit(void)
Initialize SNES hardware.
void setScreenOn(void)
Enable screen display.
void gameLoopRun(const GameLoopConfig *cfg)
Run the OpenSNES game loop. Never returns.
#define BG_MODE0
Definition video.h:27
unsigned short u16
16-bit unsigned integer (0 to 65535)
Definition types.h:52
u16 padPressed(u8 pad)
Get buttons pressed this frame.
A single scene's callbacks.
Definition scene.h:144
void(* init)(void)
Called once when the scene is first pushed onto the stack.
Definition scene.h:153
void setMode(u8 mode, u8 flags)
Set background mode.

The framework deliberately does very little. It does NOT call consoleInit() or setScreenOn() for you, NOT touch palettes, NOT configure the NMI handler. All of those remain caller-driven so the ABI stays the same as a hand-rolled main loop and any example you already have keeps compiling. What the framework owns is exactly: the while (1) WaitForVBlank(); update(); cadence.

When NOT to use this
  • You need a state machine that swaps the per-frame logic between distinct screens (title, gameplay, pause, game-over). Either dispatch from inside update, or use the scene module (D.3) — see <snes/scene.h>. GameLoopConfig is an alias for Scene, so promoting a single-loop game to a scene stack is a one-line change at the call site (gameLoopRun(&cfg)sceneRun(&cfg)).
  • You need a custom synchronisation rhythm (e.g. half-rate updates, double-buffered audio polling). Keep your hand-rolled loop — gameLoopRun is meant for the common case, not every case.
Performance

Each frame, gameLoopRun adds one indirect call (update via the cfg pointer) and one direct call (WaitForVBlank). On the order of 30 cycles per frame, dwarfed by anything update itself does. The compiler does not currently TCO the indirect call.

Modules required

gameloop (and its transitive dependency on the runtime). No other lib module is pulled in by gameLoopRun itself — what your init and update callbacks use is on you.

See also
system.h (WaitForVBlank, frame_count)

Typedef Documentation

◆ GameLoopConfig

Game loop callbacks. Alias for Scene from <snes/scene.h>.

GameLoopConfig and Scene (D.3) are the same type — both expose an init and update callback pair, both follow the same lifecycle contract (init once, update every VBlank). gameLoopRun accepts a 1-deep "single scene"; sceneRun adds the push/pop stack semantics on top.

The alias keeps the historical D.1 name available so existing examples and downstream code keep compiling unchanged. New code is encouraged to use Scene directly for vocabulary consistency across the framework trilogy.

Field documentation lives on the canonical Scene struct in <snes/scene.h>.

Function Documentation

◆ gameLoopRun()

void gameLoopRun ( const GameLoopConfig cfg)

Run the OpenSNES game loop. Never returns.

Equivalent to:

if (cfg->init) cfg->init();
while (1) {
cfg->update();
}
Parameters
cfgPointer to a GameLoopConfig. Must be non-NULL and must have a non-NULL update. init may be NULL to skip the init phase. The pointer is only consulted at the start of the loop and on each iteration's update; you may allocate cfg on the stack of main() since main does not return for as long as gameLoopRun runs.