bookmark_borderPostmortem of a Ludumdare 23 Game

Last weekend I decided to take part in Ludumdare 23 Jam. Here is a short postmortem.

The theme was “Tiny World”. After a little brainstorming and inspiration I decided to have a go at making an RTS.

After coming up with a basic list of things to do, I started to work on the engine. Since I wanted the minimum of fuss when it came to actually deploying the game, I decided to try out NME, a flash-like API written in haXe which describes itself as a “a free, open-source framework that enables development for iOS, Android, webOS, BlackBerry, Windows, Mac, Linux and Flash Player from a single codebase” – perfect!

While the “game” ended up being a complete unsubmittable disaster, I still found the experience to be quite insightful.

TinyConquer

What went right

After a few hours I managed to get a basic prototype working with a unit and walls. At this stage, the unit merely moved towards the mouse cursor and collided against the walls. Next came unit-unit collision, which turned out to be a bit more complicated since I decided to use arbitrarily sized bounding boxes.

Path finding ended up being the simplest thing to implement. For this I used AStar. While initially I stumbled across a rather insightful article with illustrations, I eventually turned to a more helpful article on wikipedia which filled in the gaps.

At the end of the second day, after asking myself “am I really having fun making this?”, I decided not to continue. In the end all I really got implemented was a simple map with units that moved around walls.

What went wrong

Collision detection

It’s easy to write code to determine if a collision has occured. It’s another thing to handle what happens after a collision has occured. While I managed to eventually ironed out most of the issues with the tile collision, later on I found there were still problems if the unit entered a tile incorrectly where it could get stuck.

Simulations are hard to debug, especially when you add in movement and collision. Knowing how annoying buggy collision detection is, I really wanted to get this solid and ended up spending far too much time resolving collision and movement issues.

TinyConquer

NME wasn’t that great

One of my biggest problems was with NME. Not only did I find drawing to be CPU intensive, I stumbled across a rather odd bug with rotations in the HTML5 target. As soon as an element was rotated, the transform for both the sprite and its children became incredibly screwed up. This did not occur in any of the other targets tested.

In addition later on while it worked fine in Chrome and Firefox, Safari was a different matter: I encountered tons of scripting errors and even made it crash!

Finally of note is that text drawing didn’t work properly in the neko target. While I ended up not needing to draw text, it still put a dampner on things.

Loss of motivation

To start off with, while I hyped myself up beforehand I found that when it came to it, I wasn’t really “in the zone”. This made progress much slower than expected. Half-way through, I started to REALLY loose motivation and ended up procrastinating a lot. Coupled with bumping into silly implementation issues, this really killed development. Realy, I underestimated the effort required to implement something like an RTS from scratch.

In the end, While my game made for a nice tech demo with prototype vector graphics, it was distinctly lacking in gameplay.

To Conclude

Using something you don’t know well in a development contest is a recipe for disaster. Having not used NME before, I wasn’t quite sure how certain things worked so I was constantly looking back and forward through the documentation.

In comparison had I used something like Unity, 99% of the underlying functionality would already have worked leaving me to work more on the gameplay and art elements which are far more important for a game.

When developing a game, getting gameplay in ASAP is a must. Without it, all you are really staring at is a tech demo, not a game.

For something like Ludumdare, simpler is better. While an RTS is conceptually simple, the underlying framework isn’t. Looking at some of the entries, a lot of the better ones are based on simpler gameplay concepts or backed by powerful game engines.

Finally, it’s worth remembering that most of the time, a good game isn’t made in a day. In fact, a good game can take years to create. So don’t treat Ludumdare as a way of making a new cool hit game. It probably isn’t going to happen.

For reference, I have put up the code to the “game” up on github.

bookmark_borderUsing OpenAL on iOS

Recently I have been tackling problems in OpenAL code for an iOS app. The trouble with OpenAL is that despite there being a spec, the underlying implementation for this audio API is mostly undefined. What can work for one system can fail miserably in another.

In the case of iOS, no sourcecode is provided so the underlying implementation is partly a mystery, though we can infer from the documentation it uses the AudioUnit API.

Here are a some best practices i’ve developed based on experimentation:

Do you really need to use OpenAL?

In some cases OpenAL may be overkill. For instance if you are just playing a one-off sound effect when pressing a button, it’s probably a better idea to use AVAudioPlayer.

If however you are making a fully immersive 3D AAA shooter, you’re probably a better off using OpenAL. If you are really crazy, for ultimate control you could even try writing your own audio mixer.

Never re-use the same source twice

The implementation of OpenAL on iOS 5.x acts rather oddly when it comes to streaming sources. Lets say you make a music manager and decide to allocate a source. You allocate some buffers then queue them for the source. You then re-use this source to play various music tracks.

However a problems arise as soon as the source is re-used. If you simply stop it and de-allocate buffers, when you queue up a new set of buffers for a new music track the OpenAL implementation seems to get confused and only plays the first buffer you allocate.

Attempting to recover the source at this point is impossible. You can stop it, rewind it, throw buffers away… nothing seems to get it to work properly. Based on this I can only assume you are not meant to use the same source more than once, at least for streaming sources.

Don’t allocate sources you don’t need

Each source you allocate and play in OpenAL will add a mixing unit to the mixer, which will be mixed to produce the final stream. In addition every source you allocate uses memory.

Instead of allocating a bunch of sources, only allocate sources as you need them. From what i’ve been able to determine, sources aren’t that expensive to allocate. It might make sense to limit your allocations however, as there seems to be no fixed limit to the amount of sources you can allocate on iOS.

At one point after receiving a general speedup by changing my source allocation, I theorized that perhaps every source you allocate in OpenAL is mixed regardless of whether or not its playing. However basic experimentation seems to indicate there is no major performance issue with merely allocating lots of sources.

Cache your buffers to disk

If for example you choose to encode your sound effects in something like OGG format to save space, you might notice it takes a noticeable amount of time to decode the audio each time you buffer it, even when using Tremor. This is no fun to an end-user.

Using an easier to decode codec is one solution, but if you have long sound effects it’s still going to take time to decode all the samples.

So it makes sense to keep buffers around for sound effects. However if you have too many buffers you will likely bump into low memory alerts, forcing you to purge non-playing buffers. When you need to play your sound effects again, you need to decode them all over again.

One way you can solve this is by storing your decoded buffers temporarily to disk in the temporary folder (NSTemporaryDirectory). That way when you get a memory alert you can dump your buffers, then whenever you need them again you can quickly re-load them straight from disk.

To conclude

Despite implementation-specific bugs, OpenAL is actually quite a nice and simple library for playing both 2d and 3d audio. There are no licensing fees, the specification is open. It’s available for practically every relevant modern development platform, what more could you want?

Have fun using OpenAL!