Saturday, 24 October 2015

NES style game in Unity - Part 1: Limitations everywhere!

Hello there!

It was a long time ago I made anything useful on this blog. Well, because I started to make a game, I feel I should share a few thoughts about it for You!

I was thinking about a platformer game a long time ago. Something that represents the good old days, the age of Nintendo Entertainment System.


Let's see the list of issues, the limitations of the original NES.
My project aims to recreate a game that if you look at it, you immediately say, it's an NES game! Many games tried to that or wanted to look something like that. A really well known example is Shovel Knight. Yes, it's a really amazing game with 8-bit NES style graphics. But is it something that could run on an NES? Was the hardware capable of that level of graphics? Actually NO.

Shovel Knight has some graphical solutions that couldn't be on NES. Some of the characters have way too many colours, there is background scrolling, wide screen support, etc... I don't want to go in-depth about it, there is a really great article on the internet about it. So technical limitations are huge on NES and many developers started to make different chips that could extend the capabilities of the system. Like the MMC5 memory management mappper. But still, with these that game could not happen as it is.
I am not aiming to break the NES. I am aiming to make it as true as possible to it. Trust me, it's not easy! My development is in Unity engine which excels in 3D. But the 2D capabilities are a little bit poor. It has 2D support, but it doesn't have tile editor built-in (but there are many third party solutions). There is the color limitation, the resolution limitation, the pixel-perfection. Let's see these in details.

Resolution

NES supports the resolution of 256x224 for PAL, 256x240 for NTSC systems. You can't just set your monitor to these resolutions so you need to scale up the graphics. If you just use a bigger resolution in Unity like 1024x896 as your visible gameplay area, it'll cause a little issue.

Pixel perfection

This is one of the things that can ruin the experience. As the graphics are scaled up, you can see large colourful pixels. And suddenly a wild pixel appears between two other pixels! Oh, how horrible. It breaks the illusion. So you need to snap the pixels to different values. How to do this? Well, one method is writing a pixel snap script, that I made and well, it works great, but I am not happy with it. In Unity, my character's hierarchy looks like this:

-character (contains: kinematic rigidbody2D, raycast based character controller, box collider, pixel snap script)
--character sprite (contains: Sprite renderer, Animator, few other scripts)
So that script solution works if I place the game object with Sprite Renderer within the game object with the controller.

The snap script just rounds the position of the object. In my case to 1/16 units precision (configurable).

The other method that I couldn't figure out in practice is basically vertex snapping. My idea is to modify the built-in sprite shader to make the vertex positions rounded just like in case of the pixel snap script. But this one would make work easier, so I would not have to attach a script to the game object, also that parent-child hierarchy should be gone. In case of large amount of sprites, it would be a pain in the ass to do that all the time. Well, using prefabs helps and obviously that the right way, but if the shader itself could do the pixel snap, it would make the difference.

UPDATE: the shader is finally done! Not perfect, since the sprite renderer doesn't generate a perfect rectangular mesh which can cause mesh distortion at rounding the values. But with the rounding value of 16 (which I exactly need), it works perfectly.

Colour limitation

NES has a very limited palette which contains 64 colour. Well, a little bit less, since there are more than one black colours (ten to be exact).

Background elements can have 3 colours from four different palettes at the same time and one shared background colour. So 12+1 colours on screen per palette. Important to note, every 2x2 block needs to share the same palette in case of backgrounds, some mappers (like MMC5) can make it possible to remove this restrictions. Probably I'll ignore the restriction in my game.

For sprites, the rule is similar, four palettes with three colour, and transparency. 12 colours on screen which means 25 colours in overall on screen. The palettes can be changed on the fly for different effects like fading, or change the character's colour like in Megaman. Note, that if you change a palette for one thing it'll change the colour for the other things that shares the same palette. For example, in Castlevania III - Dracula's Curse, if you changed character, it replaced one of the palettes and that palette was also used for moving platforms which means, if you played as Sypha, the moving platforms were blue and white, if you played as Trevor, the colours of the platforms were brownish.

For the colour limitation, I made a palette generator which reads the colours from a 64 by 2 pixel uncompressed texture. I downloaded an NES palette and made this texture based on it, actually it's easy to replace the palette to an other one (currently up to 64 colours).

NES palette generator in Unity
Palette generated from the texture, you can pick a colour to replace from the palette. Thanks to the shader and simple scripts it changes the colour of the sprite immediately.

Sprite limitations

As far as I know, NES can only handle up to 256 sprites. It's a pain in the ass actually. I don't know if I'll ignore it or not, but it sounds like a huge restriction to me. Just to make a character with animations that is 16 pixels high already uses a lot of sprites. You can share a few between frames in a few cases. I don't know if there was an expansion chip to increase this number.

Other limitation is that there can be only 8 sprites per scan-line. It's a known issue when sprites start to flicker in an NES game. It is because there were more than 8 sprites per a scan-line and they were visible every 2nd frame alternately.

I probably missed a few things and I'll complete the article later. As you see, there are many really annoying limitations of the system that's not really easy to copy in an advanced 3D engine. It needs many tricks to do. I want to make my game true to the original NES as possible. I'm sure I'll bypass a few limitations, but I'll try to make it more real than in the case of Shovel Knight for example.