OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
main.c File Reference

Game skeleton — the smallest complete game: title -> play -> over. More...

#include <snes.h>
#include <snes/input.h>

Macros

#define PLAYER_SPEED   2
#define PX_MAX   240
#define PX_MIN   8
#define PY_MAX   208
#define PY_MIN   24
#define SPR_VRAM   0x4000
#define ST_OVER   2
#define ST_PLAY   1
#define ST_TITLE   0
 Game states — the whole game is a switch over these.
#define START_TIME   30
#define TILE_COIN   1
#define TILE_PLAYER   0

Functions

static void build_tile (const u8 *rows, u8 idx, u16 tile)
 Build an 8x8 tile from an 8-row bitmap, using palette index idx.
static void draw_hud_labels (void)
 Print the fixed HUD labels once (numbers refreshed as they change).
static void draw_score (void)
 Refresh the SCORE number (clear the field first so it never smears).
static void draw_sprites (void)
 Draw the two gameplay sprites into the OAM buffer.
static void draw_time (void)
 Refresh the TIME number.
static void encode_4bpp (void)
 Pack pixbuf[] (8x8 palette indices) into a 4bpp planar tile.
int main (void)
static void show_over (void)
 Game-over screen.
static void show_title (void)
 Title screen text.
static void spawn_coin (void)
 Move the coin to a fresh pseudo-random spot.
static void start_game (void)
 Enter the play state: reset score/timer, centre the player.
static void update_play (u16 held)
 One frame of gameplay.

Variables

static u8 cx
static u8 cy
u8 game_state
 Probe oracle: current state (0 title, 1 play, 2 over).
static u8 pixbuf [64]
static u8 px
static u8 py
u16 score
 Probe oracle: coins collected.
static u16 seed_ctr
static u8 tick
static u8 tilebuf [32]
u8 time_left
 Probe oracle: seconds remaining in a round.

Detailed Description

Game skeleton — the smallest complete game: title -> play -> over.

The capstone the curriculum was missing: not a feature demo but the shape of a whole game, small enough to read in one sitting and fork for your own. It recombines the rungs you've climbed — input drives a sprite, a second sprite is a goal, a bounding-box test scores it, text is the HUD, and a hand-rolled state machine ties title, play and game-over together.

The one structural idea: a game is a state machine around one loop. Every frame you WaitForVBlank(), read the pad, then switch (game_state) to the code for the screen you're on. Transitions are just assignments to game_state plus a one-time setup for the new screen. That is the skeleton under every SNES game; basics/scene_stack shows the same idea lifted into the opt-in scene framework once the enum + switch starts to sprawl.

The game: steer the arrow with the D-pad, touch the coin to score, before the timer runs out. Zero assets — both sprites are built in C.

ROM mode: LoROM (project default).

Controls
  • Title / Game over: START to begin / play again
  • Play: D-pad to move; touch the coin to score
SNES Concepts
  • The frame loop: WaitForVBlank -> read input -> update -> the NMI flushes
  • A plain enum + switch state machine (title / play / over)
  • Sprites (player + coin) via the OAM buffer; text HUD via the auto-flush
  • Bounding-box collision; rand()/srand() seeded for varied coin spawns
What to Observe
Title shows "PRESS START". In play, moving onto the coin bumps SCORE and respawns it; TIME counts down; at zero the game-over screen shows the final score. game_state, score, time_left are the probe oracles.
Modules Used
console, dma, background, sprite, text, input
See also
examples/basics/scene_stack — the same idea via the scene framework

Macro Definition Documentation

◆ PLAYER_SPEED

#define PLAYER_SPEED   2

◆ PX_MAX

#define PX_MAX   240

◆ PX_MIN

#define PX_MIN   8

◆ PY_MAX

#define PY_MAX   208

◆ PY_MIN

#define PY_MIN   24

◆ SPR_VRAM

#define SPR_VRAM   0x4000

sprite tiles (text font is at $0000)

◆ ST_OVER

#define ST_OVER   2

◆ ST_PLAY

#define ST_PLAY   1

◆ ST_TITLE

#define ST_TITLE   0

Game states — the whole game is a switch over these.

◆ START_TIME

#define START_TIME   30

seconds on the clock

◆ TILE_COIN

#define TILE_COIN   1

◆ TILE_PLAYER

#define TILE_PLAYER   0

Function Documentation

◆ build_tile()

void build_tile ( const u8 * rows,
u8 idx,
u16 tile )
static

Build an 8x8 tile from an 8-row bitmap, using palette index idx.

< sprite tiles (text font is at $0000)

◆ draw_hud_labels()

void draw_hud_labels ( void )
static

Print the fixed HUD labels once (numbers refreshed as they change).

◆ draw_score()

void draw_score ( void )
static

Refresh the SCORE number (clear the field first so it never smears).

◆ draw_sprites()

void draw_sprites ( void )
static

Draw the two gameplay sprites into the OAM buffer.

◆ draw_time()

void draw_time ( void )
static

Refresh the TIME number.

◆ encode_4bpp()

void encode_4bpp ( void )
static

Pack pixbuf[] (8x8 palette indices) into a 4bpp planar tile.

◆ main()

int main ( void )

< sprite tiles (text font is at $0000)

◆ show_over()

void show_over ( void )
static

Game-over screen.

◆ show_title()

void show_title ( void )
static

Title screen text.

◆ spawn_coin()

void spawn_coin ( void )
static

Move the coin to a fresh pseudo-random spot.

◆ start_game()

void start_game ( void )
static

Enter the play state: reset score/timer, centre the player.

< seconds on the clock

◆ update_play()

void update_play ( u16 held)
static

One frame of gameplay.

Variable Documentation

◆ cx

u8 cx
static

◆ cy

u8 cy
static

◆ game_state

u8 game_state

Probe oracle: current state (0 title, 1 play, 2 over).

◆ pixbuf

u8 pixbuf[64]
static

◆ px

u8 px
static

◆ py

u8 py
static

◆ score

u16 score

Probe oracle: coins collected.

◆ seed_ctr

u16 seed_ctr
static

◆ tick

u8 tick
static

◆ tilebuf

u8 tilebuf[32]
static

◆ time_left

u8 time_left

Probe oracle: seconds remaining in a round.