Skip to main content

Invaders: Evolution Post-mortem

Invaders: Evolution is the game I wrote for the 24th Ludum Dare competition. It's the 3rd time I've made a game for LD (as well as one for a MiniLD event) & although I think my games get a bit better each time, I still have so much to learn. This is a post-mortem not just for the game, but for my competition experience as well.

The game is basically Space Invaders, but with a twist: it tells the back-story of the aliens through cut-scenes as you play. It also has two possible endings, one of which is rather unconventional by video game standards. You can try it out, or find out more, here:

What went right

I made a game! There was a low point where I thought I'd have to quit the competition (see the "what went wrong" section), but in the end I came through and got a game finished - and while it's not going to win the competition, it's definitely something I feel proud of.

In particular, Invaders is the first game I've done which tries to tell a story & I think it was successful. Most of the people who've commented on it seem to have got the humour and enjoyed the twist that the story adds.

On the technical side, the code I added to show the dialogue during the cut-scenes actually turned out to be useful for way more than I originally thought. I ended up also using it for spawning aliens, checking victory/loss conditions & transitioning between cut-scenes and play. Just a small amount of code, but so handy! I'll definitely be keeping this around for future comps - in fact, it's general enough that I should be able to reuse it pretty much unchanged.

What went wrong

The first idea I came up with after hearing the theme was a game about the predator/prey relationship between wolves and bison, inspired by this clip from the BBC's Frozen Planet documentary. My head was filled with grand ideas about realistic 3D snow-filled environments, tense chases and even tenser standoffs, smooth lifelike animation... You get the idea. The game I somehow thought I was going to make over the next 48 hours by myself, would probably have been about 6 months work for a small team.

Unfortunately it took me all of the first day and most of the following night to accept this. By the time I finally did, I thought I might have to quit the competition. This was a real emotional low point. When I started to think positively again, and came up with the idea for Invaders: Evolution, I only had about 12 hours left to do it in so it turned into a real rush job.

That meant things had to be cut, just so I could get finished on time. Music was the first thing to go, followed closely by sound effects - any attempt at audio at all, in fact. Shame, because I think some cool retro-sounding space invader noises would have really helped with the atmosphere of the game.

The other thing missing was any real relationship to the theme. Apart from having the word "evolution" in the title. Maybe it's an evolution of the old Space Invaders formula? Pretty tenuous...


The main thing I learnt from this is that I need to spend more time thinking through a game idea to see whether it's actually doable in 48 hours. A bit of time thinking up front can save a whole lot more time later if it prevents you from going up a dead end.

Up 'til now I've avoided doing any kind of time management for my Ludum Dare weekends apart from a vague idea of using day 1 for code, day 2 for assets & polish. I always thought it would make it more like work, less like fun. But with hindsight, the fun actually comes from making something good - and time management helps you to do that. So for the next LD I think I'll try coming up with some estimates and a rough schedule before I start work on an idea. If the schedule won't fit into the 48 hours, well I'll just have to find another idea.

To me, Invaders was a qualified success. I think it could have been a lot better if I'd been able to spend all of the available time on it, instead of just a fraction at the end. I've already greatly improved my basecode as a result of this competition, so my mission for the next LD will be to use my time more effectively. In particular, to make sure I don't have to throw all my work away after the first day.

Thanks for reading!


Popular posts from this blog

How to outperform std::vector in 1 easy step

Everyone who's familiar with C++ knows that you should avoid resizing a std::vector inside a loop wherever possible. The reasoning's pretty obvious: the memory allocated for the vector doubles in size each time it fills up and that doubling is a costly operation. Have you ever wondered why it's so costly though?

It's tempting to assume that because implementations of the STL have been around for so long that they must be pretty efficient. It turns out that's a bad assumption because the problem, in this case, is the standard itself: specifically, the allocator interface.

The allocator interface provides two methods that obtain and release memory:

allocate allocates uninitialized storage
(public member function)deallocate deallocates storage
(public member function)

(taken from this page).

What's missing is away of growing an existing memory allocation in place. In C this is provided by the realloc function, but there's no equivalent in the std::allocator interfa…

OpenGL ES and occlusion queries

This is a follow-up to my earlier post "WebGL doesn't have query objects".

Since I wrote that post, the situation has changed a bit. It's still true to say that WebGL doesn't have query objects, but the underlying reason - that OpenGL ES doesn't - is no longer true.

For OpenGL ES 2.0, there's an extension which provides basic query functionality: EXT_occlusion_query_boolean (which seems to have been based on ARB_occlusion_query2 from regular OpenGL). For OpenGL ES 3.0, the functionality from that extension appears to have been adopted into the standard. The extension provides two query types, both of which set a boolean value to indicate whether any pixels passed the depth and stencil tests.

While this is progress, unfortunately it's still not sufficient to implement the pixel accurate collision detection method I described in an earlier post. For that purpose it's not enough to know whether any pixels passed the tests; you want to know whether al…

Octree node identifiers

Let's say we have an octree and we want to come up with a unique integer that can identify any node in the tree - including interior nodes, not just leaf nodes. Let's also say that the octree has a maximum depth no greater than 9 levels, i.e. the level containing the leaf nodes divides space into 512 parts along each axis.

The encoding The morton encoding of a node's i,j,k coordinates within the tree lets us identify a node uniquely if we already know it's depth. Without knowing the depth, there's no way to differentiate between cells at different depths in the tree. For example, the node at depth 1 with coords 0,0,0 has exactly the same morton encoding as the node at depth 2 with coords 0,0,0.

We can fix this by appending the depth of the node to the morton encoding. If we have an octree of depth 9 then we need up to 27 bits for the morton encoding and 4 bits for the depth, which still fits nicely into a 32-bit integer. We'll shift the morton code up so that i…