1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 17:06:04 +00:00
nescript/examples/pong/constants.ne
Claude 21b91f6398
examples/pong: production-quality Pong game with powerups and multi-ball
A complete, playable Pong game split across examples/pong/*.ne files
and pulled in from a top-level examples/pong.ne. Features:

- **Title screen** with a 3-option menu (CPU VS CPU / 1 PLAYER /
  2 PLAYERS), a cursor sprite, blinking "PRESS A" prompt, brisk
  title march on pulse 2, and autopilot that auto-confirms CPU VS
  CPU after 45 frames of no input so the headless jsnes golden
  harness reaches gameplay by frame 180.

- **Ball physics** with signed-magnitude velocity (u8 magnitude +
  sign bit per axis), wall bounce at top/bottom, paddle AABB
  collision with push-out, and score-out detection at left/right
  exits.

- **Multi-ball** via parallel ball_* arrays (MAX_BALLS = 3). Each
  ball scores a point independently; the round continues until the
  last ball exits the playfield.

- **CPU AI** that tracks the nearest active ball heading toward its
  side with a per-frame step, 4 px dead zone, and CPU_SPEED = 1 so
  rallies can end naturally.

- **Three powerup types** that spawn every ~4 seconds, bounce off
  all four walls, and are caught by paddle AABB overlap:
  1. LONG — extends the catching paddle from 24 → 40 px for 5 hits
  2. FAST — doubles ball x-velocity on the catcher's next hit
  3. MULTI — spawns two extra balls on the catcher's next hit

- **Victory** at first-to-7 with a "PLAYER N WINS" banner and the
  builtin fanfare, auto-returning to Title.

- **Audio**: 5 user-declared sfx (WallBounce, PaddleHit, Score,
  PowerSpawn, PowerCatch) plus a title march and the builtin
  fanfare for victory.

Source layout mirrors examples/war:

    examples/pong.ne               top-level game shell
    examples/pong/PLAN.md          living design doc
    examples/pong/constants.ne     layout + gameplay constants
    examples/pong/assets.ne        45-tile Tileset (paddles, ball, alphabet,
                                   digits, cursor, center-line, powerup icons)
    examples/pong/audio.ne         sfx + music declarations
    examples/pong/state.ne         all mutable globals
    examples/pong/rng.ne           8-bit Galois LFSR
    examples/pong/render.ne        draw helpers
    examples/pong/input.ne         paddle step (human + CPU AI)
    examples/pong/ball.ne          multi-ball physics + paddle collision
    examples/pong/powerup.ne       powerup entity (spawn, bounce, catch, apply)
    examples/pong/title_state.ne   state Title + menu
    examples/pong/play_state.ne    state Playing (P_SERVE/P_PLAY/P_POINT)
    examples/pong/victory_state.ne state Victory

Verification:
- 616 compiler unit tests pass (cargo test --all-targets)
- cargo fmt / cargo clippy --all-targets -- -D warnings clean
- 33/33 emulator harness goldens match
- examples/pong.nes builds byte-identically from source

https://claude.ai/code/session_0134F5uwDEVTes2Ee9S7JeXy
2026-04-16 01:25:29 +00:00

135 lines
5.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// pong/constants.ne — layout, gameplay, powerup, and phase constants.
//
// Everything that feeds Pong's positional layout, animation timing,
// powerup machine, or score tracking lives here so one central edit
// can retune the whole game. No code, just `const` entries.
// ── Playfield layout ──────────────────────────────────────
//
// The NES screen is 256×240. We leave the top 16 px for the HUD
// score strip and the bottom 24 px as a buffer, giving a 200 px
// tall playfield from y = 16 to y = 216.
const PLAYFIELD_TOP: u8 = 16
const PLAYFIELD_BOTTOM: u8 = 216
const PLAYFIELD_LEFT: u8 = 0
const PLAYFIELD_RIGHT: u8 = 248
// ── Paddles ──────────────────────────────────────────────
//
// Paddles are 8 px wide. Normal height is 24 px (3 tiles), long
// mode bumps to 40 px (5 tiles). Paddle y is the top edge.
const PADDLE_W: u8 = 8
const PADDLE_H: u8 = 24
const PADDLE_H_LONG:u8 = 40
const LEFT_PADDLE_X: u8 = 16 // fixed x for the left paddle
const RIGHT_PADDLE_X: u8 = 232 // fixed x for the right paddle
// Human paddle speed and CPU tracking speed.
const PADDLE_SPEED: u8 = 2
const CPU_SPEED: u8 = 1
// When a powerup is caught by a paddle, the catching paddle gets
// LONG_PADDLE_HITS worth of extended-height paddle.
const LONG_PADDLE_HITS: u8 = 5
// ── Ball ─────────────────────────────────────────────────
//
// 8×8 sprite. Position is the top-left corner. Velocity is a
// per-axis (magnitude, sign) pair — u8 magnitude + u8 sign bit
// (0 = positive / +x right / +y down, 1 = negative).
const BALL_SIZE: u8 = 8
const BALL_BASE_DX: u8 = 1
const BALL_BASE_DY: u8 = 1
const BALL_FAST_DX: u8 = 2
const MAX_BALLS: u8 = 3
// ── Powerup ──────────────────────────────────────────────
//
// One powerup active at a time. Spawns periodically, bounces
// around for a while, despawns if nobody catches it.
const POWERUP_SIZE: u8 = 8
const POWERUP_SPEED: u8 = 1
const POWERUP_SPAWN_FRAMES: u16 = 240 // ~4 s at 60 Hz
const POWERUP_LIFE_FRAMES: u16 = 480 // ~8 s before despawn
const PWR_NONE: u8 = 0
const PWR_LONG: u8 = 1
const PWR_FAST: u8 = 2
const PWR_MULTI: u8 = 3
const PWR_KINDS: u8 = 3 // number of real kinds (LONG / FAST / MULTI)
// ── Sides ────────────────────────────────────────────────
//
// Side indexing for the two paddles. Used by input, AI,
// collision, powerup apply, and victory.
const SIDE_LEFT: u8 = 0
const SIDE_RIGHT: u8 = 1
// ── Scoring ──────────────────────────────────────────────
const WIN_SCORE: u8 = 7
// ── HUD ──────────────────────────────────────────────────
//
// Score digits at the top of the screen, 2 digits per side.
const SCORE_LEFT_X: u8 = 88
const SCORE_RIGHT_X: u8 = 152
const SCORE_Y: u8 = 16
// ── Title menu ───────────────────────────────────────────
const MODE_CPU_VS_CPU: u8 = 0
const MODE_HUMAN_VS_CPU: u8 = 1
const MODE_HUMAN_VS_HUMAN:u8 = 2
// Title autopilot: if no input for this many frames, the menu
// commits to CPU VS CPU so the headless golden harness always
// reaches gameplay.
const TITLE_AUTO_FRAMES: u8 = 45
// ── Phase machine (state Playing) ────────────────────────
//
// Explicit constants instead of an enum to keep names from
// colliding with state names.
const P_SERVE: u8 = 0
const P_PLAY: u8 = 1
const P_POINT: u8 = 2
// Frames spent in each non-PLAY phase.
const FRAMES_SERVE: u8 = 60 // 1 s countdown before the ball launches
const FRAMES_POINT: u8 = 40 // 0.67 s pause after a point
const VICTORY_LINGER_FRAMES: u16 = 240 // 4 s on the victory screen
// ── Tile indices into the Tileset sprite ─────────────────
//
// Every `draw Tileset frame: N` call in render.ne uses a constant
// from this block. If you add or remove a tile in assets.ne, move
// the constants too.
// Tile 0 is the builtin smiley that the linker reserves; every
// custom tile starts at 1.
// Alphabet A-Z at indices 1..26 (A = 1, Z = 26).
const TILE_LETTER_BASE: u8 = 1
// Digits 0-9 at indices 27..36 (0 = 27).
const TILE_DIGIT_BASE: u8 = 27
// Paddle body — top cap / mid / bottom cap.
const TILE_PADDLE_TOP: u8 = 37
const TILE_PADDLE_MID: u8 = 38
const TILE_PADDLE_BOT: u8 = 39
// Ball (8×8 filled circle).
const TILE_BALL: u8 = 40
// Cursor (▶) for the title menu.
const TILE_CURSOR: u8 = 41
// Center-line dash (8×8 vertical bar).
const TILE_CENTER_DASH: u8 = 42
// Powerup icons — one tile per powerup kind. Indexed as
// TILE_POWERUP_BASE + (kind - 1), so LONG = +0, FAST = +1,
// MULTI = +2.
const TILE_POWERUP_BASE: u8 = 43