Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions docs/8bitworkshop-samples.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@

### metacursor.c
- **Description:** Reads controller input to move metasprites, demonstrating `pad_poll` for two players.
- **Status:** 🟠 Moderate
- **Missing Features:**
- User-defined functions (`setup_graphics`) — must be inlined
- `for` loops → must use `while`
- Global/static arrays (`actor_x[16]`, `actor_y[16]`, etc.)
- `sbyte` signed byte type support
- Pointer-to-const-array table (`playerRunSeq[16]`) — array of array references
- C preprocessor macros for metasprite definitions (`DEF_METASPRITE_2x2`)
- `#include <nes.h>` / `OAM_FLIP_H` constant
- **Status:** ✅ Implemented
- **Simplifications:**
- Reduced from 16 to 8 actors (zero-page memory limits)
- Uses single metasprite for all actors (no animation frame cycling, which requires array-of-pointers)
- Removed boundary checks (`actor_x[i] > 0`, `actor_x[i] < 240`) — actors wrap around screen edges
- Inlined `setup_graphics()` into main body
- Used `while` loops instead of `for`
- Expanded C macros to byte array literals
- Used `0x40` constant instead of `OAM_FLIP_H`

### metatrigger.c
- **Description:** Similar to metacursor but uses `pad_trigger()` and `pad_state()` for input, plus `pal_bright()` for brightness control.
Expand Down Expand Up @@ -348,9 +348,9 @@

| Status | Count | Samples |
|--------|-------|---------|
| ✅ Already Implemented | 11 | hello, attributes, flicker, metasprites, music, tint, scroll, rletitle, tileset1, sprites |
| ✅ Already Implemented | 12 | hello, attributes, flicker, metasprites, music, tint, scroll, rletitle, tileset1, sprites, metacursor |
| 🟡 Feasible | 0 | |
| 🟠 Moderate | 7 | metacursor, metatrigger, apu, bcd, statusbar, vrambuffer, vrambuf |
| 🟠 Moderate | 6 | metatrigger, apu, bcd, statusbar, vrambuffer, vrambuf |
| 🔴 Complex | 14 | aputest, ppuhello, fami, horizscroll, horizmask, bankswitch, monobitmap, conio, crypto, climber, transtable, irq, shoot2, siegegame |

### Key Blockers (by frequency)
Expand Down
Binary file added metasprite.nes
Binary file not shown.
123 changes: 123 additions & 0 deletions samples/metacursor/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
Read from controllers with pad_poll().
Player 1 and 2 each control a metasprite cursor with the d-pad.
Other actors drift around the screen.
Based on: https://github.com/sehugg/8bitworkshop/blob/master/presets/nes/metacursor.c
*/

// 2x2 metasprite facing right (tiles 0xD8-0xDB)
byte[] playerRStand = [
0, 0, 0xD8, 0,
0, 8, 0xD9, 0,
8, 0, 0xDA, 0,
8, 8, 0xDB, 0,
128
];

// 2x2 metasprite facing left (flipped horizontally, OAM_FLIP_H = 0x40)
byte[] playerLStand = [
8, 0, 0xD8, 0x40,
8, 8, 0xD9, 0x40,
0, 0, 0xDA, 0x40,
0, 8, 0xDB, 0x40,
128
];

// person to save metasprite (tiles 0xBA-0xBD, palette 1)
byte[] personToSave = [
0, 0, 0xBA, 1,
0, 8, 0xBB, 1,
8, 0, 0xBC, 1,
8, 8, 0xBD, 1,
128
];

byte[] PALETTE = [
0x03, // screen color
0x11, 0x30, 0x27, 0x0, // background palette 0
0x1c, 0x20, 0x2c, 0x0, // background palette 1
0x00, 0x10, 0x20, 0x0, // background palette 2
0x06, 0x16, 0x26, 0x0, // background palette 3
0x16, 0x35, 0x24, 0x0, // sprite palette 0
0x00, 0x37, 0x25, 0x0, // sprite palette 1
0x0d, 0x2d, 0x3a, 0x0, // sprite palette 2
0x0d, 0x27, 0x2a // sprite palette 3
];

// actor positions and velocities (8 actors)
byte[] actor_x = new byte[8];
byte[] actor_y = new byte[8];
byte[] actor_dx = new byte[8];
byte[] actor_dy = new byte[8];

// print instructions
vram_adr(NTADR_A(2, 2));
vram_write("D-PAD TO MOVE CURSOR");

// setup graphics
oam_hide_rest(0);
pal_all(PALETTE);
ppu_on_all();

// initialize actors
byte i = 0;
while (i < 8)
{
actor_x[i] = (byte)(i * 32);
actor_y[i] = (byte)(i * 16 + 64);
actor_dx[i] = 0;
actor_dy[i] = 0;
i = (byte)(i + 1);
}

// main loop
while (true)
{
byte oam_id = 0;

// poll controller 0 (player 1 controls actor 0)
PAD pad = pad_poll(0);
if ((pad & PAD.LEFT) != 0)
actor_dx[0] = 254; // -2 as unsigned byte
else if ((pad & PAD.RIGHT) != 0)
actor_dx[0] = 2;
else
actor_dx[0] = 0;

if ((pad & PAD.UP) != 0)
actor_dy[0] = 254; // -2
else if ((pad & PAD.DOWN) != 0)
actor_dy[0] = 2;
else
actor_dy[0] = 0;

// poll controller 1 (player 2 controls actor 1)
pad = pad_poll(1);
if ((pad & PAD.LEFT) != 0)
actor_dx[1] = 254;
else if ((pad & PAD.RIGHT) != 0)
actor_dx[1] = 2;
else
actor_dx[1] = 0;

if ((pad & PAD.UP) != 0)
actor_dy[1] = 254;
else if ((pad & PAD.DOWN) != 0)
actor_dy[1] = 2;
else
actor_dy[1] = 0;

// draw and move all actors
i = 0;
while (i < 8)
{
oam_id = oam_meta_spr(actor_x[i], actor_y[i], oam_id, playerRStand);
actor_x[i] = (byte)(actor_x[i] + actor_dx[i]);
actor_y[i] = (byte)(actor_y[i] + actor_dy[i]);
i = (byte)(i + 1);
}

if (oam_id != 0)
oam_hide_rest(oam_id);
ppu_wait_frame();
}
Loading