This example demonstrates a custom tilemap-based sprite engine that treats BG1 as a grid of 16x16 "sprites" (not OAM hardware sprites). Each sprite is composed of tilemap entries pointing to 8bpp tile data in VRAM, allowing you to place, move, and scroll dozens of graphical elements on a background layer. The example supports two map modes (32x32 and 64x64) and includes a C64-to-SNES sprite format converter, showing how retro formats can be adapted to SNES hardware.
Mode 3 gives BG1 a full 256-color palette (8 bits per pixel). Each 8x8 tile uses 64 bytes of VRAM (8 bitplanes x 8 rows). A 16x16 sprite at 8bpp requires 4 tiles = 256 bytes. This is configured by calling setMode(BG_MODE3, 0) for 8x8 tile size, or setMode(BG_MODE3, 0x10) for 16x16 tile size (bit 4 of register $2105). BG2 in Mode 3 uses 4bpp (16 colors), which this example uses for the text overlay.
An SC_64x64 tilemap consists of four 32x32 tile pages (8KB total). In memory, they are arranged as: page 0 (top-left), page 1 (top-right), page 2 (bottom-left), page 3 (bottom-right). Each tile entry is 2 bytes (tile number + attributes), so each page is 2048 bytes. The code maps logical (x, y) sprite coordinates to the correct page and byte offset within the tilemap buffer.
The SNES has 128KB of WRAM at banks $7E-$7F. The compiler generates sta.l $0000,x which can only reach bank $00:$0000-$1FFF (8KB). To use the remaining WRAM, the tilemap buffer lives at $7E:$2000 and is accessed through assembly helper functions (smapWrite, smapRead, smapDma, smapClear) that set the correct bank byte.
The SNES PPU ignores VRAM writes during active display. VBlank provides roughly 41,000 master cycles for DMA. At 8 cycles per byte, a 2KB page transfer takes about 16,000 cycles – well within budget. The code DMAs one 2048-byte tilemap page per VBlank across 4 frames (67ms total), which is imperceptible to the player and avoids any visual glitching.
| Button | Action |
|---|---|
| D-PAD | Scroll the map |
| A | Toggle between 32x32 and 64x64 map mode |
| B | Toggle scroll lock on/off |
| X | Place a random gargoyle sprite on the map |
| Y | Display a C64 Rockford sprite (Boulder Dash) converted to SNES format |
1. Initialization – The console is set up with Mode 3, BG1 for the sprite map, and BG2 for text. The tilemap buffer in bank $7E is cleared, and gargoyle tile data is DMA'd from ROM to VRAM during force blank:
2. Drawing sprites on the tilemap – Each 16x16 sprite occupies 2x2 tiles in 8x8 mode (or 1 tile in 16x16 mode). The drawSprite32x32() function writes tile indices into the RAM buffer, mapping logical coordinates to the correct SC_64x64 page:
3. Tilemap DMA to VRAM – After modifying the RAM buffer, changes are sent to VRAM one page per VBlank:
4. C64 sprite conversion – The convertC64Sprite() function reads 2-bit C64 pixel data and repacks it into SNES 8bpp bitplane format (8 interleaved bitplanes per 8-pixel row, 4 tiles per 16x16 sprite).
Then open dynamic_map.sfc in your emulator (Mesen2 recommended).