Week of Awesome 5 – Post-Mortem

Well the 5th Week of Awesome Gamedev competition is over! It’s incredible to think that this thing has been running for half a decade.

So the way this competition worked this year is that there are four themes announced at the beginning of the week, which were: Chain Reaction | Alien Invasion | Assassination | Castles.  And each contestant needs to pick two of those and make a game around them, with a week to do so.

My game was “Invasion of The Liquid Snatchers!”.

The Idea

Straight away Chain Reaction and Alien Invasion spoke to me as strong themes that would go well together. I had vague ideas for the other themes too so I spent my 1st day conceptualising ideas for different mixes of themes and trying come up with a viable concept.

In the end I settled on an idea where the game is staged from the perspective of an alien species who are invading Earth to harvest its resources. You play by helping a handful of blue-collar (manual labour) alien minions to undertake the “behind the scenes” activities of an on-going invasion. Activities such as processing Earth’s resources or refuelling a wave of saucerships.

All of this would be driven by the use of the Earth-bound liquid resources that they had been collecting. Water, Magma, Oil and Nuclear Waste were the 4 resources that I settled on. From there I really, really wanted to try and manifest these using a real-time fluid simulation, because that just seemed like a novel and somewhat challenging thing to do – which is exactly the whole point of the gamejam for me: To push myself and do something different.

Each kind of fluid would serve a different function in the game: Water activates hydraulics (raises platforms or opens doors), Oil activates machinery, Nuclear Waste powers saucerships and Magma is supposed to be used by the aliens to forge saucerships.

The chain reaction theme would feature by way of the environment changing in response to these liquids (hydraulic platforms activating or mechanised gears rotating, etc). Most of those changes would be good and allow progression through the level but others would trigger “hazards in the workplace” such as having a row of missiles lined up to fall like dominos that end up crushing your minions!

What Went Well?

Let’s see…

  • Time – I had the week off work. Never done that for previous years where I’ve always worked during the week. So this year I had a lot more free-time in comparison. I didn’t spend it all programming mind you, but it was just nice to not have to hold down the day-job and then spend my evenings coding as well!
  • Existing code-base – From the previous two times I have competed I have built up a thin framework over the top of LibGDX which really helps me hit the ground running. Mostly it’s just resource caches for textures/sounds/etc and some ‘fix your timestep’ gameloop stuff. Nothing too fancy.
  • Shaders – My fluid simulation is rendered using a custom shader. I’m no shader expert having written a merely a handful of simple shaders in my time.Shaders cause(d) other people a lot of agro where their games don’t work on other GPUs, etc. For that alone I tend to avoid them generally. But this year I couldn’t, not for the fluid anyway. Fortunately I had very few issues with the shader authoring. I’ll write a bit more about how the fluid sim works in a follow up technical post.
  • Audio – I was able to find online several soundbite recordings of water sloshing around (each 0-2 seconds long). I picked several that sounded good and classified them into two sets: One for water being emitted and one for water being collected. Then to create the seamless sound of running liquid I select a sound snippet at random every 1 or 2 seconds and play it with sufficient falloff and overlap with the previous snippet while also making sure to never play the same sound twice in a row because humans are too good at noticing repeating patterns. It sounded pretty bad at first but after a but of tuning I’m quite pleased with the end result.
  • Art(?!) – As I say every year: I don’t attribute myself with much of any digital graphics design skills and I’m colour-blind which is a huge pain in the ass for this sort of thing. So I try to mask my artistic failings with code. But I surprised myself with the art work this year, it kind of works I think?! For the first time this is ALL my own art work, I didn’t take anything from the interwebs, I just used Paint.Net and a lot of it is drawn free-hand with the mouse.

What Went ‘Not So’ Well?

  • Liquid CPU performance – To begin with I simply assumed that performance wasn’t going be an issue in my little old game. I was wrong. It took some ingenuity to prevent the sim from becoming a bottleneck. Fortunately I have a copy of JProfiler which is my favourite profiler for finding performance hotspots. I’ll write more about that in the follow up post about the fluid rendering.
  • Level creation – In previous years I would implement an ASCII-based level format that gives a reasonable-ish approximation of how the level will look on-screen. The idea works ok for purely grid-based worlds but it doesn’t scale very well with multiple layers or when things are not grid-aligned. So this year I spent some time mid-way through the week to write a crappy in-game interactive level editor. Even with that I found it very hard to create engaging levels. And since my game is heavily physics-oriented I had to account for all sorts of “physics bullshit” in order to get each level to a point where it is deterministically solvable by the player and not just a big mess of physics stuff that may or may-not play out.
  • Box2D Determinism – It is my belief that Box2D is supposed to be deterministic (as long as the input is the same and the timestep is fixed – which it is). Yet I am definitely seeing slight variation from run-to-run. So I can’t explain that yet. I need to investigate what the ‘f’ is going on there. For this time around I just decoded to design around the problem.

Reception So Far…

So far I have had very positive reviews. First and foremost I’m very pleased to hear that people enjoyed the game.

Many/most of the criticisms I’ve received are about things which I completely agree with too, so no surprises there. I would definitely have fixed them where this not a week-long development. There’s just not time to do everything unfortunately.

It’s not known yet how all the judges feel as that still remains to be seen.

Riuthamus (one of the judges) live-streamed his play-through of my game on Twitch. It was hilarious! He actually found some pretty decent ‘alternative’ ways of solving one or two of the levels that looks to me every bit as good as my intended solution. So that’s fine by me! It was great fun to watch and valuable feedback too.

So How Does That Fluid Simulation Work Anyway?

One of the biggest compliments I’ve had is when people think the fluid simulation is a soft-body physics or a true fluid simulation. It’s really not 😛

I’ve decided to write up a technical article about the fluid simulation and rendering process which you can find over here.

That’s A Wrap!

I had good fun over the week and just want to extend a big thanks to the competition organiser (slicer4ever), to the other judges and to the prize-pool contributors.  They have all done a fantastic job at making this competition happen! Every year I see the competition evolve in very positive ways!

And good luck to all the contestants!

Week of Awesome IV – Gamut of Blob – Postmortem

Embarrassingly I haven’t used this blog in 2 years and that was for my WoA2 postmortem!

Well WoA4 is over and I am super pleased with my entry. It is somehow more complete and polished than I had anticipated to achieve considering I had a full week of work and a couple of weekend commitments that would see me Macbook-bound for the majority of the weekend.

This year announced 4 themes and contestants were expected to select and incorporate 2 of these for their game: Shadows, Evolution, Ruins, Undead.

A restriction was that Shadows and Evolution had to manifest as gameplay mechanics, whilst Ruins and Undead would need to manifest as graphical theming. Since I am no artist, it takes me a long time to produce art and I have no experience producing art of any kind on a Mac, I decided to opt for the 2 gameplay themes: Shadows & Evolution.

Scope is always an issue in any project. So I took the entire Monday just to let the themes sink in and try to come up with an idea that was appropriate in scope for the free-time I had. I was open to extremely simple games like Flappy Bird but I simply could not marry that up with the requisite themes (evolution, shadows, ruins, undead) in a way that enthused me. Also under consideration was a farming game where veggies are bred and transmuted to achieve a desired phenotype with a supply & demand mechanic driving that, as well as some kind of underwater game like flOw. Both interesting ideas but were too ambitious.

The idea I went with was top-down maze-puzzler with minimalist graphical look featuring cute little blob creatures. Gameplay-wise I was partially inspired by games like Chronotron or the Clank levels from Ratchet & Clank: A Crack in Time. In these games there is a way to generate multiple versions of yourself which must collaborate together to finish the level, things like standing on buttons to open gates. While I did not include their time-travelling mechanic I do have lots of cute little blob creatures running around standing on switches to banish shadows and allow fellow blobs to progress. Blobs can replicate themselves by finding DNA/gene fragments in the level; picking these up will spawn an evolved blob friend, each blob colour has a unique skill which allows it to access parts of the map that your regular unevolved green blob is unable to reach.

day6 (3pm)

The great thing about this idea is that it scales up/down depending on how productive I am: If things go well I can always develop new types of blob which enables new gameplay elements. If things go slowly then I can scale back on my ambitions for lots of different kinds of blob and focus up on just getting *something* done. My original plan included 5 types of blob:

  • Green – The standard unevolved blob
  • Blue – Able to swim and pass through water.
  • Red – Tolerant to extreme temperatures and can walk over lava.
  • Purple – Resistant to the genetic stresses of teleportation and can use teleport pads.
  • Yellow – Speedy, takes long straight paths very quickly and does not stop until it hits a wall.

I probably could have implemented all of these if I had sacrificed some polish but I didn’t want to do that.  In the end I managed all but the Yellow blob, not bad at all! And I don’t feel that the game has suffered at all.

One of the hard-learned lessons from previous years was that starting from a position of no code (just an empty main() method) is tough going. I end up spending a good 2-3 days just knocking out basic infrastructure (resource management, game-states, sprite-rendering, audio, physics, etc). So this year I prepped a very light-weight game-agnostic framework based on LibGDX to handle all that. This was a massive productivity boon and this ‘engine’ wasn’t at all constraining either having received only a minimal amount of frantic hack’n’slash near the end, which I will probably refactor and generalise for the future!

Something that didn’t work out as well I had hoped was the level file format. I used a similar format to my WoA2 game which worked very well for that game. However this time around I had lots of layers to the map and keeping them in-sync was an error-prone head-ache. Some kind of level-editor would have gone a long way to ameliorating this but there wasn’t time for that kind of development. Perhaps for next time I can generalise the concept of a tile-based level editor? Or learn to use an existing one and write an importer for its file format.

Overall, as usual, it was a lot of fun. Very tiring. But a lot of fun.

I have whizzed through playing the other contestants’ games (need to go back and play some of them for longer) and I have to say that I really do not have a good sense for where my game will place amongst them once the judging is over. As usual I am blown away by what people are able to achieve in a week!

Congratulations to everybody who managed to submit an entry. I am looking forward to next year’s competition already! 😉

Save My Toys: A Walkthrough (Week of Awesome II)

First off I am delighted to have placed 5th in the competition overall!

Due to the great response I’ve had to the game, from other competitors and the judges I have decided to record a quick playthrough of my Week of Awesome II competition entry: Save My Toys.

The video quality is bit low but this shows the full extent of the game and the solutions I originally envisaged – although some levels have multiple solutions either by design or not quite intentionally.

Enjoy!

“Week of Awesome II” – Post-Mortem

Amazingly it has been a whole year since Gamedev.net hosted the first Week of Awesome competition. I competed last year and wrote a post-mortem of my game so it’s that time again! A bunch of people have already written up post-mortems, which is great to see. As far as I recall last year only a couple of us did.

This year the rules were much the same: A theme is announced at the start and 7 days with which to implement that into a playable game.

Last year the theme was about what if dinosaurs were still alive. This year the theme was “The toys are alive!“. I’m beginning to notice a sub-theme going on 😉

You can download my game (with a few bugfixes) here: Save My Toys.zip

Save My Toys!

 

What follows is my post-mortem, covering how I approached the problem and how I thought it went after-the-fact…

 

Early Considerations

Before even knowing the theme there are some considerations to make.

  • I am working by myself on this.
  • I am a good programmer (I think) and precious little else – Not an artist, sound designer, level designer… nothing.
  • We have only 7 days available to build/test/polish a game and I have work on 5 of those too.
  • I believe the secret to a good entry is to have a simple idea that is executed well. (The secret to a winning entry might well be a big idea executed well, but that’s something else entirely)
  • When brainstorming ideas it is important to stop and think about how that idea will rack up points from the individual judging criteria. Which include categories like graphics, gameplay, sound, etc.

With these things in mind there is no chance of me making an asset-heavy game. If it requires 3D meshes, skeletal animation, complex sprites, custom sound FX, complex manually-created levels — basically anything like that. It won’t work for me. I am more or less limited to a 2D game with simple, (mostly) static sprites. Last year I got around this by going for a deliberately over-simple MSPaint look and procedurally generated levels, I wanted to try something a bit different this year though.

Additionally it goes (almost) without saying that scope will be a constraining factor here, and feature-creep is an ever-present enemy of any project.

Toy Theme & Brainstorming

The toy-related theme was challenging because it’s not an abstract idea (like “Light vs Dark” say). I concluded that one simply cannot get very far without actually rendering some toys to the screen at some point – and asset production is a major nemesis here.

Being a cutesy theme I wanted some cutesy graphics and was reminded of an artist called Kenny who had posted on GDNet some months prior to tell us all about his free-to-use tilesets that he’d created. I was impressed at the time and quickly hunted them down: http://opengameart.org/users/kenney This guy has done a wonderful thing because are all licensed to Creative Commons Zero which puts them in the Public Domain, as in totally freeballs!

It’s hard to pass up a resource like that, so I very easy settled on the idea of a tile-based game. At this point I brainstormed 3 possible ideas:

  • Sokoban – The idea would be you play as “Mom” or maybe <Insert Generic Child Name Here> tidying away the toys who had up’d and littered themselves around the bedroom during the night.
  • A Rodent’s Revenge variant – Except obviously instead of cat and mouse, the toys would be defending themselves against some kind of enemy (maybe Mom is the enemy?)
  • A Lemmings variant – You control a stream of alive toys who are just trying to get home.

I decided to discard Sokoban. As a core idea it is too simple – I would easily have that game polished in just a few days which would be a waste of the full week. At the same time the prospect of extending the gameplay is daunting. It turns out that the impressive thing about Sokoban is not the gameplay itself, it’s the fact that some poor guy once managed to dream up those devilish maps!

Rodent’s Revenge didn’t really inspire me enough so Lemmings it was! This was always going to be a favourite idea as I have long wanted to make a Lemmings variant.

I began researching for ideas that would be a good fit for a tile-based version. In original Lemmings you assign individual lemmings to specific tasks and they add/remove terrain pixels which alters the flow of those low-res dudes. I had a simpler idea in mind where the Toys are completely self-autonomous and instead you indirectly control them by adding behaviour-altering tiles to the map (like making them jump, turn around, land safely, explode, etc).

I drew my early inspiration from a game called MinimaLemmings; my research indicated that this game has been cloned/re-skinned by others. I didn’t want to clone it but I really liked the core idea of placing jump tiles, so I “borrowed” that and consequently paid homage to them by roughly basing Level 5 “Difficulty Gradient” from their first level. The forces and velocities between my game and theirs aren’t the same, so I was surprised to be able to mimic that level so easily to be honest!

 

What went well?

Sprites & Animations

Kenny’s tiles are great, not only are they a source of inspiration all on their own (mushrooms!), but they work beautifully in the game. At least I think so, I *am* colour-blind so take that sentiment with a pinch of salt 😉

I drew all the toys and their animation frames myself (and the angled mushrooms). Granted they are very simple but I am no artist so I am pleased with the result. I think the cutesy animations work well with the rest of the game.

Level Design

To some extent, this remains to be seen as they haven’t been extensively play-tested yet. For all I know there are flaws in them. That being said, I am pleased with the number and quality of the levels I managed to produce.

The fact that this year I was making a game which would require manually-crafted levels was a major concern to me all the way through, at least until day 6 when I had managed to put a few together finally. In the end I managed to produce 10 levels in the game, in increasing difficulty, although the early levels are really quite easy and exploit low-hanging fruit in terms of level design.

To help ease level production and mitigate the amount of time spent fixing level design flaws close to crunch time I came up with a file format that could convey the shape of the level straight from a text file – quick, easy and low-tech!

For example, here is level4.txt:

<level name="Hazards can be Hazardous!">
    <rescue>10</rescue>
    <map>
        X . . . . X X X X X X X X .
        # . . . X # # # # # # # # X
        # . . F # . S . . . . . . #
        # . . # # # # # # # . . . #
        # . . . . . . . . . . . . #
        # . . . . . . . . . . . . #
        # # # X X # . X . X X # X #
        # # # # # # . # # # # # # #
    </map>
    <spawnerConfigs>
        <spawn amount="10" freq="0.5" />
    </spawnerConfigs>
    <inventory>
        <blockers available="5" />
        <jumpSingle available="5" />
        <jumpDouble available="5" />
        <jumpLeft available="5" />
        <jumpRight available="5" />
    </inventory>
</level>

I opted for “convention over configuration” when it came to levels, meaning I could trivially add new levels just by dropping a file called “levelN.txt” (just replace ‘N’ with a consecutive level number) and the game will load to it when appropriate. No need to register the files with the code.

Time Management

Unlike last year I was more or less on top of my time management this year. My minimum viable entry was essentially ready by some point on day 6 so I had a whole day and half to iron out bugs, design levels and apply other polish.

Part of the reason for this was that I had learnt lessons from last year which minimised the amount of time I spent hunting down terminal bugs. I cpy()’d my Vector2’s, I deferred my Box2d deletes and I had last year’s readme to point me in the direction of good sites to find free fonts and sounds!

Building, Packaging & Deployment

On the week prior to the competition I spent a bit of time nailing the build, package and deployment processes. As this was something that very nearly sunk the ship last year since I left it till the last minute.

First I bundled a complete JRE with my game, so no external dependencies for judges to install! Until the promise of a modularised Java 9 comes out the current JRE is still huuuuge so I had to trim it down a tad. Oracle publish a list of optional files and note one big-ass uncompressed JAR that can be compressed. By eyeing it up, I reckon the JRE is still way fatter than I needed but unfortunately Oracle doesn’t permit you to remove anything further for licensing reasons.

I also needed a way to connect my game with that JRE. A batch script would do it but isn’t very pretty so I found a project called Launch4j which creates an .exe that will launch your JAR for a given JRE – perfect!

Finally, LibGDX (the simplistic game framework I was using) has radically changed their build process since I last played with it. They now use a tool called Gradle, which is a coming together of Groovy, Ant and Maven into a single build tool. It’s quite swanky but I am not familiar with it. So I had some tedious “fun” getting all that to work correctly.

By doing all this the week before, I could just focus on the game itself.

 

What went wrong?

Non-gameplay Screens

Those following my progress updates during the competition would have seen that I posted a few times about getting non-gameplay screens working. My update loop, input handling and rendering were so slapdash that it wasn’t possible for me to handle anything that wasn’t “in-game”. I decided to expend a bunch of time refactoring them to support non-gameplay screens and I ended up re-inventing the old idea of GameStates once again.

Unfortunately I spent so much time doing this that in the end I didn’t have the time to fully exploit the feature. My final game has only 4 states:

  • Start screen
  • Text-based intro screen
  • In-game
  • Text-based end-game screen

Whereas I planned to have highscores and level-selection screens. But hey ho.

The idea and implementation of GameStates is very generic but very useful. I think for next year I will prepare in advance an empty LibGDX project template that includes a GameStates implementation from the beginning.

Box2D is a Physics Engine and will always want to be a Physics Engine!

I coped with this by staying calm. But I know that Box2d is basically a poor choice for the movement controllers in my game.

What I really wanted was:

  • Non-physical horizontal movement but fully-elastic rebound off walls.
  • Gravity (read: physical vertical movement) but completely inelastic landing on floors.
  • Non-physical (but physically “believable”!) jumping movements.
  • Collision detection & resolution (but NOT involving conservation of momentum, etc).

You basically have to fight Box2d to get the non-physical behaviours that you want. On the whole what I want is a colliding kinematic simulation, not a dynamics simulation.

I could probably write one myself, but not in the timeframe of the competition. I decided it would be wiser to fight with Box2d and get the result I wanted.

The magic here basically amounts to tracking velocity yourself outside of Box2d and just keeping the simulation in sync using setLinearVelocity(). Gross but it works.

Additionally, to get completely plastic collision against the ground working well, I had to implement a ContactListener and disregard the contact entirely. To start with I was just detecting the case using the impact normal and calling setLinearVelocity with a zero’d vertical component to remove any bounce, but it was producing visual artifacts (I presume because it was – by necessity – spread across two update cycles with a frame rendered in-between).

Lots of hair-tearing fun to be had all round! Like any framework though, it’s a matter of becoming familiar with its foibles.

My Upload Speed

I always forget how crap my home internet is. It took me 20 – 30 minutes to make an upload. What I should have done is get it all setup on my work PC, remote into it and do the upload from there!

Since I was making incrementally more-finished uploads as the competition drew to a close I ended up losing a couple of hours total just managing my uploads – each one was very tense and I could hardly focus on code while one was going on. I would have liked to churn out a couple more levels, but nevermind.

 

What got Cut?

With more time I would have extended the player’s tool-set to include one-way barriers and explosives (sacrifice a toy to carve a route through for others in its wake – ala traditional Lemmings blowing up).

I would also have liked to explore the lock-and-key mechanic more. I had different coloured lock and key sprites, which would have been used for more complex puzzle logic. I only managed to make a couple of levels involving these, which doesn’t do it justice really.

I also wanted a level where you have a stream of toys that spawn at a slower frequency and you exploit that to split the stream into two teams which head off in different directions simultaneously.

In-game-help – Like last year I wanted to introduce signposts that would popup helpful tips and comedy relief. Some signposts would be off the critical path and only there for the hard-core players to reach.

Gems – Some kind of collectible that would encourage replay and allow for gauging how good a particular solution was.

Water – I had spikes and water was essentially just another hazard. I had pondered the idea that maybe only the ball and the duck could cross water tiles.

One-way Platforms – Currently solid blocks will block from all directions. But there was an occasional need (that I had to work-around in the level design) for a platform tile that could be passed through from the under-side but would be hard like a floor when landed on.

 

Final Thoughts

Once again the competition was a load of fun. It eats a week of your life but the result always feels completely worth it.

I have played many/most/all of the other entries and they are impressive to say the least. Those made with Unity are of particular interest because the pace at which those contestants could churn out gameplay was staggering. I think I will have to spend some time getting to grips with Unity at some point – who knows maybe next year’s entry from me could be Unity powered!

It is interesting actually, the shift in technology choices since last year. This time around there were a lot of people using Unity and other engines. Last year there was a high percentage of Java/LibGDX entries, but only 1 or 2 this year. I expect next year will be even bigger and badder as the competition gains visibility and people improve their skillsets.

Since I was using github to keep my codebase in sync between home PC and travelling laptop my code is (and always was!) available online. But I have spent a bit of time today converting my readme to markdown and cleaning up directories, etc. You can find the repo here: https://github.com/daveagill/WoA2

Now it’s all in the hands of the judges.

Good luck to everybody!

My “Week of Awesome” Competition Entry: Post-Mortem

So it’s been a while since I last posted but here I am writing a new entry!

The other week I competed in the unofficial GameDev.net ‘The Week of Awesome’ game development competition. The idea is you’re given a week to develop a game and the game must fit a theme which is only announced at the very start of the competition. The theme was: “What if Dinosaurs hadn’t gone extinct?” There were various takes on the theme, all of them were good ideas.

My take on it was that the dinosaurs didn’t go extinct because, after the meteorite hit, they came back to ‘life’ as zombies. Clearly then the hordes of dinos romping around are the bad guys. To bring a good-guy into the mix (and therefore the player)  I settled on the idea of Granny who was on her way out to the Bingo but is highly inconvenienced by the zombie dinosaurs; hence her reason for kicking some zombie-dino butt.

For anyone looking to download my entry, you can download it here: Granny v.s. Zombie Dinosaurs. You’ll need at least Java 6 to run it.

Planning

The first thing I did was to plan the game. I don’t think you have to plan every aspect of something before you start coding. I’m a strong believer that requirements can rarely be gathered in full in advance and they will change once the thing begins to take shape and new & improved ideas begin to form in peoples’ mind. Maintaining a level of agility is important and, let’s face it, we’ve only got a week to develop a game. Analysis paralysis is something to be avoided.

Granny v.s. Zombie Dinosaurs - Planning 1

My planning involved sketching ideas down in a notebook. I already knew I wanted to do a 2D side-scroller with zombie dinos coming in from both sides of the screen so it was really the case of fleshing that out a bit:

  • What would the dinosaurs look like?
  • What would the main character be and look like?
  • What would the world look like?
  • Miscellaneous things: Weapons, pickups, etc

Granny v.s. Zombie Dinosaurs - Planning 2

One of the key things for me was to play to my strengths: I am a good programmer. I am somewhat creative and artistic but I am NOT an artist. I know nothing about making music, sound effects or animation. Sophisticated artwork would take time to produce; waste time even! The game needed simple graphics that could be produced quickly. Which means they either need to be abstract shapes that can be rendered by code, or they need to be simple sprites that I can knock together quickly in Paint. Since we’re talking dinosaurs rather than just squares and circles, I opted for the latter. I’ve always liked the idea of making a monochrome game, just two colours. Like as if you’re playing as silhouettes. So I thought I would test that out somewhat with this: White on Black. That would play nicely with my goal of simple graphics as there would be very little detail within each sprite.

Development

In keeping with the goal of playing to my strengths I opted to use Java for the development language. I use it everyday at work, so my present state of familiarity with the language is very high. For the graphics I chose LibGDX, which is a framework I dabbled with once before and it imparted a good impression. In fact, they have a swanky looking website now, so it’s obviously doing well. Turned out that 4, if not more, of the other entries also used libGDX so it must be gaining traction.

Since I was doing a 2D game I decided to stick to libGDX’s 2D framework, which is a high-level abstraction over OpenGL in the form of textures, sprites and batched-rendering. It’s easy to use, which is the important thing.

I wanted to have non-flat ground and I wanted Granny to be able to jump. This meant I needed at least rudimentary physics for gravity and ground collisions. Throw in the requirement to track collisions between Granny and dinosaurs (for them to inflict damage) and between Granny’s bullets and the dinosaurs – and I decided to just go right ahead and integrate Box2D (of which libGDX includes a JNI wrapper) to handle the collision detection and entity movement.

Granny v.s. Zombie Dinosaurs - Day-4I posted almost-daily progress updates on the GDNet forum topic, which included screenshots. The important thing was to stay focused; to always have it clear in mind what feature I’m implementing currently and which features I wanted to pick off next of all. Such as today I’m all about integrating physics, or today I want a highscrores table and improved blood, etc.

I made the deliberate decision not to worry too much about the code health as I won’t be maintaining it long-term. There are various devices in software engineering that slow down the short-term development in favor of improved maintenance and development costs in the long term. Things like coming up with a perfect abstraction and removing duplicate code, etc. By not doing these things you accrue technical debt that must be paid off later on, but if there is no “later on” then it’s a no-brainer that getting shit done fast is a Good Thing ™, especially for a competition. As a result I have plenty of duplicate code. Rather than trying to common-up the granny entity with the dino entity, I just have two classes: Granny and Dino. Both of these do a lot of the same stuff. I could have created an abstract base class for them both, but I was worried that I would need to slap in hacks at the final second and by having them share code would make that kind of thing harder to do.

I had it fairly well defined in my head that the World, Granny, Dino, Bullet, etc classes where “the model” from a traditional MVC architecture. I had a renderer that was obviously the view; it maintained all the sprite information and used the data from the model to paint the scene, quite literally something like: renderer.draw(world); I also had a WorldEvents class, which kind of acted like the controller. It would receive events from the input mapper, from physics collisions and from the World itself. Its job was to decide how to influence the model based on those events.

What I was less sure about – and still am – is about my handling of the simulation. For whatever reason I decided to couple it very tightly with the model. Most entity classes had a Box2D Body data member within them. The physics engine itself was hosted inside the World class and even besides physics, various bits of game logic such as dino spawning where handled by the World in its update() method. …Possibly all of that should have been extracted from the model… In which case the various entity classes would hold their own positional data and some external update loop would synchronize that with Box2D while also use public methods on the World to periodically spawn Dinos, etc. I think perhaps by coupling them together it simplified and sped-up the development for this game, but for a longer-term project separating the model from the simulation would be a good choice.

Sound effects where another big thing in this game. I only use 3 audio files, one of those is the background music. This was all done on the final day so it does look a bit hacked in. I had never implemented sound before so it was a cool experience. LibGDX makes it very straightforward affair. I know from perusing the DirectX audio documentation in the past that sound can be a complex matter but LibGDX cuts all the crap and has only a basic API that was all I needed. One of the interesting thing about audio (at least in libGDX) is that unlike most other things it’s a fire-and-forget type resource. You don’t have to advance through the sound frame by frame like you do with animation, or keep hold of any handles (you can, but it’s optional). You simply invoke the non-blocking play() method and it just begins to play. So it was an absolute breeze!

What went well?

A lot of it went well, I was fortunate really:

Spare Time – I had much more free time than I expected to get initially. Most of this allowed for better polishing.

LibGDX – A very pleasant framework to use. The only gotcha is that it’s high-level and even where it exposes just a simple JNI wrapper (e.g. around Box2D) there are no guarantees that it’s 100% complete. But if you don’t necessarily need all the bells and whistles then it’s a perfect choice for a Java media library.

Box2D – It is really easy to use and paid dividends in speeding up development. Initially I began to implement my own simplified physics for jumping but when I began to consider bullets firing, inter-entity collisions, blood splats, etc, I decided that Box2D would be a smarter choice. It took about a day to integrate whereas it would probably have taken me 2 days to implement all the physical interactions in my own code and fix all the ensuing bugs. When it came to implementing blood it took me mere moments to get a basic implementation up and running!

LibGDX also comes with a debug-renderer for Box2D, it is worth its weight in gold, so get that running early on! Being able to see visually how the physics is behaving relative to your own visuals is incredibly helpful and helped me nail tons of bugs much faster than I otherwise would have.

Granny v.s. Zombie Dinosaurs - CutsceneArt-style – Using paint for all the artwork (and Paint.Net to apply alpha) made for a unique visual style, almost like an animated Paint drawing. In the end I quite like it. It won’t win an awards for artistry but it hangs together well. Much better than mis-mashed images stolen of the internet would have. Or if I’d tried to actually do a good job at the artwork 😛

Animation – Bringing things to life is important. Static sprites sliding around just looks rubbish. It was pretty easy to add walking feet. I just tween across a sine-wave to create the swinging motion of the dinosaur’s feet and the up-down motion of Granny when she walks. If I had more time I would have animated her walking stick and the jaws of the dinosaurs.

GameStates – GameStates are full-screen states that the game can be in at any one time. For example there’s a game-state for actually playing the game, a game-state for the high-scores table, for the start-screen, etc. They can decide when to transition from one state to another, in effect it’s an FSM. I had heard about people implementing game-states like this before but wasn’t sure how well it would work out – turned out great for me. It made adding new features like the high-scores table really easy.

Granny v.s. Zombie Dinosaurs - SignpostsThe only state that is a bit iffy is the sign-reading state. Probably this shouldn’t be a state at all, just a boolean within the in-game game-state; I got it to work this way though, which just goes to demonstate the flexibility of the system. In fact it acts like a stacked state, it first renders the in-game game-state before rendering itself. I knew this would be the only stacked state though so I didn’t implement any generic handling of stacked game-states, I just had the sign-reading state handle it on its own.

I actually recently wrote about the game-state system on the GDNet forums.

Focusing on the scoring criteria – There were 5 criteria each marked out of 20: Graphics, Audio, Gameplay/fun-factor, First time user experience and Theme. I aimed to keep my graphics simple and the audio I decided just had to be simple and sensible to work well. The gameplay/fun-factor was always going to be a challenge, making something really fun involves a surprising amount of work and time but I decided that you can’t go wrong with a game that involves shooting things that squirt blood.

The first-time user experience is something I thought a lot of other entries might lack so I decided to try and win some points in this area by adding a cutscene at the start, comical in-game help along the way with the use of sign-posts and also a highscores table with humorous entries in and also a guaranteed position on the leaderboard for the first-time play through (i.e. 7 out of a maximum of 8 entries were pre-populated).

What went wrong?

Well, a number of things:

Being too ambitious – Partly this was deliberate, I wanted to use the competition as an excuse to play with graphics, physics and audio. It did mean it really took over my life for a week though and I was up against the clock at the end.

Co-ordinate systems – I should have nailed this one down early on really, but I didn’t. There are a few coordinate systems in-play within the game: Box2D has one on the scale of real-world objects (meters), the renderer has another one defined just as a scaling of the coordinate system used by Box2d in order to render it. The renderer also has regular screen-space coordinates (pixels) that is used for drawing the full-screen backgrounds as well as applying multi-part sprite offsets (e.g. for the legs relative to the body). None of that code is particularly well encapsulated and it was always a bit of a headache to remember which one I’m using for what and how to convert between them all.

Separating entity representations – The physical properties of an entity are held in one place, the rendering properties in another. They’re actually quite related values though; if an entity is physically larger the it should also be rendered bigger, right? It’s nice in some ways to keep them separate but it was a pain at crunch time to keep those values in sync. What I should have had is an abstract representation and the physical & visual properties be calculated from those. Arguably that might have been more work.

Floor/Terrain – This didn’t go wrong so much as it didn’t pan out to be as awesome as I initially envisioned. I had planned that there would be multiple routes through the game e.g. a high route and low route, done using foreground and background terrain as well as platforms which would further emphasise Granny’s jumping ability and add an extra dimension to the player’s decision-making which, as it stands, is pretty limited to just which dino to target next.

Granny v.s. Zombie Dinosaurs - In-gameIn the end I only had time to implement a basic continuous height-mapped terrain system. I did however make it infinitely auto-generate by selecting randomly from a set of a pre-made level-segments each with differing probabilities. I only had time to create 3 level-segments though: A flat segment, a step-up/step-down segment (see screenshot) and a hill. The camera also won’t follow Granny vertically so the useful height was effectively  constrained to about 5 units, when combined with the limitation that the terrain be continuous it pretty much  limits the amount of creativity possible when designing terrain segments.

Level Balancing – I didn’t get to spend as much time on this as I would have liked, in fact I only spent about a half hour on the run-up to the end of the contest configuring the gameplay difficultly and how that changes as you progress. This is definitely something I should have been more on-top of.

I implemented the concepts of Levels, which are actually demarcated by the signposts but I purposely didn’t want an overly explicit level counter, just continuous gameplay. As the player reaches each level the settings are adjusted to control how frequently the dinosaurs spawn from either side, which dinosaurs will spawn (and the likelihood of spawning any given type of dino), which floor segments will be used  to auto-generate the terrain (and again to what likelihood) and the frequency of spawning ammo-pickups. I managed to define about 7 levels (with the final level being a never-ending one) that gradually introduce more complex terrain, more kinds of dinosaur, more frequently spawning dinos and all the while have the signposts introduce the new content as the player progresses.

It worked out okay but it was sheer fluke that my level-balancing was as good as it turned out. That said, it seems like you cannot progress past about level 5 when the stegosaurus are introduced since I simply don’t provide enough ammo to take them all out. Fortunately, by that point, all the game’s content is introduced except for a couple of non-helpful, comedic sign-posts; the remaining levels are just about making things harder. But at least you get to see everything the game has to offer, by and large.

As a final point, Granny has health, but I didn’t have time to add health-pickups so she’ll only ever get more and more unwell, poor Granny.

Other Lessons

Besides those that have been mentioned above I learnt (or “learned” – crazy irregular verbs) a few good lessons during development. Mostly these were about peculiarities of Box2D and/or LibGDX as these were essentially new tech to me.

Always cpy() your Vector2s – It turns out that Vector2’s in LibGDX are mutable little devils. Presumably this is done as an optimisation. Nevertheless it caught me by surpise a number of times. Consequently if returning a Vector2 from a function, or accepting one as a parameter: Always make a copy! This is actually good general advice whenever you accept a mutable value that you intend to own. Last thing you want is for it be changed under your feet!

My worst experience with this was when I was returning Vector2’s from a Box2D body and forgetting to make a copy (in fact you might have thought LibGDX’s wrapper would do that; it isn’t clear whether mutating this object is actually safe and if it would correctly modify the body’s physical property). Consequently when the body was destroyed it left a now-dangling Vector2 held some place else that would crash the JVM once touched. Tracking that back to a missing cpy() was more guesswork than scientific debugging.

Defer your deletes – This one kind of depends on how your architect things. For me the various entities exposed details such as their position and velocity, but these were just being passed straight out from the underlying Box2D bodies. So, say a dino was killed by a bullet impact. I would remove the dino from the World, which would also destroy the Box2D body. It appears that Box2D immediately frees the resource (it doesn’t wait for the next tick, for example). The problem is what if you wanted to spawn some blood from the dino’s position? You can’t if you kill him first. Obviously you could spawn the blood and then kill him (and maybe, for blood, that makes sense) but it’s a little on the brittle side and a leaky abstraction – The dino-to-bullet collision handler is just telling the world that the dino is dead; if it has to know that the dino will also become invalidated then it undesirably knows something about the implementation that I would have preferred to keep hidden.

Another issue is when multiple collision handlers are invoked by Box2D. One of my more serious and bugs was an occasional crash that only began to appear after I introduced multiple dinos. It turned out that a bullet could collide with multiple dinos at once. This is obvious in hindsight – the bullet isn’t infinitely tiny like a raycast, it’s a circle with an area being simulated by Box2D. If both those dinos happened to die from that bullet impact then one of those collision handlers is dealing with an already-deleted Body and badness ensues.

This was all fixed by buffering all deletes up inside of my own Box2D World wrapper. Multiple deletes were de-duped by storing them in a HashSet container. At the next tick I would then run through and do all the deferred removals for that frame. Now those bodies would remain valid for the entire frame and I could go back to forgetting about memory management issues 😉

Finding free assets is hard – By far the hardest asset to acquire was the font. It’s called DINk. Many “free” fonts have uncertain licenses, I’m sure the owners intend them to be wholly free but unless they give clear licensing terms then I am uneasy going near them. Many other fonts are free for virtually any purpose but may not be redistributed. Lack of redistribution is a massive bummer because that is exactly what I need to do – package it as an asset and redistribute it as part of my game. Most of the font licenses I found were around the idea that a font is used in subset to create a document and that document is about the only derived work that can be created from that font. I did my best to acknowledge all the asset authors in the ReadMe, as well as being clear about what the licenses are.

Conclusion

Overall it was really fun. I hope they do another one as I’ll surely participate. I think I’ve learned a few lessons for this one though: It was too ambitious to truly finish and sucked up far too much time. I think a much simpler game could fair just as well. Using the competition as an excuse to play with new tech is quite fun though – Maybe next time I’ll play with shaders; perhaps some kind of game involving making things glow or somehow involving the lighting such having to stay hidden in the shadows. I have already expressed an interest in another competition, this one initiated by one of the judges and the goal is to make some flavour of a Pong clone – could be quite cool!

I shall post this post-mortem to the GameDev.net forums when all the judging is complete – I think that pointing out the flaws in my game whilst the judging is still underway would be unwise 😛

If you want to see what kind of twisted, scary code and sheer quantity of magic numbers that went into making this game, I have open-sourced it on GitHub: https://github.com/daveagill/GvZD

In closing I would also like to thank those who voted for my game in the Peoples’ Choice Award, which I am delighted to have won.

I look forward to seeing what the final verdict was from the judges!