I'm still working on my animation, but given my love for retrotech, I might as well talk a little bit about the constraints you'd be under when actually developing for the NES and the Gameboy.
The Gameboy came later and in some ways is more capable than the NES; we only have four colors to work with and we can use them all at the same time, of course. However, it
also has its own palettes as well so you can do things like my night-to-day transition without needing two copies of your graphics. You can even make some of the four colors overlap if you wanted details to gradually emerge, or to do a fade to black or white.
The fundamental unit of graphics on the Game Boy is the 8x8 tile, and you had 384 of them to work with: 128 reserved for background, 128 reserved for sprites, and 128 shared between both. This lived in a chunk of RAM that could be copied to out of the cartridge ROM as needed. There were two map areas into which you could place background tiles, each noticably larger than the whole screen, and the hardware let you set it up to display two parts at once; the main background, and then a separate chunk (bound to an edge) that covered things like status windows. That meant that you could have a fixed status window on the bottom or the right of your screen and then have an omni-directional scrolling window over the main map, all without having to do more than just asking the chip to arrange the screen that way.
But that's 1989 tech. The NES was designed in 1983, and the idea of what videogames were even
for was a lot more restricted.
The base NES console and cartridge hardware has two different ROM chips: a 32KB ROM for holding the program, and an 8KB ROM for holding the graphics data. Once again, the fundamental unit of graphics data is the 8x8 tile, and it provides was two disjoint sets of 256. Background and Sprite graphics can independently pick which to use, so the options are basically "share everything" or "share nothing".
In this basic configuration, you also don't have the option like you do on the Game Boy of rewriting the sprite and background data between levels; there's only ever just the one chip. (Pretty much every game post-Super Mario Bros. had
some kind of extra logic on the cartridge to let it map different parts of a larger ROM into the program or graphics space--Gradius, for instance, only needed 32KB for its program and music but would swap between two sets of graphics twice a frame, one for the level and one for the status bar.) Scrolling only part of the screen was also much harder on the NES; you were pretty much obliged to put your status window at the top or bottom of the screen because you were restricted to changing your graphics modes mid-frame. Unlike a lot of the home computers of that era like the Atari or C64, you also had some challenges knowing when to split the screen. The intended way to do it was to set a sprite at some point on the screen and then go into a tight loop seeing if that sprite had "hit the background" yet. When it did, that meant it had been drawn and it was time to change modes.
One other trick you could do, and which Zanac does, is to replace the graphics ROM with high-speed RAM chips. You could then create graphics on the fly as needed, much like you would on the Game Boy.
NES Sprite displays were pretty straightforward. Color 0 was transparent, and colors 1-3 were entries in one of the four sprite palettes, as was described. Each sprite could have its own palette, and the hardware could even automatically flip your sprite horizontally or vertically as needed, or have it render in front of or behind the background as you wished. You had 64 sprites to work with overall, and you could use them as 8x8 sprites or 8x16 sprites (created from pairs of adjacent tiles in your set of 256).
So far this isn't really too bad. Where things get ugly is the map data.
Like the Game Boy, the NES keeps a space larger than the screen to put tiles into so that you can scroll cleanly. Unlike the Game Boy, it's only larger than the screen in
one dimension, so the original idea is that you would decide at game design time whether you would be scrolling horizontally or vertically and
solder some wires together on the cartridge circuit board to represent this choice. (Again, later cartridges put some logic on the cartridge to decide this, from the one-dimension-at-a-time scrolling of Metroid or Kid Icarus that changes from room to room, to Dragon Warrior which hides the swap in the little pause as you changed directions on the world map, to the full 2D scrolling of Super Mario 3 and Kirby's Adventure, which accepted a bit of graphical corruption to get the power.)
Anyway. Effectively, you have two KB of memory for two screens of tiles, which gets you 32x30 8x8 tiles to build any given 256x240 screen out of. Like sprites, each gets a palette assigned to it. Unlike sprites, you can't have them flipped as they're drawn. And then,
very unlike sprites, you don't have a completely free hand in assigning palettes to tiles.
This falls out of the math, basically. 32x30 tiles is 960 bytes. That leaves only 64 bytes for the palette information, and with four palettes we need two bits for each palette. This works out to each byte of color data for the background corresponding to
four 16x16 regions on the map. These are arranged as squares, so this means you can divide your map up three ways and have them all make sense:
- 32x30 8x8 tiles where you have some restrictions on colors
- 16x15 16x16 tiles where you can give each tile its own palette assignment, but where generating the color tables requires a little work at run time (this seems like the most common approach)
- 8x7.5 32x32 tiles where copying color information is as easy as copying tiles into the map
So, what does this mean about the kind of game we're writing our NES sprites for? Well, the target size is 8x16, so that's either one or two sprites on their own. This implies that we're probably playing a game that has a great deal of motion in it, as our world is going to be full of small moving objects, and we don't have to spend a lot of individual sprites to get the displays we want.