mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 17:06:04 +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:
parent
91f82c169a
commit
c5b04c2065
9 changed files with 165 additions and 89 deletions
|
|
@ -35,7 +35,7 @@ Open any `.nes` file in an NES emulator ([Mesen](https://www.mesen.ca/), [FCEUX]
|
|||
| `sfx_pitch_envelope.ne` | varying-pitch pulse SFX | A 16-frame frequency sweep written as a per-frame `pitch:` array on a Pulse-1 sfx. The compiler emits a separate `__sfx_pitch_<name>` blob and gates the audio tick's pitch update path on the `__sfx_pitch_used` marker, so programs that stick to the scalar `pitch:` form still get byte-identical ROM output. |
|
||||
| `metasprite_demo.ne` | declarative multi-tile sprites | A 16×16 hero sprite split into a `metasprite Hero { sprite: Hero16, dx: [...], dy: [...], frame: [...] }` declaration. `draw Hero at: (px, py)` then expands to one `DrawSprite` op per tile in the IR lowering, each with its dx/dy added to the user's anchor point and the frame offset by the underlying sprite's base tile. The codegen needs no metasprite-specific support — it sees N regular draws and the OAM cursor allocator handles the slots. |
|
||||
| `nested_structs.ne` | nested struct fields, array struct fields, chained literals | Two `Hero` instances each carry a `Vec2` position and a `u8[4]` inventory. Exercises `hero.pos.x` chained access, `hero.inv[i]` array-field access, and chained struct-literal initializers (`Hero { pos: Vec2 { x: ..., y: ... }, inv: [...] }`). |
|
||||
| `platformer.ne` | **every subsystem** | End-to-end side-scrolling demo: custom CHR tileset, full 32×30 nametable with per-region attribute palettes, 2×2 metasprite hero with gravity/jump physics, wrap-around horizontal scrolling, stomp-or-die enemy collisions, coin pickups, a sprite-based status bar pinned to the top of the viewport (coin icon + 2-digit score on the left, heart icon + lives counter on the right), cross-state life tracking that sends GameOver back to Title when the last heart is spent, user-declared SFX + music, and a Title → Playing → GameOver state machine with a proximity-based autopilot so the headless harness cycles through stomp, stomp, die, and retry inside six seconds. Regenerate the tile art with `cargo run --bin gen_platformer_tiles`. |
|
||||
| `platformer.ne` | **every subsystem** | End-to-end side-scrolling demo: custom CHR tileset, full 32×30 nametable with per-region attribute palettes, 2×2 metasprite hero with gravity/jump physics, wrap-around horizontal scrolling, stomp-or-die enemy collisions, coin pickups, a background-nametable status bar pinned at the top of the viewport via a sprite-0 hit scroll split (coin + 2-digit score on the left, heart + lives counter on the right; updates gated behind a `last_score` / `last_lives` shadow compare so most frames touch zero VRAM-ring bytes), cross-state life tracking that sends GameOver back to Title when the last heart is spent, user-declared SFX + music, and a Title → Playing → GameOver state machine with a proximity-based autopilot so the headless harness cycles through stomp, stomp, die, and retry inside six seconds. Regenerate the tile art with `cargo run --bin gen_platformer_tiles`. |
|
||||
| `sprite_flicker_demo.ne` | `cycle_sprites`, 8-per-scanline hardware limit | Twelve sprites packed onto the same 4-pixel band — two more than the NES's 8-sprites-per-scanline hardware budget. The W0109 analyzer warning fires at compile time, and a `cycle_sprites` call at the end of `on frame` rotates the OAM DMA offset one slot per frame so the PPU drops a *different* sprite each frame. The permanent-dropout failure mode becomes visible flicker, which the eye reconstructs across frames. The classic NES technique used by Gradius, Battletoads, and every shmup that ever existed. |
|
||||
| `war.ne` | **production-quality card game**, multi-file source layout | A complete port of the card game War, split across `examples/war/*.ne` files and pulled in via `include` directives. Title screen with a 0/1/2-player menu (cursor sprite, blinking PRESS A, brisk 4/4 march on pulse 2), a 50-frame deal animation, a deep `Playing` state with an inner phase machine (`P_WAIT_A`/`P_FLY_A`/.../`P_WAR_BANNER`/`P_WAR_BURY`/`P_CHECK`), card-conserving queue-based decks built on a 200-iteration random-swap shuffle, a "WAR!" tie-break that buries 3+1 face-down cards per player and plays a noise-channel thump per bury, and a victory screen with the builtin fanfare. The first NEScript example to use a top-level file as a thin shell that `include`s ~12 component files; building it surfaced seven compiler bugs across the analyzer, IR lowerer, and codegen that were all fixed on the same branch (see `git log` for details). |
|
||||
| `pong.ne` | **production-quality Pong**, powerups, multi-ball, multi-file | A complete Pong game split across `examples/pong/*.ne`. CPU VS CPU / 1 PLAYER / 2 PLAYERS title menu with brisk pulse-2 title march and autopilot, smooth ball physics with wall and paddle bouncing, CPU AI that tracks the ball with a reaction lag and dead zone, three powerup types (LONG paddle for 5 hits, FAST ball on next hit, MULTI-ball on next hit spawning 3 balls) that bounce around the field and are caught by paddle AABB overlap, multi-ball scoring (each ball scores a point, round continues until last ball exits), inner phase machine (`P_SERVE`/`P_PLAY`/`P_POINT`), and a "PLAYER N WINS" victory screen with the builtin fanfare. First-to-7 wins. |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue