Game consoles, especially older ones, are defined more than anything by their graphics capability. The unique graphical limitations of a system can often make it possible to identify a game console just by a screenshot; for example, the average SNES game has more colors but a lower resolution than the average Genesis game. The NES has a distinctive palette that’s unique to it. But these limitations also mean that you can’t just shove a BMP into VRAM and call it a day. Here’s my process for how I do things.
Too long, didn’t read!
If you get nothing else from this document, I want to say:
Don’t be afraid to make your own tools! I’m going to link to some things and code I’ve written. This isn’t however a suggestion to just use what I’ve written; write your own! Fork mine if you find it useful, sure.
I believe that anyone can learn to program. However, not everyone can teach programming, and methods of learning that work for one person might not work for someone else. Making tools that do one job and only you ever need to use (it crashes when you do that? Don’t do that) is a good way for me to try things out. Generally, here I’ll be talking about what works for me– but the most important thing is to find something that’s comfortable, so you can do it a lot and practice.
If you’re making games for an old console, or even just targeting the look of an old console, one way to do that is to borrow some tools from the ROM hacking scene. After all, these will include all the limitations of the console built-in, and will generally save files in a format that can be directly used in your final game.
This is YY-CHR; it’s an editor I’ve used since I was a kid messing about, and has a number of releases, and it’s what I used for Aspect Star “N”. There’s a lot in the interface, but some things to point out:
- The palette is swappable. In fact, it allows you to choose from an NES palette by default when it load it up.
- The base unit is an 8x8 tile, just like the NES.
- You might notice the dropdown for the console format (“2BPP NES”) and for a tile layout (“FC/NES x16”). This is laid out how you would need it for the NES’s 8x16 sprite mode; you can also change to “FC/NES x8” for the 8x8 sprite mode. Aspect Star “N” uses both, so this is invaluable.
However, a major downside of ROM format editors is that they won’t include palette data. The palettes in that screenshot are default; you have to load palettes from a separate file. Additonally, if your goal is only to make a retro-styled game, you might want to be able to leave the limitations now and then.
One way to do this is to use a higher-valued system. For example, Aspect Star 2’s graphics were originally drawn in SNES format, even though that game mostly uses an NES style. Of course, this is inauthentic, but oftentimes that doesn’t actually matter. For example, Aspect Star 2 is also a widescreen game, so clearly we aren’t being strict here.
Personally, I’ve found maintaining separate palette and image files to be a pain, so I don’t recommend this for large projects, except for NES or other consoles where the palettes are small and you’re often using many variants.
But even if you do most of your graphics editing somewhere else, I recommend having an editor like this on hand. They’re useful for checking your work and conversions.
Modern image editors
Another way is to use some kind of intermediate format. Use an editor of your preference, save your graphics in a format that will include both palette and graphics data. This format could be a PNG file, or any other common format.
Whatever editor you choose, I strongly recommend that it be a paletted editor. What do I mean? When you use a format like BMP or JPEG, you’re storing a color at every point. So for an uncompressed file, each pixel has three numbers for R, G, and B. (And maybe a fourth for transparency). Changing the color of one pixel doesn’t change the others. Most graphics programs these days will default to this, usually in 24-bit mode. (24 = 8x3, so 8 bits for red, green, and blue)
The other option is to have palettes. Essentially, you only have one number at each pixel. That number maps to a palette where, say, color 0 is black, color 1 might be red, etc. etc. If you change color 1’s value, everything that uses color 1 will change. When you’re making graphics for a system like the PC Engine, every color in a 15-color palette counts.
PNG, a common format, can be paletted or not. GIF is always paletted. So make sure you know your graphics editor. Paint Shop Pro 5, for example, can load paletted images and use them as paletted.
If you do use a general-purpose graphics editor, make sure to be very careful about aligning. Things like 8x8 tile boundaries won’t be built into your image; you’ll need to deal with them yourself.
A dedicated pixel art editor
There are also editors dedicated to the purpose of pixel art. For example, Aseprite seems to be very popular, though I haven’t used it. ChibiAkumas has AkuSprite, which is optimized for output for the computers and consoles that his tutorials support. Personally, I use Terraformer, a buggy and low-feature editor that I wrote myself.
Terraformer isn’t perhaps the best editor ever made, but it has the major benefit that it’s optimized by me for the sorts of things I want to do. So it’s paletted, it mimics YY-CHR’s interface (which I’m most used to), and stores its files in JSON, which is a format I’m familiar with. It’s missing a lot of features, but the ones it does have I know exactly how it works. I’ve used this since Happy Train!, for JS games and homebrew alike.
Do I recommend you use it? Oh hell no, I don’t want to support other people, and it really is very limited (you can’t even change the image size, instead only adding “pages”, and you need to open it from a terminal). But it works very well for my needs. I show it as an example to say that if you’re not happy with any of the editors you see, you can write one yourself. For me at least, spriting is harder than programming.
Using your images
So you’ve made sprites, and they’re sitting pretty in a file. But how do you get them into your game? Like I said when starting this, you can’t just dump a BMP into, say, the Sega Genesis’ VRAM and expect everything to work.
If you’re using a ROM graphics editor, this might seem easy enough. For example, in Aspect Star “N”, pretty much any tutorial should tell you how to include CHR-ROM in your game, and that’s all you need.
But it gets a bit harder with other formats. You have some options. For example, ROMHacking.net has some standalone utilities that can convert from graphics formats to ROM formats. More flexibly, Aseprite has a detailed plugin system that I know people have used for exporting to the right format.
Personally, I find it easiest to write these myself. This can sound intimidating, but it’s really not. Most consoles you’d code homebrew for have decent guides out there to how their formats work, and you can use a ROM graphics editor like YY-CHR to check your work. Terraformer can only save JSON files because it was written with this in mind; Python is very good at manipulating JSON. But you can also use a library like Pillow for more familiar image formats.
For example, take the dialogue scenes of Ava above. They’re laid out in rows of 32x48 blocks laid out for easy editing. But in the ROM, they’re stored like this for the code to handle:
Obviously this is only a feature useful for Space Ava 201, so the only way it would exist is if I wrote it that way. Small quality-of-life improvements are a major benefit of writing things your own way, if you’re willing to put in the extra coding time. The downside, of course, is that if you want to change how things work, you’ll also need to rewrite your tools. I had to write a whole new converter for my Neo Geo project.
Automate, automate, automate
The most important thing in my book, is to make a system you can automate. In Aspect Star 2, the graphics process went as follows:
- Open YY-CHR
- Load the graphics file
- Load the palette file
- Edit the graphics in YY-CHR
- Save the graphics, and palette if that changed
- Export to an image
- Open the image in Paint.NET
- Resize the image and add transparency, possibly color tweaks
- Save the image in the Content folder
- Rebuild in Visual Studio
- Test the game
That’s a lot of manual steps! And sure, that might not seem that bad, but seeing graphics “in action” is the best way to see how they’ll really look (especially animations), and this is a lot of effort for making small changes. For me at least, the best way to get good-looking graphics (or, at least, tolerable graphics) is to be able to constantly make tweaks and have a tight “feedback loop”. Really, it’s the same for coding the game too.
Space Ava 201 had the following:
- Open Terraformer
- Edit the graphics file
- Save the graphics file
- Build the game as usual
- Test the game
Of course, it’s up to you to determine what the best balance is, and where best to focus your time. This code-heavy approach works for me; it may not work best for you, and that’s totally fine. But don’t be afraid to try it out either.
I didn’t really go into how to draw sprites here, because well, I don’t really know myself. My strategy is to just draw a lot of random things, and save everything I’m at all happy with, even if the project dies. It’s probably no surprise that the faces in Aspect Star “N” and in Space Ava 201 share a common ancestor; a long-abandoned NES-style graphical adventure.
So I guess that’s the most important thing, even if it sounds cliche: Try. Don’t be afraid to fail, and don’t delete your mistakes. Is Space Ava 201 a work of high art? No. But it exists! And that counts for something.