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

Aim, distance, and angle showcase for <snes/math.h>. More...

#include <snes.h>
#include <snes/text.h>
#include <snes/math.h>
#include <snes/fixed32.h>
#include <snes/gameloop.h>

Macros

#define PLAYER_X   124
 Player position — fixed at screen centre.
#define PLAYER_Y   108

Functions

int main (void)
static void on_init (void)
static void on_update (void)

Variables

static s16 prev_target_x
 Previous target X — for change detection (skip text reformat when nothing moved).
static s16 prev_target_y
 Previous target Y — see prev_target_x.
static const u8 sprite_pal []
 Sprite palette — single palette shared by player and target.
static const u8 sprite_tiles [64]
 Two 8×8 sprite tiles in SNES 4bpp format (64 bytes total).
static s16 target_x
 Target X coordinate (movable, 0–247).
static s16 target_y
 Target Y coordinate (movable, 0–215).

Detailed Description

Aim, distance, and angle showcase for <snes/math.h>.

Demonstrates the four math primitives a 2D action game leans on the most: sqrt16 (pixel distance), atan2_8 (8-bit angle to a target), and the fixCos / fixSin LUTs (project a velocity vector along that angle). Everything updates live as the user moves the target with the D-pad — the numbers on screen are real arithmetic, not pre-baked.

The player ("P") sits at screen center. The target ("X") starts upper-right and follows the D-pad. Each frame the example recomputes dx/dy from the two positions, calls sqrt16(dx² + dy²) for the pixel distance, calls atan2_8(dy, dx) for the 8-bit angle, then calls fixCos and fixSin on that angle to read back the unit direction vector. All five values are printed live in the text panel above the play area.

SNES Concepts
  • <snes/math.h> square-root and atan2 (chantier B6, 2026-05-09):
    • sqrt16(n) → integer floor of √n, range 0–255
    • atan2_8(dy, dx) → 8-bit angle in the same convention as the sin/cos LUT (0 = +X, 64 = +Y, 128 = −X, 192 = −Y)
  • fixSin/fixCos LUT chaining: feed the atan2_8 output back into the trig LUT to recover a unit direction vector that points from player to target — the canonical pattern for projectile aiming, pursuit AI, and any "rotate sprite to face X" code.
  • Mode 0 + sprite overlay: BG1 hosts the text via the text module; the player and target are 8×8 OBJ sprites on the OBJ layer so they don't disturb the text display.
What to Observe
  • The "P" sprite stays anchored at the screen centre.
  • The "X" sprite follows the D-pad. Diagonal input moves diagonally — both axes update on the same frame.
  • As you move the target, the live readout panel updates on every frame:
    • DX / DY are the signed distances from player to target.
    • DIST is sqrt16(dx² + dy²), in pixels (0–255).
    • ANGLE is the 8-bit angle from the player to the target, printed in hex; the equivalent in degrees follows in parentheses (≈ angle × 360 / 256).
    • COS 8.8 / SIN 8.8 are the 8.8 fixed-point components of the unit direction vector. At ANGLE = 0x40 (90°, target is straight south) you see COS = 0x0000, SIN = 0x0100.
    • COS 16.16 / SIN 16.16 are the SAME values lifted to the new fix32 type from B5 (2026-05-21). Look at the bottom hex digits: they're always 00 because fix32Cos/fix32Sin reuse the 8.8 LUT and shift up. A future 16-bit LUT would fill those bits with real precision — the comparison row makes the 8-bit-LUT precision floor visible at runtime.
Before / after — fix32 demonstration
Pre-B5, this example only used fixCos/fixSin (8.8). The B5 chantier added the parallel fix32Cos/fix32Sin display rows so users can see the 16.16 representation alongside, with the trailing zeros that expose the LUT-lifting strategy. Not a functional change — a pedagogical one.
Modules Used
console, sprite, dma, background, text, input, gameloop, math, fixed32
See also
math.h, fixed32.h, sprite.h, text.h, gameloop.h

Macro Definition Documentation

◆ PLAYER_X

#define PLAYER_X   124

Player position — fixed at screen centre.

Made into a #define rather than a runtime variable so the compiler folds the constant into the dx/dy expressions and we don't pay a load+sub for a quantity that never changes.

◆ PLAYER_Y

#define PLAYER_Y   108

Function Documentation

◆ main()

int main ( void )

◆ on_init()

void on_init ( void )
static

◆ on_update()

void on_update ( void )
static

Variable Documentation

◆ prev_target_x

s16 prev_target_x
static

Previous target X — for change detection (skip text reformat when nothing moved).

◆ prev_target_y

s16 prev_target_y
static

Previous target Y — see prev_target_x.

◆ sprite_pal

const u8 sprite_pal[]
static
Initial value:
= {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0xFF, 0x7F,
}

Sprite palette — single palette shared by player and target.

Both sprites use palette 0; the visual difference between them is entirely the tile shape (diamond vs. X). Keeping the palette minimal trims four bytes off the CGRAM upload and avoids the second dmaCopyCGram call that an earlier draft used.

BGR555 layout: [R5G5B5] packed into two bytes, low byte first. Only colour 3 is rendered — the tile bitplanes above always resolve to index 3.

◆ sprite_tiles

const u8 sprite_tiles[64]
static
Initial value:
= {
0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18,
0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC3, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0xC3,
0xC3, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x66, 0xC3,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

Two 8×8 sprite tiles in SNES 4bpp format (64 bytes total).

Tile 0 ("P", player): a filled square edged with a dot — easy to spot at the screen centre.

Tile 1 ("X", target): a crosshair / plus sign — points at its own centre so the user knows exactly where the target's coordinate is.

Both tiles use bitplanes 0 and 1; planes 2 and 3 are zero so every drawn pixel is colour index 3 in the chosen palette.

◆ target_x

s16 target_x
static

Target X coordinate (movable, 0–247).

◆ target_y

s16 target_y
static

Target Y coordinate (movable, 0–215).