1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-07 00:22:50 +00:00
nescript/examples/pong.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

100 lines
4.2 KiB
Text

// Pong — a full NES port of the classic two-paddle game.
//
// Production-quality example: a title screen with a three-option
// menu (CPU VS CPU / 1 PLAYER / 2 PLAYERS), live gameplay with
// smooth ball physics and two paddles, powerups that bounce
// around the playfield and modify gameplay when caught
// (long paddle / fast ball / multi-ball), a victory screen with
// a fanfare, and a brisk title march. Every piece of the game
// (logic, art, sound, states) is authored in NEScript itself —
// no external assets, no external tooling.
//
// The source is split across examples/pong/*.ne files. This
// top-level file declares the hardware config, the reset-time
// palette and Tileset, the audio/state/logic includes, and the
// `start` declaration. Every include is processed by the parser
// before lexing, so it's exactly as if the whole game lived in
// one .ne file.
//
// The file layout mirrors how a real NES game would be organised:
//
// examples/pong.ne — this file, the top-level game
// examples/pong/PLAN.md — living implementation plan
// examples/pong/constants.ne — layout + gameplay constants
// examples/pong/assets.ne — Tileset sprite block
// examples/pong/audio.ne — sfx + music
// examples/pong/state.ne — global variables
// examples/pong/rng.ne — 8-bit Galois LFSR PRNG
// examples/pong/render.ne — draw helpers
// examples/pong/input.ne — paddle update (M2+)
// examples/pong/ball.ne — ball physics (M3+)
// examples/pong/powerup.ne — powerup entity (M8+)
// examples/pong/title_state.ne — state Title + menu
// examples/pong/play_state.ne — state Playing (inner SERVE/PLAY/POINT phase machine)
// examples/pong/victory_state.ne — state Victory
//
// Controls (humans):
// D-pad up/down — move your paddle up/down
// A / Start — confirm a menu choice
// / return to title from the victory screen
//
// In CPU-vs-CPU mode both paddles are CPU and the game plays
// itself; in 1 PLAYER mode you are the left paddle and the CPU is
// the right; in 2 PLAYERS mode both sides are human (P1 left,
// P2 right). The headless jsnes golden harness boots straight
// into CPU VS CPU (title auto-commits after ~45 frames with no
// input) so the captured frame is always a scene from actual
// gameplay.
//
// Build: cargo run --release -- build examples/pong.ne
// Output: examples/pong.nes
game "Pong" {
mapper: NROM
mirroring: horizontal
}
// ── Palette ─────────────────────────────────────────────────
//
// Classic Pong is a black field with white paddles and white
// ball. We add a yellow accent for powerup icons and the menu
// cursor so those read as distinct without growing the sprite
// sub-palette budget (sprites all share sp0 in NEScript's
// codegen).
//
// Sprite sub-palette 0 vocabulary:
// 0 = transparent
// 1 = white (paddles, ball, letters, digits)
// 2 = lt_gray (reserved for subtle secondary accents)
// 3 = yellow (cursor, powerup icons)
palette Main {
universal: black
bg0: [dk_gray, lt_gray, white] // center line + score gutters
bg1: [dk_blue, blue, sky_blue] // reserved — P1 side accent
bg2: [dk_red, red, peach] // reserved — P2 side accent
bg3: [dk_olive,olive, yellow] // reserved — powerup flash
sp0: [white, lt_gray, yellow] // every sprite uses this
sp1: [dk_blue, blue, sky_blue] // reserved
sp2: [dk_red, red, peach] // reserved
sp3: [dk_gray, lt_gray, white] // reserved
}
// Pull in everything else. Order matters only for symbol visibility:
// constants before the state variables that use them, state variables
// and helpers before state handlers.
include "pong/constants.ne"
include "pong/assets.ne"
include "pong/audio.ne"
include "pong/state.ne"
include "pong/rng.ne"
include "pong/render.ne"
include "pong/input.ne"
include "pong/ball.ne"
include "pong/powerup.ne"
include "pong/title_state.ne"
include "pong/play_state.ne"
include "pong/victory_state.ne"
start Title