🔍

If you like my posts, you can support the creation of new ones by letting your browser mine cryptocurrency while you read. More info in this post.

Please whitelist this site on Adblock!
Post-Mortem: Ludum Dare 33

As promised in my previous post, here’s a bunch of stuff about the game I made for Ludum Dare 33. Minor, relatively vague spoilers ahead – play the game first if you’re going to at all, it’s pretty short.

Ludum Dare, for the uninitiated, is a weekend-long game development event. The idea is to make a game from scratch – design, code, graphics, audio, etc – in a weekend. To facilitate this, each event has a theme that is only decided on right before the event starts.

Ludum Dare is technically split into two separate but related events: the “Compo” is a 48 hour event which requires you to work on your game solo and has very strict rules about what resources you can use, and the “Jam” is a 72 hour event which you can enter as a team under far more relaxed constraints. The Compo requires submission of source code, and the Jam does not. I didn’t actively think about which one I was going to participate in before starting – I just happened to have a decent enough game by the Compo deadline and reasoned that having an extra day to work would be of no use when that day was a Monday.

I have one rule about entering these sorts of time-limited events: use a tool you know. Preferably one you can spin up a game in without consulting Google (for me, that’s GameMaker Studio). I broke that rule for this jam, and in so doing, proved it.

After the theme “You are the Monster” was announced, I spent a good few hours just thinking up an idea for the kind of game that would fit it. There are a set of very obvious ideas that come to mind: godzilla simulator, some weird reversal of a retro game like Space Invaders or Pacman where you play the invaders/ghosts or something in the vein of Execution (one game that needs no imitators). There’s also a Spec Ops: The Line angle to the idea, but in a weekend jam you barely have enough time to make a functioning game, let alone make one that functions well and uses that to subvert itself a few levels in.

So I decided pretty early on that I would be writing a text game, as a way of keeping the scope of the project manageable and also because I find rubbing glass shards in my eyes more enjoyable than drawing sprites. I wasn’t able to spend every waking minute on my game over the weekend, and it probably would have been a more complete game if I had, but everyone’s got things they need to do.

I decided to write it in the open source hypertext gamedev tool Twine because it’s something I’ve been playing around with for a while and really been itching to write a game in. I figured it would be like a less restrictive Inklewriter but not quite the parser deep end of Inform.1 Twine is touted as extremely accessible but also sports a scripting language and extensiblity via CSS and JavaScript, so in that sense it’s a bit like Tumblr.2

With my medium and tool decided on, I came up with this idea about the game being from the perspective of a haughty volcano god who demands sacrifices from the humans living next to his volcano and then went and wrote that. I had a few pangs of guilt about breaking my “no unfamiliar tools in gamejams” rule, but I figured that Twine wasn’t that unfamiliar and seemed really quite simple besides. What could possibly go wrong? It wasn’t as if I was using LD33 to start learning how to develop games from first principles in C++.

Well, things went well enough that I ended up with a game at the end of the weekend, but there were quite a few bumps along the road, owing both to Twine 2’s being fairly new and in parts incomplete and to my inexperience with the tool (though mostly the latter).

Ideas about the game’s structure evolved and changed during the making of it. I started with a vague concept, wrote some introductory passages to pin down the tone and voice, and then fiddled with passage connections and added variables as seemed appropriate. I’ve been a programmer for about half my life, so it wasn’t long until many variables and datamaps (hashmaps/dictionaries/key-value stores/whatever) seemed appropriate.

Twine’s main interface is a game map of square nodes (passages) and lines connecting them (hyperlinks), styled like a blueprint. So most Twine games look like complicated flowcharts. As an example, here’s the map from this randomly selected retweet by @twinethreads:

Contrast that with the map of I Hunger, which looked like this:

While the one above is a nice, connected web, this is just a bunch of nodes in a claustrophobic cluster (I didn’t want anything going off-screen). The game starts with a conventional web on the far left side, but that degenerates as you go further right, until you’ve got a lot of nodes that either connect to the same one or have no connections at all.

A traditional Twine game is like a Choose Your Own Adventure book. “To feed the troll, turn to page 37. To run away, turn to page 54,” that sort of thing. There may be a few variables here and there which change some text depending on whatever for more versimillitude, but the basic structure is still a web of nodes with definite, constant connections between them.

I Hunger, on the other hand, uses dynamic variables to decide which nodes the user can visit from which other nodes and when, and what the user sees is almost always an amalgamation of a bunch of different passages rather than one at a time.3 It’s not quite in line with Twine’s intended use-case, and that’s where my troubles began.

Twine’s Harlowe scripting language4 held up to the challenge for the most part, but was missing a number of features that would have certain parts a lot less of a headache to implement. The journey of programming, I’ve personally found, seems to be a progression from using lots of if and switch statements to using as few as possible. As you learn, you speed up your work by mapping data, writing generic functions and performing pattern recognition instead of cumbersomely catering for every eventuality with a different explicit instruction. Some of Harlowe’s limitations sent me back to those dark days of long if-elseif-else chains, with all the debugging and careful searching for typos that that entails.

But I don’t want to diss the language too much. Leon Arnott has done a fantastic job overhauling and extending on the classic syntax from Twine 1.x for Harlowe’s scripting, and there are some absolutely fantastic and easy-to-use text substitution methods. But the language remains very much a work in progress: recent feature acquisitions include being able to use a variable instead of a literal as an array index (I have a hard time imagining how arrays were good for anything before). Another issue is that the (acknowledged to be rough) documentation is somewhat incomplete, and you need go through the latest changelogs to make sure you don’t miss out on any useful recent features. You can’t not love a language which includes the <present tag| as a syntax element, but its immaturity leads to a lot of niggling little problems.

For example: When printing an array, Twine would print a list of the array’s contents separated by a comma rather than a comma and a space, so you’d end up with something like You are carrying: key,lantern (I wasn’t hoping for robust a Inform-style printed list with appropriate indefinite articles and “and”-placement, but spaces would have been nice). I had to ask a question on the forums before I discovered that oh, hey, you can just use JavaScript array functions on your Twine arrays and it works by some sorcery. And I discovered this only after the game was already submitted for the compo.

This lead to an investigation of JavaScript in Harlowe-flavoured Twine 2, which lead to… well, not a lot actually. I thought I’d uncovered something that meant I could have implemented everything in I Hunger more easily had I just used JavaScript for most of it, but it turns out you can’t access Twine variables from JavaScript or call functions defined in “Edit Story JavaScript” from your passages, even though you can put <script> tags in them. And those aren’t really useful obviously for core story functions because JavaScript isn’t designed to have statements that say “print this text right here”, which is most of what you do in Twine. You can probably achieve said effect with careful study of the Twine game DOM and <span> spamming, but it won’t be a small amount of code. So all it’s much of a muchness, at least in the Harlowe format.

During the actual timespan of the competition, I of course wasn’t investigating JavaScript integration and waxing lyrical about Harlowe’s scripting. I was getting frustrated with stuff I didn’t anticipate and struggling with a parser I had to figure out as I went. Which is why I have my one rule about game jams: use a familiar tool.

I struggled through nonetheless, though I had to cut a number of features and a good deal of content that would have made the game a much richer experience. As it stands, I Hunger gives you only a few choices at each point, and only really responds to the bluntest, least interesting choices you can make. That’s not wonderful, and fairly contrary to what I was trying to go for.

Additionally, the “Observe Man” sections are far shorter than I wanted them to be. I wrote about sixteen variation passages with a couple of sub-variations in each depending on various values, but what I really wanted for those sections was whole mini-stories where you can make choices on a more granular level and have those choices very subtly impact what happens later.


Going forward with this game, as I am planning to, I have a few options about what to base it on:

Continue to work in Harlowe despite its shortcomings. Work around the unimplemented language features, hope that 2.0 comes really really soon, or write some very hacky JavaScript.5

Investigate the other two story formats which come with Twine 2. One of them appears to be aimed at power users who just want to use JavaScript as much as possible. Promising.

Try a different engine entirely. For example the very swanky Undum or something custom-built – preferably in JavaScript, because the result is just more accessible that way. From what I can tell ChoiceScript’s system would actually be very conducive to the kind of things I want to do with I Hunger. It’s less traditional hypertext and more stats-based – rather than having your choices always branch you away to another node on the web, your choices affect stats, and those stats determine various textual variations in the coming story, which is mostly what I Hunger does. But ChoiceScript doesn’t have hyperlinks (I’m just not that jazzed about radio buttons), and it’s not nearly as pretty as Harlowe. Tough choices.

At the moment I’m leaning towards the middle option because it seems like it’ll be the least work in the long run, but it’s dependent on a number of decisions I still have to make about design features and changes to the structure of the current version of the game.

In any case, look out for the next version of I Hunger. I promise it’ll suck less. And remember: always use a familiar tool when entering a game jam, or pay the price.


  1. Something else I’d like to write a game in at some point, but probably not for a weekend jam.
  2. To quote myself: “Tumblr, actually, is very nice from a blogging platform point of view. It’s really the perfect blend of ease-of-use and customisability, given that any non-technical person can have a functioning tumblog in four clicks and any technical person can have the same and then go and edit their blog’s HTML in whatever way they see fit.”
  3. I seem almost physically incapable of making games like this without at least one abnormal structure. Even my Inklewriter game contained a loop or two, which the editor chided me for.
  4. Twine 2 takes the novel approach of implementing a different scripting syntax for each of its various so-called “story formats”, which all run on top of a single engine. The default one is called Harlowe, and I used it mainly because it was pretty and I didn’t know any better.
  5. I made the mistake of looking at the features of the unreleased 2.0 version of Harlowe just before implementing something which would have been a million times easier and better with array slicing, one of the big additions.