Sometimes, NES sprites flicker when there are a lot of them, like at 1:19 in this video of Super Mario Bros. Why did they do this?
2 Answers
The Picture Processing Unit (PPU) in the NES can only draw 64 sprites per frame and 8 sprites per horizontal line (scanline). If the game tries to draw more than that, some of them will be invisible.
It could ruin the game if enemies became invisible because there were too many of them, so the developers programmed the games to change the order of sprites in the sprite list. Instead of some sprites always being invisible, the invisible sprites change every frame, causing the flicker effect.
The PPU stores the list of sprites in a a 256-byte area of memory called the Object Attribute Memory (OAM). Usually, games keep the sprite data in the program RAM and DMA it to OAM every frame.
The PPU also has Secondary OAM, a 32-byte memory area where it stores OAM entries for sprites that will be visible on the next horizontal line of the picture (scanline) and eight internal registers that store bitmaps, positions, and attributes for sprites that are visible on the current scanline.
Because primary OAM is 256 bytes, and each sprite takes 4 bytes, the PPU can only draw 64 sprites per frame. Because secondary OAM is only 32 bytes and there are only 8 sprite registers, the PPU can only draw 8 sprites per scanline. If there are more than eight sprites per scanline in OAM, only the first 8 will be drawn -- the rest will be invisible.
-
I remember that this would get really bad in the original Legend of Zelda game. Commented Dec 8, 2016 at 13:15
-
NobodyNada, It seemed to me that this doesn't happen in newer NES games. Maybe I'm wrong. Did they eventually find a way past this sprite limitation? Commented Nov 22, 2017 at 19:15
-
@LateralTerminal No, there’s not really a way to work around the sprite limitations. Later games might have improved sprite management by, for example, using less sprites in general, placing them on the screen so as to prevent too many sprites from being in the same scanline, or combining background and sprites like the lasers in Quick Man’s level in Mega Man 2. Do you have an example of a specific game? Commented Nov 26, 2017 at 22:19
-
@NobodyNada: Some games may also use "background tiles" to mimic the appearance of sprites in cases where many objects on a horizontal line are moving in the same speed and direction, and there isn't any other background.– supercatCommented Oct 27, 2022 at 19:58
There are a fixed amount of memory cycles for the PPU to read the sprite data on each scanline; once those are exhausted, no more sprite data will be fetched.
As NobodyNada said, programmers would rotate the order in the list to make sure that the user would see all the sprites.
The technique was also used on other systems that didn't work the same way, but sprites were rotated to give the illusion of having more objects on screen. The Atari 2600 did that a lot (Joust is a perfect example of this where the birds constantly flicker). On the Intellivision, it was forbidden by Mattel since they wanted the Intellivision to showcase a better visual quality than the competition.
-
Ah, that's why they put 8 sprite registers in there. I knew there was a constant amount of time for sprite fetches, but somehow I never realized that it's just enough time for 8 sprites. Commented Dec 8, 2016 at 0:24
-
yes, essentially as soon as the hblank is triggered, there is a fixed amount of cycle until the display starts again; during that time the bus was used to fetch data and then it stops when video scanning restarts; quite a few video chips have a similar system– ThomasCommented Dec 8, 2016 at 21:22
-
@NobodyNada-ReinstateMonica: There are enough fetches from display memory to process eight sixteen-pixel-wide sprites, but the data registers and shifters are only 8 pixels wide. A bit of a shame in retrospect, given how many games use doubled-up horizontal pairs of sprites. The cost of expanding the data registers and shifters would have been cheap compared to the cost of doubling everything for the sprites, but the benefits would have been almost as great.– supercatCommented Apr 12, 2020 at 22:30
-
@supercat It's true there's enough H-blank cycles to read 32+1 bytes (2 bytes per 8px), and the sprite shift-registers could've been 16px, but this would've added a lot of transitors. It's because Nintendo simplified the VRAM controller by hardcoding it as a 4-step tile fetcher. The only way to access VRAM is to let it read a tile index, then the palette, then 2 pattern bytes which go into a buffer. To read sprites the PPU allows an undefined part of the tilemap to be read, then uses a tiny escape hatch to overwrite the calculated address so that it fetches the desired sprite instead.– DavidCommented Mar 11 at 14:14