1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-07 00:22:50 +00:00
nescript/examples/sprites_and_palettes.ne
Claude ad951a835f
examples: adopt the friendly asset syntax
Rewrites every example with non-trivial asset declarations to use
the pleasant QoL syntax introduced in the previous commit. Every
example still compiles to a byte-identical ROM (verified by a
temp-path diff before committing), so the committed `.nes` files
and the 23 emulator goldens are unchanged.

  * platformer.ne — the centerpiece end-to-end demo:
      - `palette Main` goes to grouped form with a shared
        `universal: 0x22` (sky blue), one shared colour per
        sub-palette, and named NES colours throughout; the
        long-standing `$3F10` mirror-trap warning is now handled
        by the parser and the manual pitfall comment is gone.
      - `sprite Tileset` is 15 tiles of ASCII pixel art instead
        of 240 bytes of inline hex.
      - `background Level` uses a `legend { '.': 15, '#': 9, ... }`
        block plus `map:` strings for the 32×30 nametable, and
        `palette_map:` rows for the attribute table. The map
        reads top-down like the rendered screen.
      - SFX latch-once `pitch: 0x30` scalars + `envelope:` alias.
      - `music Theme` uses note names + `tempo: 10` default.
  * audio_demo.ne — scalar sfx pitches, `envelope:` alias, and a
    note-name `C4, E4, G4, ...` music track.
  * palette_and_background.ne — grouped CoolBlues / WarmReds
    palettes with `universal: black` + named colours, plus
    `legend` + `map:` tilemaps for the two backgrounds.
  * sprites_and_palettes.ne — Arrow and Heart sprites rewritten
    as `pixels:` ASCII art.

Along the way, two small parser extensions support the rewrites:

  - `parse_pixel_art` now accepts `a/b/c` as aliases for `#/%/@`,
    matching the vocabulary every NES editor (and our own
    gen_platformer_tiles.rs generator) uses.
  - `palette_map_to_attrs` allows up to 16 metatile rows (the
    full attribute-table coverage, including the off-screen
    bottom half) and auto-replicates row 14 → row 15 when only
    15 rows are supplied so the visible bottom of the screen
    gets consistent sub-palette assignments by default. The old
    15-row cap couldn't match a hand-packed `0xAA` attribute
    table for the last row; the platformer required this to
    stay byte-identical.

`scripts/gen_platformer_tiles.rs` is updated to emit the new
syntax directly (pixel-art `pixels:` block + `legend`/`map:`/
`palette_map:` for the background), so regenerating the
platformer tiles stays a one-liner.

474 lib tests + 64 integration tests pass (3 new parser tests
for `palette_map:` 15/16/17 rows and the `abc` alias). All 23
emulator goldens still match pixel- and sample-for-sample.

https://claude.ai/code/session_01PzaSFj3VahDzxEYTKCESkz
2026-04-13 18:04:21 +00:00

69 lines
1.4 KiB
Text

// Sprites and Scroll — demonstrates M3/M4 asset features.
//
// Shows: sprite declarations with inline CHR data, type casting,
// PPU scroll writes.
//
// Build: cargo run -- build examples/sprites_and_palettes.ne
game "Asset Demo" {
mapper: NROM
}
// Define a sprite with ASCII pixel art. Each character maps to a
// 2-bit palette index: `.` = 0 (transparent), `#` = 1, `%` = 2,
// `@` = 3. The parser handles the 2-bitplane CHR encoding, so we
// never touch hex bytes by hand.
//
// Arrow — a right-facing arrow in palette-index 1.
sprite Arrow {
pixels: [
"...##...",
"...###..",
"#######.",
"########",
"########",
"#######.",
"...###..",
"...##..."
]
}
// Heart — a full-colour heart in palette-index 3 (the brightest
// shade, `@`).
sprite Heart {
pixels: [
".@@..@@.",
"@@@@@@@@",
"@@@@@@@@",
"@@@@@@@@",
".@@@@@@.",
"..@@@@..",
"...@@...",
"........"
]
}
var px: u8 = 128
var py: u8 = 120
var scroll_x: u8 = 0
on frame {
// Movement
if button.right { px += 2 }
if button.left { px -= 2 }
if button.down { py += 2 }
if button.up { py -= 2 }
// Scroll background
scroll_x += 1
scroll(scroll_x, 0)
// Type cast demo
var wide: u16 = px as u16
// Draw sprites
draw Arrow at: (px, py)
draw Heart at: (px, py - 16)
}
start Main