1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 08:55:38 +00:00

platformer: move HUD from sprite OAM slots to background + sprite-0 split

The status bar now paints into NT row 1 (coin + score digits on
the left, heart + lives digit on the right) using the `bg3`
sub-palette that matches `sp0` pixel-for-pixel. A single OAM
slot-0 anchor sprite sits over the coin tile; its one opaque
pixel lines up with the coin's bottom row so sprite-0 hit fires
at scanline 15, and a trailing `sprite_0_split(camera_x, 0)`
latches the playfield scroll starting at scanline 16. NT rows
0-1 stay pinned while scanlines 16+ scroll with the camera.

Score / lives updates are shadow-compared (`last_score`,
`last_lives`) so the VRAM ring sees an entry only when the
backing state actually changes — most frames append zero bytes.
OAM footprint drops from 5 sprites per frame down to 1.

Tile pipeline gains a 27th entry — a 7-transparent-row + 1-pixel
anchor — so the sprite-0 hit lands on scanline 15 instead of
scanline 8 (the latter would smear the HUD glyphs across the
split). `gen_platformer_tiles.rs` is updated in lockstep.

Ancillary changes: `bg3` retuned from `[yellow, orange,
dk_orange]` to `[red, orange, white]` (matching `sp0`);
`palette_map` row 0 flips from bg0 to bg3; legend gains `o`, `h`,
`0`, `3` so the initial map can preload the static HUD tiles and
the committed nametable already reads "coin 00 ... heart 3" on
frame 0.

`docs/future-work.md` loses the sprite-0 HUD follow-up section
(this commit lands it). Goldens + gif refreshed.
This commit is contained in:
Claude 2026-04-20 17:21:20 +00:00
parent 91f82c169a
commit c5b04c2065
No known key found for this signature in database
9 changed files with 165 additions and 89 deletions

View file

@ -260,47 +260,6 @@ missing:
call — would shave a few bytes more on programs with many deep
handlers.
### `examples/platformer.ne` HUD — move from sprites to sprite-0 hit
The platformer currently renders its status bar as five OAM
sprites re-emitted every frame inside `draw_hud()`. That works but
burns 5/64 OAM slots on static UI and forces the redraw path to
walk the HUD every tick even when `score` / `lives` haven't
changed. The clean upgrade is to paint the HUD into the top row of
the nametable and use a sprite-0 hit split (same pattern as
`examples/sprite_0_split_demo.ne`) to reset the X-scroll at the
HUD/playfield boundary so the rest of the screen can keep
scrolling freely. Target shape:
1. Pre-paint row 0 of the nametable with `Bar` + glyph tiles via
an `on enter` one-shot that drops `nt_set` / `nt_fill_h`
writes into the VRAM ring — same shape as
`examples/hud_demo.ne`.
2. Place sprite 0 as a 1-pixel-wide invisible dot on the last
scanline of the HUD row; the PPU sets the sprite-0 hit flag
when rendering crosses it.
3. Poll the flag in `on frame` and latch `scroll(camera_x, 0)`
only after the hit, leaving the HUD painted with scroll=0 for
the top rows.
4. Replace the four in-frame `draw Tileset at: (…HUD…)` calls
with a shadow-compare `if score != last_score { nt_set(...) }`
pair (score digits) + `if lives != last_lives { nt_set(...) }`
(heart row). Most frames write nothing.
5. The palette row at metatile y=0 needs a dedicated sub-palette
so the HUD doesn't inherit the sky/brick/ground attribute
zones — add it to `palette_map` in row 0.
6. Shadow variables `last_score` / `last_lives` initialize to
`255` so the first frame paints unconditionally.
Wins: 5 OAM slots back for enemies/particles, no per-frame HUD
draw cost, and the flagship demo actually exercises sprite-0 hit
in a real game (the standalone `sprite_0_split_demo.ne` stays as
the minimal pedagogical example). Still NROM — no mapper change.
Blocker to track: the HUD reads `stomp_count` as a u8 decimal;
when this lands, plumb it through whatever digit-extraction path
replaces the current `tens_digit` / `ones_digit` helpers.
### Cross-block temp live-range analysis
The slot recycler is function-local per-block. Temps that flow across block

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

After

Width:  |  Height:  |  Size: 456 KiB

Before After
Before After