30 September 2013

Continuing from the previous post, I’m looking at some of the lessons learned from my entry in the Js13kGames coding competition.

The ugly

Concurrency

Concurrency is hard, and brings with it the potential for whole classes of bugs you’ll never encounter in single-process systems, including devious Heisenbugs that might occur one time in a thousand. Getting a server and two (or more) clients to co-ordinate with each other and agree on consistent state is an order of magnitude more difficult than writing code that runs on a single machine.

I didn’t have too much of a problem with the typical multi-threading bugbear of shared mutable state, since my threads were necessarily isolated by running on different machines with minimal communication between them. However, getting them to all agree on the outcome of a pseudo-random quasi-chaotic user-interactive process (i.e. my game) was very hard indeed. Anything that made the system even slightly non-deterministic (e.g. timing differences, floating point errors, order of execution) could cause them to dramatically diverge. I spent a long time debugging these sorts of issues and fixing subtle bugs.

The final blow to this class of bugs was enforcing better separation of concerns in the clients, by having them update their state in lock-step with the server at a fixed time interval, and worrying about smoothing out the animations in the view (which calculated its own less precise but more frequently updated model of the current state). Everything suddenly became much easier after making this change, which was actually quite simple to do (although I’d missed the SoC opportunity before, I had at least kept my code reasonably modular).

The other big challenge was to make the server authoritative while allowing the clients to carry on the simulation for the mainline case where the server never tells them anything they disagree with (as discussed in Gabriel Gambetta’s Fast-paced Multiplayer series). Compensating for things working out differently (e.g. when two players perform conflicting actions and the server picks a winner) can be very complex and have a lot of knock-on effects. Only mini integration tests covering most of the shared model code made this tractable. I still have a few hypothetical scenarios to address on my to-do list though, which I believe will currently go wrong some tiny proportion of the time.

That fox sprite

I was rather pleased with the little purple bunnies that populated my game world, but really struggled to get the artwork for the foxes right. I had an idea that I wanted the fox sprite to be more angular than the rounded bunny sprite, so that it looked aggressive. However, it also needed to look larger than the rabbit sprite, which was already rather fat and round. Most of my attempts ended up looking a bit like a cat, or an enormous mouse, or simply no kind of animal at all.

Keeping in mind my issues with prioritisation (see above), I ended up settling for something that would do, and getting on with the rest of the game. However, the first thing I did after the competition was to redraw the fox sprite from scratch. You can compare the two versions below. I’m still not quite 100% pleased with the current version, but I’m much happier with how it fits in with the rest of the game’s artwork, and think it looks suitably fox-like.

Before
After

What’s next

I’ve carried on working on the game since the competition ended, and have started updating the live deployed version now that judging is over. Apart from updating the fox sprite, I’ve also…

  • Fixed a few interface bugs raised by my colleagues at Softwire who were kind enough to playtest the game
  • Introduced more core gameplay features
  • Improved handling of network play edge-cases
  • Written a passable AI opponent for single play
  • Aided accessibility (in particular, colour-blind users)

Still to come

There are a fair few things on my TODO list, including:

  • Yet more concurrency edge cases (see above)
  • Four-player multiplayer
  • A lobby system and nicknames to allow people to co-ordinate games between friends
  • Improvements to the AI
  • Support for mobile/tablet platforms
  • More paranoid cheat prevention
  • Additional core gameplay features
  • Audio (SFX and music)

Once I’ve worked through some of these, I also hope to market the game to some extent (possibly as part of the Ludum Dare October Challenge). I’ve really enjoyed taking part in this year’s Js13kGames and previous Ludum Dares, and - as brilliantly illustrated in this recent article by Steve Yap - I suspect I’ve just scratched the surface of what you can learn from this kind of project.