SNES sprite limitations are much more forgiving than NES limits but there are still design considerations when it comes to producing high-quality games. This guide will explain the technical aspects of creating sprites for the Super Nintendo and highlight some important terms for developers and artists.
The limits imposed by hardware are the following:
Colors: Each SNES sprite can have 16 colors and a palette slot out of 8 total palette slots. Disregarding advanced tricks like rewriting palette data during a scanline, this is the general limit. The 0th entry of each palette slot is transparent, regardless of what color is specified there.
Sizes: A SNES sprite can be 8x8, 16x16, 32x32, or 64x64. Sizes cannot be chosen freely. A game can have two of the predetermined size combinations:
- 8x8, 16x16
- 8x8, 32,32
- 8x8, 64x64
- 16x16, 32x32
- 16x16, 64x64
- 32x32, 64x64
This means that once picked, the SNES will consider every sprite in the game to be one of these sizes. Thus, if a game is using 8x8 and 16x16 sprites, a 32x36 character would be considered as 3 sprites. If the game was using 32x32 and 64x64 sprites, then the 32x36 character would be 1 sprite.
Sprites per Scanline: 32. This is a hard limit. On top of that only 34 8x8 tiles can be displayed regardless of how big the sprites are. This is related to the next limit.
Sprite Pixels per Scanline: 256. This means no matter how many sprites are there, after 256 pixels the PPU starts cutting off sprites. The renderer always clips the frontmost (lower id) sprites.
Sprite VRAM Size: There are two 128x128 pixel areas that are allocated for VRAM. Each of them is assigned to... nothing actually. Each sprite can be told which size should it take and where from VRAM it should be taken from. There is a flag for each sprite for which VRAM area should be fetched from.
Sprite Positions: No limitations here.
Total On-Screen Sprites: 128. That’s how many simultaneous entries there are for sprites.
This stands for Object Attribute Memory. This is a memory area in the PPU taking up 512+32 bytes. This represents 128 sprites in total.
In the OAM the following information is stored:
- Sprite X position
- Sprite Y position
- Sprite palette slot number (starting from 0, stored from the 8th position of CGRAM)
- Sprite size (one of the two possible sizes)
- Sprite graphics in VRAM
- Sprite flipping information: whether it is flipped in X or Y (or both) directions.
Sprite Engine Variations
Now that we have an understanding of the basics, we can discuss how to turn this information into a sprite engine. There are several ways to design a powerful tool around these capabilities/limitations. These are some common design guidelines:
Static VRAM Usage
This technique is useful when the sprites do not have too many animation frames and all the sprites a game ever wants to use fit into the VRAM area.
Static VRAM Usage with Streaming
Occasionally, all the necessary sprites will fit into the VRAM but their animation frames do not. That means their position is fixed in the VRAM but the frames are streamed (also known as “sprite pumping”) straight into the VRAM with the help of DMA.
Dynamic VRAM Usage
This usually explicitly means streaming of the frames since it makes no difference what sprite frame is handled dynamically. This method involves dynamically allocating sprite positions in VRAM and keeping a list of allocated and free slots.
VRAM is just one of the manageable resources. The other is the actual number of sprites and their composition. It is rare when a game element takes up just a single sprite. Either it is combined with multiple sprites or the same sprites are repeated but at different locations.
Static OAM Usage
This is similar to the static VRAM handling. Each sprite is assigned to a fixed slot in the OAM.
Dynamic OAM Allocation
In this method, the sprites are not mapped directly to OAM entries. This is done usually for flexibility and to overcome some of the limitations detailed below.
Sprite Priority and Rendering
While it seems obvious, in most games it matters what happens when sprites cover each other. The easiest approach is to leave it up to the PPU which renders the sprites with FIFO, meaning that the first rendered sprite is on the top.
The common solution is to reorganize the sprites to have the desired priority. At this point, sprites will be handled as virtual sprites since there is no 1:1 assignment between OAM and their IDs.
The same thing happens when multiple sprites are used to compose one object. These are often called meta sprites.
Repeated sprites do take up multiple OAM locations but not necessarily multiple VRAM slots. At this point, the OAM locations are logically assigned to the virtual sprites.
Although more forgiving than the NES, the SNES still has plenty of considerations when it comes to creating and managing sprites. However, there are some tools and techniques developers can use to get the most out of this platform. As with any retro project, careful planning and an awareness of the restrictions will guide artists and the rest of the team towards a beautiful, feature-rich game.