I only recently got into the whole game-jam phenomenon. To be perfectly honest, I had never even heard of it until about a year ago when I stumbled across Ludum Dare and its wonderful creations. By then, I had been dabbling in game development by my lonesome (on and off for some years), and LD seemed like a brilliant way to focus my energy into a singular project with a short development cycle, as well as show off my creations and get involved in a wonderful community. It was brilliant.
Some jams later, I prepared myself for yet another sleepless weekend. The checklist of poisons was ticked, my development platform was sturdy, and I had even found two friends who were eager to get involved. And from those humble beginnings of the Ludum Dare #31 weekend, the Mortuus Est project has blossomed into a semi-fulltime (if there is such a thing) game project.
The 72 Hours of Jam
The decision was unanimous – we were going to go full-cliché and develop yet another zombie shooter. Cringing aside, we did have a slightly different vision of the end product than what you would imagine. You see, we had an artist among us. A hand-drawn, top-down zombie shooter is what would emerge from the weekend of toil. At least, that was the plan.
Some pen-and-paper designs later we had the basic concepts in order: top-down perspective, linear levels, fixed-direction aiming, multiple weapons, and a number of obligatory zombies to fight off along the way. Hell, we even made layout provisions for an Android port down the line. I dug up a custom libgdx framework I had knocking around my harddrive and we got to work.
The basic framework was that of an MVC pattern – the WorldContainer contains the objects in the world space, the WorldController controls the game logic, and the WorldRenderer … Err, renders the world. Each object is of course completely self-contained, following the basic principles of OOP, and most implementations revolve around enumerated lists as states. Static variables were also a great help, and I coded some simple, methodless developer-variable classes to store much of the values involved in balancing various aspects of the game. You know, just to save scratching through miles of code to change naughty values.
Some rectangular obstacles and circular human fixtures later, we got to work developing the zombie AI – a simple system that calculates the angle between the zombie and the player, and moves the zombie forward in this direction. Of course, pathfinding was not on the agenda – you can’t build Rome in a day, so we settled with a small shed.
A simple collision calculation determined if the player was in contact with the zombie or not and, appropriately, this spelt the death of the player. And immediately too – no sissy health-regeneration or multiple lives here! Projectiles were handled in a similar way – a body with constant velocity, created with forward velocity and spawning at the player’s point of origin. The zombies had a basic health system, and their well-being wasn’t too fond of being hit by the small red line segments that we called projectiles.
It was an early decision to implement an in-game level editor because programmatic level design is like trying to dig a hole with a spoon. This allowed us to slap together a full-on level, executable as an object creation script, and test the mechanics by spawning some cannon-fodder. It was all starting to come together.
A simple HUD for keeping an eye on collected cash and ammunition was in place. Next, it was time to implement different weapons. A separate weapon controller was created and instantiated within the player class. It uses an enum list to track the currently selected weapon and a facade design pattern where calls to fire rate, projectile damage, projectile speed, and so on return the value associated with the currently equipped weapon.
Within the player class, a new class was defined to take on the role of the inventory. This uses booleans to keep track of owned weapon and applied boosters, integers to store ammo reserves and cash, and enums to store modifications to each weapon.
And all the values involved in balancing were stored neatly in the DEVVARS developer variables class. I’ll go into detail about some of the core code and algorithms in a future article.
Because things were now getting a little more involved, we decided to get the texturing systems in place. Google was our best friend here, and multi-coloured 2D crates and the Android mascot were used to represent our environment. It wasn’t long after that when we had some simple textures to implement. Left to her own devices, our resident artist had turned multiple A2 pages into suitable textures that we photographed, photoshopped, and implemented into the game. It was all coming together quite nicely.
And then we scope-crept.
You see, we were starting to fall in love with our clunky little game. “No this doesn’t feel right, I think this would be better… Oh, you know what would be great? Unfathomably large systems that in reality take weeks to implement – we need those.”
More advanced boosters, weapon modifications, more zombie types, buying interfaces … It was all too much. Too much for a 72-hour time-frame anyway. In the end, we fiddled and faffed, and when it came time to submit we were short many textures, an entire sound engine, and, most importantly, playable levels. Although disheartened, we enjoyed our odd little machination so much that we decided to continue developing it post-jam. Little did we know that it would become a project that would take months of on-and-off work.
Taking It Further
Now that the jam was over, I could sit back and examine what we had done. The nature of a game jam forces you to spew out code, with time constraints leading to a lack of neatness and performance consideration. I had to spend a long time refactoring the mass of spaghetti-code that was Mortuus Est. I commented, optimised, and debugged the hell out the source, and this gave me a great base to continue from.
The developer variables class which I had used had grown far too large for its own good. With hundreds and hundreds of lines of values, it had to be divided up. A few months down the line, I’m now sitting with 5 separate DEVVARS classes and I’m looking at dividing further. All in all, there is roughly 500-odd variables in those classes.
There are also controllers everywhere – for projectiles, zombies, weapons, zombie navigation, levels, HUD, in-game text, audio, the world itself … It’s like a regular menagerie of logic bombs. The models package has also grown considerably, keeping all the weird and wonderful creations safely at bay and neatly organized.
One thing worth noting is that I can’t get enough of random number generators. If there is a possibility to throw a random result in somewhere, I’m on it like tie-dye on a hippie. I love the subtle uniqueness that it adds. From randomized shadow directions, to textures, to blood rotation, colour, and scaling – it all adds up.
The funny thing is, even with all this progress, we’re still sitting with zombies that don’t fall over when dead (no textures for that), a complete and utter lack of any sound in the game, a subset of the icons needed for all the different items, and no main menu – just a kooky developer level that I spawn into in order to test my creations. It has every possible purchasable and collectable all neatly lined up, a few level loaders so that I can ‘teleport’ to playable levels, and a zombie petting zoo so that I can safely shoot the crap out of them and they can’t get to me in order to rip my brain out. It’s my little sanctuary.
For now, the journey continues. I have a scope to stick to, a roadmap that I am following, and final vision for the game. It’s fairly late into the project and the infamous final build is my goal. Hopefully the release date will be in the coming months – well, at least that is the plan.
Credit Where Credit Is Due
- Kevin Baynham – Programmer
- Cilliers van Rooyen – Game and level designer
- Samantha Nolle – Artwork and development feedback