Robogenesis After Action Report: part 1

I'm finally getting around to typing up some of my thoughts and lessons learned following Ludum Dare 28 and the creation of Robogenesis! (Note from 9/2/2021: the old Ludum Dare site is no longer available, but I'm working on getting this playable again.) It seems like most folks in the Ludum Dare circle would label this article a "post mortem". I don't feel like Robogenesis is truly a dead project, though, so I hope you'll forgive me for bucking the trend and using "after action report" instead.

As I wrote this, I found I had a ton to say about how I came up with the theme of the game and how I felt about the outcome. Then I thought this might not be interesting to all audiences, so I broke that off into Part 2. This article will focus on practical lessons and methodology, challenges and successes.

About me

As a bit of preamble, I should explain this has been my first Ludum Dare and, really, my first completed game. I did some reading on what to expect and how to prepare but this was still treading into a lot of unfamiliar territory for me. I feel like I learned a great deal, and hopefully some of this will be helpful to you as well.

Art

Hands down my biggest challenge was creating art assets. Most of my work was done in Inkscape. I like dealing with mutable shapes (vector graphics) more than pushing pixels around, but I have much less experience in Inkscape than in Photoshop. So that slowed me down a bit. I stuck with simple color palettes (I'm a bit color blind) and went with a cartoony, thick-outline art style in the hopes of keeping things simple. I would have liked to achieve a grungier, apocalyptic art style, but I think that was just beyond my abilities.

In my case, the amount of time spent creating art translated directly into cut features. It simply took too many hours to create a single part graphic, for example, to have more than a handful. My original concept called for a great variety of parts, but I had to go with the minimum that would still make a playable game. Becoming more fluid with Inkscape would be a great help here, but I think my future Ludum Dare entries will see little improvement in the quality of art. Just trying to be realistic here: I'm a programmer, not an artist.

Sound

I was quite pleased with how the sound effects turned out for Robogenesis. I simply used Bfxr and mashed on the "Randomize" button until something useful came up. I would like to pretend there was more skill involved, but that's really what it came down to. Once I had something close to what I envisioned, I would spend a bit of time tweaking the waveform properties (I do have a bit of college background in digital signals processing, which came in handy) but it was largely guesswork. This is where a quality tool makes me look way more skillful than I actually am, so major kudos to Bfxr!

Thankfully LibGDX makes working with sound effects a breeze, so finding sounds I liked was the only challenge.

Code

Code is where I am most comfortable, by far, and I can't say enough good things about LibGDX. There are always little nitpicks naturally, but I was able to lean heavily on Scene2D to save me from the drudgery of doing things myself. For a hobbyist-game-developer, professional-software-engineer like myself, LibGDX simply made all this possible.

I went the somewhat unusual route of using Scala as my main programming language. Programming in Scala is another hobby of mine and, for the most part, it worked very well with LibGDX. Just to show off the neat tricks that are possible with Scala, here's one bit of sample code that – while arguably unnecessary – is really darn cool.

I got sick of having to manually call dispose on a Screen's disposable assets one-by-one, but LibGDX doesn't have a "Disposable" interface to mark the classes that need to be disposed. (Note from 5/20/2014: LibGDX has since added Disposable as an interface; or possibly it existed back then and I overlooked it. Hard to tell. In any case, pretend the Disposable interface didn't exist, when reading the following example!)

Not to worry, Scala can do that with Structural Types! So in a package object I defined this:

type Disposable = { def dispose() }

Then I wrote a trait around Screen (and Game) which kept track of a queue of disposables:

val disposables = Queue[Disposable]()

And an abstract implementation of Screen (and Game) which overrode the dispose() method as so:

override def dispose() = disposables foreach { _.dispose() }

This is the kind of elegant "make it work" code that Scala allows you to write.

It wasn't all sunshine and rainbows, though. For starters, including the Scala jars in the packaged game adds about 10 MB of the total 17.5 MB jar. (I might have been able to slim that down a little by ditching scala-actors.jar, etc., but I didn't try.)

Furthermore, including Scala apparently made it incompatible with the GWT-based HTML5 version that LibGDX tries to give you for free. Thus I was unable to release a web-based version and had to stick with the Java package only. For a couple of evenings I wrestled with this, and it seems like there's a GWT module in a sort of beta stage that would have made my Scala code work, but frankly I don't have the GWT background to make sense of any of it and I eventually gave up. If anyone reading this has walked this path already, I'd be delighted to hear from you!

Finally, I ran into some challenges with Scene2D's Actions and setting up complicated scenes. (For example, when the game finishes, the conveyor belt grinds to a halt, the lights fade, and the dialog with the BOSS radio slides onto screen.) I couldn't tell if my issues were due to me missing something about the way things should be done, or if it was an actual issue with LibGDX. I'll write a post soon that explains my use-case and my hack solution, though, and hopefully someone can enlighten me! This was the only time the code really slowed me down, but seeing things animating around the screen nicely was worth the effort.

Final thoughts

In Part 2, I write in length about how Ludum Dare forces you to finish a project. This has value in and of itself, especially if you're a perfectionist at heart like me. Ludum Dare's voting process also exposed me to the wonderfully creative minds of my fellow entrants. It was a great inspiration to see what other people managed to accomplish. It was delightful to see how other people's strengths and weaknesses lie in different areas, resulting in a wide variety of submissions. I was always impressed at how people interpreted the theme. Ultimately participating in Ludum Dare's process was a reward in and of itself. I can't wait until the next one and I hope to see you all there with me!