mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 08:55:38 +00:00
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
458 lines
10 KiB
Text
458 lines
10 KiB
Text
// pong/assets.ne — the one big Tileset sprite block.
|
||
//
|
||
// Every custom 8×8 CHR tile in Pong is stacked vertically inside a
|
||
// single `sprite Tileset { pixels: [...] }` declaration. The parser
|
||
// splits each consecutive 8 rows into its own tile, so tile index N
|
||
// in a `draw Tileset frame: N` call picks the N'th block.
|
||
//
|
||
// Every constant in constants.ne points at a position in this list.
|
||
// If you add or remove a tile, update BOTH this file AND the matching
|
||
// constant range.
|
||
//
|
||
// Colour vocabulary (sp0 sub-palette in pong.ne):
|
||
// . transparent
|
||
// 1 white (paddles, ball, alphabet, digits)
|
||
// 2 lt_gray (reserved — subtle accents)
|
||
// 3 yellow (powerup icons, cursor highlight)
|
||
|
||
sprite Tileset {
|
||
pixels: [
|
||
// ── 01-26: alphabet A..Z (6-wide bold on transparent) ─
|
||
//
|
||
// Bold sans-serif letters with 2-pixel strokes so they
|
||
// still read on a CRT. Every letter is 6 wide, centred
|
||
// in the 8-wide tile. This block is the same shape as
|
||
// war's alphabet so a future refactor could lift it into
|
||
// a shared include.
|
||
|
||
// A
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".111111.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"........",
|
||
// B
|
||
"........",
|
||
".11111..",
|
||
".11..11.",
|
||
".11111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11111..",
|
||
"........",
|
||
// C
|
||
"........",
|
||
"..11111.",
|
||
".11..11.",
|
||
".11.....",
|
||
".11.....",
|
||
".11..11.",
|
||
"..11111.",
|
||
"........",
|
||
// D
|
||
"........",
|
||
".1111...",
|
||
".11.11..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11.11..",
|
||
".1111...",
|
||
"........",
|
||
// E
|
||
"........",
|
||
".111111.",
|
||
".11.....",
|
||
".11111..",
|
||
".11.....",
|
||
".11.....",
|
||
".111111.",
|
||
"........",
|
||
// F
|
||
"........",
|
||
".111111.",
|
||
".11.....",
|
||
".11111..",
|
||
".11.....",
|
||
".11.....",
|
||
".11.....",
|
||
"........",
|
||
// G
|
||
"........",
|
||
"..11111.",
|
||
".11.....",
|
||
".11.111.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// H
|
||
"........",
|
||
".11..11.",
|
||
".11..11.",
|
||
".111111.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"........",
|
||
// I
|
||
"........",
|
||
"..1111..",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"..1111..",
|
||
"........",
|
||
// J
|
||
"........",
|
||
"....111.",
|
||
".....11.",
|
||
".....11.",
|
||
".....11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// K
|
||
"........",
|
||
".11..11.",
|
||
".11.11..",
|
||
".1111...",
|
||
".11.11..",
|
||
".11..11.",
|
||
".11..11.",
|
||
"........",
|
||
// L
|
||
"........",
|
||
".11.....",
|
||
".11.....",
|
||
".11.....",
|
||
".11.....",
|
||
".11.....",
|
||
".111111.",
|
||
"........",
|
||
// M
|
||
"........",
|
||
".11..11.",
|
||
".111111.",
|
||
".111111.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"........",
|
||
// N
|
||
"........",
|
||
".11..11.",
|
||
".111.11.",
|
||
".111111.",
|
||
".11.111.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"........",
|
||
// O
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// P
|
||
"........",
|
||
".11111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11111..",
|
||
".11.....",
|
||
".11.....",
|
||
"........",
|
||
// Q
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11.111.",
|
||
".11.11..",
|
||
"..111.1.",
|
||
"........",
|
||
// R
|
||
"........",
|
||
".11111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11111..",
|
||
".11.11..",
|
||
".11..11.",
|
||
"........",
|
||
// S
|
||
"........",
|
||
"..11111.",
|
||
".11.....",
|
||
"..1111..",
|
||
".....11.",
|
||
".....11.",
|
||
".11111..",
|
||
"........",
|
||
// T
|
||
"........",
|
||
".111111.",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"........",
|
||
// U
|
||
"........",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// V
|
||
"........",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"...11...",
|
||
"........",
|
||
// W
|
||
"........",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".111111.",
|
||
".111111.",
|
||
".11..11.",
|
||
"........",
|
||
// X
|
||
"........",
|
||
".11..11.",
|
||
"..1111..",
|
||
"...11...",
|
||
"...11...",
|
||
"..1111..",
|
||
".11..11.",
|
||
"........",
|
||
// Y
|
||
"........",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"........",
|
||
// Z
|
||
"........",
|
||
".111111.",
|
||
".....11.",
|
||
"....11..",
|
||
"...11...",
|
||
"..11....",
|
||
".111111.",
|
||
"........",
|
||
|
||
// ── 27-36: digits 0..9 ────────────────────────────
|
||
// 0
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// 1
|
||
"........",
|
||
"...11...",
|
||
"..111...",
|
||
".1.11...",
|
||
"...11...",
|
||
"...11...",
|
||
"..1111..",
|
||
"........",
|
||
// 2
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
".....11.",
|
||
"....11..",
|
||
"..11....",
|
||
".111111.",
|
||
"........",
|
||
// 3
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
"....11..",
|
||
".....11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// 4
|
||
"........",
|
||
"....11..",
|
||
"...111..",
|
||
"..1.11..",
|
||
".11.11..",
|
||
".111111.",
|
||
"....11..",
|
||
"........",
|
||
// 5
|
||
"........",
|
||
".111111.",
|
||
".11.....",
|
||
".11111..",
|
||
".....11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// 6
|
||
"........",
|
||
"..1111..",
|
||
".11.....",
|
||
".11111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// 7
|
||
"........",
|
||
".111111.",
|
||
".....11.",
|
||
"....11..",
|
||
"...11...",
|
||
"..11....",
|
||
"..11....",
|
||
"........",
|
||
// 8
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
"..1111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..1111..",
|
||
"........",
|
||
// 9
|
||
"........",
|
||
"..1111..",
|
||
".11..11.",
|
||
".11..11.",
|
||
"..11111.",
|
||
".....11.",
|
||
"..1111..",
|
||
"........",
|
||
|
||
// ── 37: paddle top cap ────────────────────────────
|
||
//
|
||
// Paddles are 8 px wide and an integer number of tiles
|
||
// tall. Each paddle is rendered as TOP + (N-2) × MID + BOT,
|
||
// where N is 3 in normal mode (24 px) or 5 in long mode
|
||
// (40 px). The cap tiles are rounded at the outer edge so
|
||
// the paddle doesn't look like a blunt slab.
|
||
"..1111..",
|
||
".111111.",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
// ── 38: paddle middle (repeated for tall paddles) ─
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
// ── 39: paddle bottom cap ─────────────────────────
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
"11111111",
|
||
".111111.",
|
||
"..1111..",
|
||
|
||
// ── 40: ball ──────────────────────────────────────
|
||
//
|
||
// 6×6 filled circle centred in the 8×8 tile.
|
||
"........",
|
||
"..1111..",
|
||
".111111.",
|
||
".111111.",
|
||
".111111.",
|
||
".111111.",
|
||
"..1111..",
|
||
"........",
|
||
|
||
// ── 41: cursor arrow (▶) ─────────────────────────
|
||
//
|
||
// Yellow-tinted so it pops against white menu text.
|
||
"........",
|
||
"..3.....",
|
||
"..33....",
|
||
"..333...",
|
||
"..333...",
|
||
"..33....",
|
||
"..3.....",
|
||
"........",
|
||
|
||
// ── 42: center-line dash ──────────────────────────
|
||
//
|
||
// A vertical 2-px stripe down the centre column of the
|
||
// tile. Repeated every 32 px vertically to form the
|
||
// classic Pong dashed divider.
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
"...11...",
|
||
|
||
// ── 43: powerup LONG icon ─────────────────────────
|
||
//
|
||
// A yellow "L" on a framed background. The frame is
|
||
// white so the icon reads against the black playfield.
|
||
"11111111",
|
||
"13....31",
|
||
"13.3..31",
|
||
"13.3..31",
|
||
"13.3..31",
|
||
"13.3333.",
|
||
"13....31",
|
||
"11111111",
|
||
// ── 44: powerup FAST icon (F) ─────────────────────
|
||
"11111111",
|
||
"13....31",
|
||
"13.3333.",
|
||
"13.3..31",
|
||
"13.333.1",
|
||
"13.3..31",
|
||
"13.3..31",
|
||
"11111111",
|
||
// ── 45: powerup MULTI icon (M) ────────────────────
|
||
"11111111",
|
||
"13....31",
|
||
"13.3.3.1",
|
||
"13.333.1",
|
||
"13.3.3.1",
|
||
"13.3.3.1",
|
||
"13.3.3.1",
|
||
"11111111"
|
||
]
|
||
}
|