My 2015 new years resolution was to write 12 Super Nintendo mini-games in 12 Months.
On 4th January 2016, I completed that challenge. A hard drive crash prevented me from making the 31st December Deadline.
I chose this challenge because I was in the middle of designing a SNES Game Engine and was very undecided as to how to structure/design the architecture. Before the challenge I had written:
- Structure Macros to simplify code reading
- Multiplication & Division
- Routines An over designed fixed width text engine
- Conway's Game of Life
After taking a break in order to clear my head, I came across the 1 Game A Month website and decided I needed to prototype the various aspects of a Game Engine to see if they were suitable for the SNES.
Each demo incorporated some aspect of a SNES Game Engine within it. This allowed me to effectively prototype each stage and estimate how much CPU time it needed.
- A better way of arrange my code.
Each demo used a slightly different way of arranging code as an experiment. Some separated code into modules, others used submodules.
From this I have created a reliable layout for large assembly projects.
- An effective way of creating pseudo-classes in my game engine.
Each class is accessed via Direct Page manipulation and called using
Function Tables accessed with
LDX z:classStruct::functionPtr ; JSR
(addr, X). Classes can be extended by using assembler macros to
ensure all subclasses use the same memory locations as the base
class. All classes are the same size to prevent fragmentation issues.
This does limit me to ~7.9KiB of RAM for class instances (126 instances @ 64 bytes per class), but I gain an extra index register for my code. As I'm only going to use it for moving objects and particle effects, I don't see a problem with it.
- 8 bit CPU tricks.
I've learnt how to squeeze a few extra cycles out of the 65816 just by changing how the data structures are arranged in memory (Structure of Arrays vs Array of Structures, Linked Lists vs Tables, etc).
- Unit testing to find bugs is easier than reading 65816 assembly traces.
Before implementing proper unit testing, debugging consisted of:
* Noticing a bug * Duplicating the bug * Reading the assembly trace-log to determine how the bug occurred. Sometimes I had to read the trace and the source code side-by-side to parse what is happening. * Changing the code and recompiling it. * Setting a breakpoint at the routine I changed to verify the bug is fixed.
And even then some slipped through the cracks. There was signed-comparison bug in my original collision detection code that prevented collisions from occurring at the edge of the map that remained there for seven months (even though I reused the code in four different games).
I started properly unit testing my low-level code in November and its already caught some strange edge-cases.
After unit testing, there still was a bug in my new MetaSprite routine, but after checking the memory I realised what went wrong, wrote a test to check for that condition and set about to fix it. The process was about three times faster then the old one.
That's not to say everything will be unit tested. So far I'm only testing the low-level stuff that is most likely to fail.
- Perfect is the Enemy of Good.
There are lots of unfinished bits of code in my mini-games. If my perfectionist tendencies had interfered with the code, many of the mini-games would not have been released.
- I do not have to process everything in a single frame.
Bat Cave splits its map generation algorithm into two. On one frame the map is drawn to the framebuffer. On the next frame the new segments of the map are generated. Without this, I would have had to scrap and rewrite the vertical line drawing code with a complex bit-twiddling optimisation.
- Playing a game on a SNES controller is very different to playing with an xbox360 controller or a keyboard.
My new game engine is going to be tested on a real SNES first, emulator second.
I'm thinking of adding a custom controller type to bsnes-plus so I can take advantage of an analogue joystick in future games.
I'm taking the practical experience I gained this challenge to write a Metroidvania SNES Game Engine.
I will document the process in this blog to all of those who are interested.