Be forewarned, this post contains a significantly unstructured stream of consciousness. This post does not contain any technical details as to how the game was implemented, rather it is a story of how I came to use the technology I did and where the concept of the game came from. Turn back now before it is too late!
The autumn lisp game jam is now over. There were several phenomenal submissions to this year’s jam, including my own apparently (Always Kill Your Heroes), which took home the trophy. While this was the first game I have submitted to a jam, it is not the first game I have made, though, it was by far the most polished.1 I had written a game for the spring game jam. A collaborative effort, me coding and my friend writing. And, while it did have base functionality, it was too buggy at the time of the Jam closing to fully integrate the written material.2 Bummer.
Leading up to this Jam I reflected on my previous failure. While I had been prepared —writing the framework I needed for my game before hand— 3 it was not enough. There was not sufficient groundwork laid to get the game into even an alpha alpha state. Lesson learned. Don’t write you own engine, unless you:
- know what you’re doing, or
- have time to learn what you’re doing
If only I had taken this to heart. Two weeks before the Fall Jam was to begin I dove headlong into sbcl and tried working the opengl bindings into an engine.4 It only took me 3 days to figure out that I would spend more time writing a passable engine than writing a game. Not something I had time for in the few free nights I had left before the jam. It was around this time that fennel jumped out in front of my speeding train of thought, and this is where our story begins.
I had read an article recently on Hacker News about this little known language that was used by the winner of the 2018 spring lisp game jam, Phil Hagelberg. Fennel is a lightweight wrapper around lua. By lightweight I mean it is unintentionally similar enough to its lua output that you can make efficient use the back-trace errors in the lua code for fixing your fennel source (most of the time). In a rare lucid moment I also decided I’d use a well designed engine, rather than rolling with my own series of hacks. While there were several game engines that use lua as a scripting language, I choose to conserve all creativity for actually writing the game, and borrowed Phil’s idea to use love2d. All art is derivative right?
Now, at this point (roughly a week before the Jam was to commence) I had never written a line of lua in my life,5 nor used love2d, or any other engine for that matter. Rather than, you know, try out the engine and find some libraries to use, I decide to try to implement a general astar library using fennel. Looking back, it almost seams like all of my actions were taken to directly sabotage myself.
But lo, the eve of the game jam was upon us! Based on writing that one less than stellar library, I felt confident in my mastery of this concise language.6 I had bookmarked the love2d reference manual and was ready to jump into things. The theme was dropped at 12:01. It was SLIME.
Lets have a frank discussion about the theme. To be honest, SLIME was a bit of a curve ball. I mean SLIME , aka Superior Lisp Interaction Mode for Emacs, it’s funny. But once the laughter is gone, what are you left with?
1 : soft moist earth or clay especially : viscous mud
2 : a viscous, glutinous, or gelatinous substance: such as a : a mucous or mucoid secretion of various animals (such as slugs and catfishes) b : a product of wet crushing consisting of ore ground so fine as to pass a 200-mesh screen
3 US, informal : a morally repulsive or odious person
More than I had first thought!
Several ideas raced through my head. My initial ideas were almost all based on the final definition; a morally repulsive or odious person. Most of these ideas were pretty awful. Awful in the sense that the game would not get a PG rating, and may force you to be, as the dictionary defines it, evil. Things like, having a fiduciary responsibility to a multinational and needing to buy and sell less than moral things on a simulated stock market to maximize your company’s profits. Complete with a little moral meter that would sit in the corner of the screen and have no purpose or impact on the game other than to remind you how awful you are for the actions you are taking. Too dark. I thought I might double down on this idea of odiousness, while at the same time making it a little more PG. Idea two. You would be a proto slime, managing the lives of other slimes. You would adjust their needs meter to change their behaviours and accomplish tasks. The twist, which added the double layer of slime, in order to win the game you must work your slimes to death! This was still a little too dark for my taste. Plus, while my astar search library worked, it was not general enough to be used in a GOAP planner.
Final idea. This time trying to avoid hard amoral game mechanisms. You still play as slimes, but rather than control them indirectly, you control them directly through an RTS style interface —easier to implement than GOAP and complex pathfinding. Also, rather than being cruel to your in-group, vis-a-vis having your slimes work to their expiry, have them preform some other odious task to some out-group. This kind of behaviour, for whatever reason, seams to come across as less reprehensible. The odious task could be something like, slaying traditional protagonists, or Always Killing Your Heroes. All that was missing was an inciting incident. Now, why would such innocent members of your in-group be driven to commit such foul deeds?7
As I warned you at the start of the post, I will not get into details of how the game design went here, these will come in later blog posts. Suffice to say, the first weekend was spent drawing adorable slimes and the other was spent in a sort of fever dream implementing the half baked features I had come up with during the week. 10 days seams like lots of time, but when you have no idea what you’re doing and you’re spending most of your time working or roofing, somehow it does not feel like enough.
Upon finalizing the finally titled Always Kill Your Heroes, I realized that something was missing. Once you enter the game you don’t get any more story or context. I couldn’t empathize with the protagonists or the heroes! I did not care about them at all! I played the 10 min duration and thought, damn this is flat. After stalling while going through all the phases of grief, I came up with a stop gap solution. In the dying hours of the jam I scrambled to add little quips to both the heroes and the slimes. The slimes would randomly say something every 3-5 seconds. They had two word lists, one for idle and one for combat. The heroes would say something every time they entered combat. These quips, more than any other feature, completed the game, and it took 30 minutes to implement.8 I’m not even sure what the takeaway should be from that fact. I’d say you need to play test your game earlier, but even a prototype takes time to develop to a state where game play similar to the final product can be realized.
There were lots of good submissions for the Jam this year, hence my surprise. My favourite submission was Slimers Dungeon by akaml, which rightfully won the look and feel criteria. When I first played through Slimers Dungeon I only realized I was holding my breath when I hit the victory screen.9 I also enjoyed Slime the World, which came in a very close second. Slime the World was a very complete game. I feel @Jakob had a well defined scope for a game that could be written in a few days, and executed on it excellently. With the wonderfully selected chiptune background music even the most arduous levels were enjoyable. He has done a write up of his experience, which can be found on his site.
If I had one take away lesson from this experience what would it be? In lua, tables are passed by reference everything else by value. I did not realize this until I had too little time left to refactor.
Would I recommend using fennel and love2d to a first time game jam participant? Hands down. The love2d API is very well documented with a trove of example projects to build your understanding from. Fennel has minimal to no performance cost on top of lua, but fixes some issues with accidentally creating global variables and provides the “everything is an expression” experience.
I’ll put out a slightly more technical post sometime next week detailing my workflow. I want to refactor some of my code before I present it as an example.
If you want to get in touch send me a toot on mastodon @firstname.lastname@example.org.
You can download the game at itch.io or from the links below.
- Barring Search and Destroy Colours of Destiny, which still has This is an Unstable Development Version under it’s title. [return]
- I may write a post mortem of this project, and outline my approach to building a text game engine in emacs in the future. [return]
- Writing tools / engines before the jam is explicitly permitted in the lisp game jam. [return]
- I had not used common lisp in 2 years. [return]
- This is a lie, I did edit one line of the VLC youtube playlist script, which is written in lua. [return]
- Fennel is very compact, and there are great reference materials for it. [return]
- This is an exercise left up to the reader. [return]
- This 30 mins includes coming up with the dozen or so quips for each condition. I think it could be improved by simply doubling the number of quips and having a process where there is selection without replacement. [return]
- Honestly I’m shocked this game did not do better. I guess that originality score killed it. [return]