This past weekend I just finished competing in the Lisp Game Jam 2018. While I'd made a game under game-jam-like constraints I had never officially participated in one before, so this one was a perfect place to start. I wrote my game in the Fennel programming language using the LÖVE game framework. The game is called EXO_encounter 667; you play an unmanned probe exploring the exoplanet Gliese 667 Cc that uncovers remains of an ancient outpost.
Update: I'm proud to say that EXO_encounter 667 won first place in the game jam!
Overall I'm thrilled with how it turned out; at the end of the jam I ended up with a game I'm very proud of. This game jam is a little unusual in that it ran over the span of ten days; most jams limit you to closer to 3 days and end up being much more of a crunch. Ten days was enough time to make something fairly polished (though of course still short) without pulling a bunch of all-nighters.
Using Fennel allowed me to take advantage of a bunch of existing tools without starting from square one. I had used the LÖVE framework before, but only from Lua. As I blogged about previously, Fennel is a lisp language which compiles to Lua output and stays very close to Lua semantics, which means it's very easy to use tools and libraries from the Lua world. I can't speak to how it would hold up in a larger codebase (the game ended up being only 667 lines of code), but I felt that for this project using Fennel with LÖVE and a couple helper libraries put me on nearly the perfect level of abstraction. I ran into one minor problem with Fennel where the line numbering of the output wasn't quite right, but I was able to fix it quickly in-flight.
One of the limitations of the jam is that all game coding and level design must be done during the ten days of the jam, but if you have pre-made assets you can use them as long as they're freely-licensed. I found like I hit the jackpot when I stumbled across Daniel Cook's Hard Vacuum tileset. Created in 1993 for a Dune2-inspired strategy game, it was released under a Creative Commons license because the game was never finished. I was really impressed with the impeccable pixel art and the wide variety of terrain and buildings available in the set. Often when you are looking for freely-licensed art it's not that hard to find what you need if you look across various sets, but combining several sets leads to some pretty jarring inconsistencies in visual style. Here I found one set which had basically everything I needed.1
I also found a couple pieces of music that I felt really fit the theme I was going for: ambient and thoughtful to put you in the mood of exploring on a distant planet that took hundreds of years to reach. My son helped me choose Galactic Temple for the main theme, and for the endgame I used the slightly more upbeat Bazaar Net by Max Stack, who also composed music I used for the trailer of another of my games.
I had sketched out a plan up-front which I mostly was able to stick to; the main thing I cut scope on was the level layout. The original plan had the map divided into three sections: one where you approach the base, one base where all the text is in Russian, and the other base where things are in English. Because the aliens abandoned the outpost in 1999, the signals they received from Earth were from 1976 when the space race was still in full swing, so they were preparing for first-contact with Russia as well as the US. This was supposed to be part of the mystery you uncovered, but in the end it was just too meandering, and the final product ended up a lot more focused with a single base containing six doors you had to figure out how to open.
I spent most of the jam on a business trip where I had the evenings alone in a hotel room, so I was able to get a lot done there. I wrote the entire story text from DNA Pizza, a 24-hour pizza shop owned by JWZ that features bizarre, surreal music videos.2 For something written in 2 hours I'm really happy with how the story turned out; it was inspired heavily by the the mythos of Marathon series as well as the Three Body Problem novel.
But when on Saturday I got home from my trip and still didn't have any puzzles ready, I started to get a little worried. Not only did I not have any puzzles, I also didn't really have any idea how I would make puzzles in the first place or what would be fun. I sat down with my kids in the Tiled map editor and just worked thru a progression of the mechanics I had implemented so far, starting with using the probe's laser to trigger sensors which open doors, and working up thru reflecting the laser off one of your rovers, to a multiple reflection chain puzzle, and that worked better than I expected.
The next day eight hours before the competition closed I had half a map worth of puzzles and was running out of ideas. The reflection mechanic I had implemented was solid, but it wasn't enough to carry the game by itself. In about an hour I added in beam splitters as well as sensors which would only open the door as long as the laser remained on them. My son came up with the idea for the last puzzle involving splitting the laser and then reflecting the laser back into the splitter to get three beams which I felt worked really well.
In the end, I was able to finish the map within the last hour before the deadline, but just barely.
The versatility and ease of use of Tiled impressed me greatly. Once I loaded up my tileset into it, I had a tool simple enough that I could put my kids in front of it and they could make genuinely helpful contributions to the map. Highly recommended! All the collision and layer data is part of the map, as well as all the non-player animations.
Each object in the Tiled map contains a set of properties I used for various purposes; for instance I set a "door" property on each laser sensor switch to indicate which door should open when it was triggered. Early on I found myself making a lot of mistakes where I'd forget to set a property, so I added a linter which would error out early if it detected that a certain type of object was missing a required property or if a sensor referred to a door that didn't exist. This saved me a lot of fruitless manual debugging, and I'd strongly suggest doing something like it if you use map object properties.
I tried to introduce each mechanic with a very simple puzzle before moving on to non-obvious tricks. (I really messed up the difficulty curve near the end; the second-to-last puzzle is a fair bit more difficult than the last one.) This can be really tricky to do depending on your mechanics; I had one player who didn't see the message that explained how to aim because he accidentally skipped ahead by opening a door too soon. After the jam I went back and fixed this by starting off with the laser aimed in the wrong direction, so it's impossible to open the door without first aiming.
Using LÖVE was an obvious win; I got so much functionality for free as well as compatibility across operating systems and access to third-party libraries like the Tiled renderer. I wasn't sure how it would work to use Fennel for this, but looking back on it I find it remarkable how seamless it felt. The language just got out of the way and let me focus on the task at hand; I barely noticed it. Update: surprisingly, you can run the Lua linter on the output of the Fennel compiler and still get helpful results!
In the last hour I got my wife to playtest the game, which yielded some interesting insights. (Why can the rovers move forward but not backward? I just didn't think of it.) I found that having my kids playtest continually as the game evolved meant that they didn't see certain flaws; things that were clear to them weren't obvious to first-time players. (Of course, as the author I expect to be blind to many flaws myself.) In particular, getting a precise aim of the laser was much too difficult because the turn speed was too fast. I added a "hold shift to turn slowly" feature early on, but it wasn't introduced in the tutorial and you had to read the help text to see it. In the future I'd make more of an effort to get playtesting feedback earlier on in the process.
Speaking of the tutorial, having a tutorial was very helpful in introducing the mechanics. The implementation of the tutorial had some interesting technical features, but I will save that for part 2 of this post. Thanks for reading, and please enjoy playing EXO_encounter 667.
Update: part 2 is published.