This tutorial covers SNES sprites (OBJ layer) including OAM management and animation.
SNES Sprite Basics
- Up to 128 sprites on screen
- Sizes: 8x8, 16x16, 32x32, 64x64 (two sizes per mode)
- 4bpp (16 colors per palette)
- 8 palettes available (palettes 8-15 in CGRAM)
- Stored in OAM (Object Attribute Memory) - 544 bytes
OAM Structure
Each sprite uses 4 bytes in main OAM + 2 bits in high table:
Main OAM (4 bytes per sprite):
| Byte | Content |
| 0 | X position (low 8 bits) |
| 1 | Y position |
| 2 | Tile number (low 8 bits) |
| 3 | Attributes: vhoopppN |
Attributes:
- v = Vertical flip
- h = Horizontal flip
- oo = Priority (0-3)
- ppp = Palette (0-7, maps to CGRAM 128-255)
- N = Tile number bit 8
Using OpenSNES Sprite Functions
Initialize OAM
}
int main(void)
Entry point — initialize audio, display controls, run transport loop.
Definition main.c:37
void consoleInit(void)
Initialize SNES hardware.
void setScreenOn(void)
Enable screen display.
#define REG_TM
Main screen designation (W)
Definition registers.h:181
#define TM_OBJ
Definition registers.h:443
void oamInit(u16 size, u16 tile_base)
Initialize the sprite (OAM) system.
Setting a Sprite
oamSet(0, 100, 80, 0, 0, 0, 0);
oamSet(1, 120, 80, 0, 0, 0, 1);
void oamSet(u16 id, u16 x, u16 y, u16 tile, u16 palette, u16 priority, u16 flags)
Set sprite properties.
Updating OAM
while (1) {
}
static s16 player_y
Player Y position in screen coordinates.
Definition main.c:57
static s16 player_x
Player X position in screen coordinates.
Definition main.c:55
void WaitForVBlank(void)
Wait for next VBlank period.
void oamUpdate(void)
Copy OAM buffer to hardware.
Hiding Sprites
void oamHide(u8 id)
Hide sprite.
Loading Sprite Tiles
Sprite tiles go in VRAM (location set by REG_OBJSEL):
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
for (
i = 0;
i < 32;
i += 2) {
}
}
static u8 i
Definition main.c:156
static u16 bx
Definition main.c:159
#define REG_VMADDH
VRAM address high (W)
Definition registers.h:118
#define REG_VMAIN
VRAM address increment mode (W)
Definition registers.h:112
#define REG_VMADDL
VRAM address low (W)
Definition registers.h:115
#define REG_VMDATAL
VRAM data write low (W)
Definition registers.h:121
#define REG_OBJSEL
Object (sprite) size and base (W)
Definition registers.h:52
#define REG_VMDATAH
VRAM data write high (W)
Definition registers.h:124
unsigned short u16
16-bit unsigned integer (0 to 65535)
Definition types.h:52
unsigned char u8
8-bit unsigned integer (0 to 255)
Definition types.h:46
static const u8 sprite_tile[32]
Inline 8x8 solid square sprite tile in SNES 4bpp format (32 bytes).
Definition main.c:43
Sprite Palettes
Sprite palettes use CGRAM addresses 128-255:
}
#define REG_CGADD
CGRAM address (W)
Definition registers.h:148
#define REG_CGDATA
CGRAM data write (W)
Definition registers.h:151
Animation
Frame-based Animation
anim_frame++;
if (anim_frame >= 4) {
anim_frame = 0;
}
}
}
void oamSetTile(u8 id, u16 tile)
Set sprite tile.
Movement with Animation
Sprite Sizes
Configure sprite sizes with REG_OBJSEL:
Example: Two Players
See examples/input/two_players/ for a complete example with two independently controlled sprites.
Performance Tips
- Minimize oamUpdate() calls - Only call once per frame
- Use sprite pooling - Reuse sprite slots instead of creating/destroying
- Check sprite limits - Max 32 sprites per scanline, 128 total
- Batch similar sprites - Group sprites using same tiles/palettes
Next Steps