Hello all. I’m Doug (@nesdoug2, dougeff). Welcome to my tutorial – How to program an NES game in C. You can make an original Nintendo game that plays on a real NES console (or emulator).
Probably nearly all original NES games were written in Assembly (few game developers were using C in 1985). If you prefer that route, then you could start with the Nerdy Nights tutorial like I did.
But, ASM is harder to read than C, and slower to write. You could develop a game in half the time in C. Thanks to the helpful homebrew community, we have access to tools and free libraries of code that the programmers of the original NES games didn’t have.
Another option, you could use NESmaker (currently $36), which has all the code for a game written, and all you need to do is design the graphics and the levels. Apparently hundreds of people are in progress of making games with this tool.
Why make an NES game today? Why not? You could make a much better game in Game Maker, or Unity… much bigger, with better audio, and full color graphics. But, I like the nostalgia of retro consoles. And when someone sees you pop your game into a real NES console, and it plays…they’ll say, “Wow! You made this?” Yes. You can. I did, and I’m an idiot.
And the NES is in that perfect middle ground for making a retro game. Before that and the graphics was big squares and the audio was just beeps. Later than NES and it gets very complicated to get anything to work.
Let’s talk about the NES.
Released in Japan (Famicom), 1983, released in US, 1985.
CPU, Ricoh 2A03, 1.79 MHz, is a 6502 (missing decimal mode) with audio circuitry. 6502 was a very popular chip at the time. It is the same chip that Apple II and Atari 2600 used.
256×240 pixels, and can display 25 colors onscreen, out of 53 total.
64 sprites (8×8 or 8×16), freely moving graphic objects.
60 fps (50 fps Europe)
5 channels of audio. 2 square, 1 triangle, 1 noise, and 1 for small samples.
Here’s the memory map for the CPU.
That’s only 2048 bytes of RAM standard. Not a lot to work with.
The PPU (produces a video image) is a separate chip, that has its own memory. It is only accessible from the CPU through a slow 1 byte at a time transfer, using hardware registers.
Here’s the memory map for the PPU
Each tileset holds 256 tiles. Each tile is 8×8 pixels.
Nametable is a technical word that basically means tilemap, or background screen.
There is also another 256 bytes (0-FF) memory dedicated to Sprites (OAM). This memory is especially volatile, and needs to be rewritten every frame.
It looks like there are 4 usable nametables (background screens), but actually there is only enough internal VRAM for 2. The cartridges are hardwired to either be in “horizontal mirroring” or “vertical mirroring”. More advanced mappers can switch between these options.
Vertical mirroring (or horizontal arrangement) is for sideways scrolling games, and the lower 2 nametables are just a mirror of the upper 2 nametables, like this…
Horizontal mirroring (or vertical arrangement) is for vertically scrolling games, and the right 2 nametables are just a mirror or the left 2 nametables, like this…
A rare few games had extra RAM on the cartridge to actually have 4 different nametables (Gauntlet is one example). For more detailed information, check out the nesdev wiki.
Lastly, the game cartridges usually have 2 ROM chips inside. One PRG-ROM (executable code), and one CHR-ROM (graphic tiles). But some games, instead of a CHR-ROM chip, have a CHR-RAM chip. The graphics are located somewhere in the PRG-ROM, and the program has to transfer the bytes from there to the CHR-RAM chip.
My tutorials will exclusively deal with CHR-ROM style games. It’s easier. With this style, the graphic tiles are automatically connected to the PPU and you don’t have to transfer them to the PPU. With the simplest cartridge you get 2 sets of 256 tiles (8×8 pixel). Usually, one for background tiles and one for sprite tiles.
You might want to read up on hexadecimal numbers. 8 bit numbers are much easier to read and understand in hex. I usually use $ to indicate hex, but sometimes I use 0x. $ is used in assembly languages, and 0x is used in C like languages. You don’t need to be a math expert, but it will help if you know what I’m talking about.