Monday, September 2, 2013

Going 8x8 or 8x16

In my last post I mentioned that I wanted 60fps with 6 enemies on screen at once. Why 6? Well, there is a logical explanation for that number. The NES does not work like a typical raster display that you find in a PC. Instead it uses a very specialized PPU, or graphics chip. The graphics chip can output a background made up of various tiles, and up to 64 sprites on top of this background.

This tile based display greatly reduces the amount of RAM used for the display, and it also offloads the heavy act of drawing the graphics to the PPU, while the CPU can spend the time doing other stuff. Compare the NES to a common PC of its time, and the advantages of using this design for a game system is easy to see.

Sprites are independent graphics objects that can be placed anywhere on top of the tiled background. They do not have to follow the tile grid, and are therefore perfect for players, enemies, bullets etc. There are however some limitations to the sprites. A sprite on the NES can be either 8x8 pixels or 8x16 pixels. Each sprite can have one of four palettes, each consisting of three colors plus transparent.

Examples of how the meta sprite would be split up in 8x8 or 8x16 mode.

The player and enemy sprites in my game are roughly 16x24 pixels large. That means I can either choose to use 8x8 sprites, and each character will take up 6 of the 64 possible sprites, or I can choose 8x16 sprites and have each character only use 4 sprites. So why choose 8x8? Well, as the NES has a very limited graphics memory, there is a better chance that I can be able to reuse a sprite twice or more. For example, the top of the head might be the same in all frames of an animation, so I don't have to store it twice. Plus, when using 8x16 sprites, I have to save the empty space beneath the character and waste space.

I had initially started by using 8x8 sprites, making the maximum number of characters available on screen at once 10. I also knew that I had to save some of the sprites for things like effects, crosshairs, health indicators and stuff like that. So I was left with 6 enemies and two players.

Having a maximum of 8 characters on screen also fit nicely into the sprite limitations per scanline on the NES. One of the biggest limitations of the NES is that it can only show 8 sprites on one scanline. If you try to show more, they will simply not appear at all. What most programmers did to solve this problem is to draw the sprites in a different order each frame. That way, when there were too many sprites on a scanline at once, they would only become invisible every other frame. This was very common on the NES and can be seen in almost any game.

Sprite flickering example in Megaman 2 (esp at around 1:06)

Since my characters are 16 pixels wide, they use two sprites. So if all characters happened to stand next to each other, half of them would disappear. The simple solution, since I know there is no possible way more than 16 sprites can show up at once on a scanline, is to just draw the sprite buffer backwards every other frame (If I need to, more on this will come). That's why I wanted 6 enemies at once.

But I have since become greedy. This is a game about zombies. No zombie apocalypse has ever been much to call home about with only 6 zombies. I want hordes of them! That is why I have chosen to change thigs up and go for 8x16 sprites instead. This means I have a theoretical limit of 14 zombies and 2 players on screen at once. I'm still not sure I will be able to pull this off, but that's what I'm aiming for.

As you can tell from my sprite, I can still get away with the 3 color limitation when using 8x16 sprites. The pants need to use a different palette, but the top of the body only uses three colors.

Next up is the great challenge of drawing the sprites in order and keep track of what to flicker and when. More on that soon.

2 comments:

  1. I don't understand just one thing. Can you mix 8x16 and 8x8 sprites on one screen, or does every sprite have to be the same size?

    ReplyDelete
  2. All sprites( 8x8 or 8x16 blocks) need to have same size.

    ReplyDelete