Wednesday, March 6, 2019

Anatomy of a Game Jam

Recently, a former housemate and I competed in a game jam. In this blog, I'd like to go over our process for making it.

As a little background, we've known each other for the better part of six years, during which he has been working to become a writer/novelist, while I've been working to become a game programmer/designer.

Our game jam planning session took place at a bar in Tokyo, where we started discussing the theme: cycles. I have to give it to my writer friend, because he almost instantly hit upon the idea of reincarnation.

We began discussing what animals to use, as well as actions. For myself, I wanted to limit the amount of player movement or interaction with the environment. The time limit for the game was only 100 hours, and happened to overlap with my main working days, cutting out 28 hours, and I don't believe in sacrificing my sleep in order to work on something, so that takes about another 21 hours, which left 61 potential hours of work.

Anyone who knows of my love and obsession with Buckminster Fuller will know how happy I was when I realized we had ended up with four animals, each of which had three characteristic actions, each of which is shared with one other animal, allowing one to model it as a tetrahedron.


We began coming up with situations, and for balance reasons ended up with 14 situations which equally distributed the different actions.

The idea was that each time you played, you would start as a random animal with a random lifespan. You'd be presented with random situations many times in your life, and you would be presented with three choices. These choices would be unique to each situation, in the sense that each situation would have a unique combination of choices. Although there are actually 20 such possible combinations, we only used 14.

Each time you make a choice, this is saved and used to calculate the animal you will start as in the next life. Since each animal has three characteristic actions, the top three most frequent choices you made are used to pick the next animal. For example, if you chose rest, socialize, and mate most frequently, in the next life you will be a dog.

After each choice, you'll be presented with another randomly chosen situation, and will have to make another choice. This will repeat until you die, when you'll be reborn as another animal.

All that, if you can believe it, was worked out over drinks at a number of bars in the course of several hours. After that, my writer friend and I parted ways, he to do some writing and myself to do some programming.

I began with the ChoiceType class and Animal class. I knew I needed to store a few strings in each to begin with, and a list or array of ChoiceTypes in the Animal class. Eventually, I'd end up storing a few sprites in the Animal class, but the ChoiceType class has remained essentially unchanged.

Then, I started working on the Situation class. This is where a lot of the information is contained. Originally, this had a few strings and two matched lists of ChoiceTypes and strings. This was to hold a choice and the text for the consequence, but it was difficult to keep everything matched correctly, so I switched to using a dictionary. Now, because I was using Unity, I had a problem: Unity's default serialization does not cover dictionaries, so any information I entered would be lost if I closed the program. Fortunately, I found some nice code that allows you weasel around this issue with minimal fuss, so I was able to use a dictionary.

The Situation class holds a name, a description of the situation, a sprite, and a dictionary which uses ChoiceType as the key. For each choice, it stores a prompt, a sprite, and a consequence. The first and last are just strings describing what (will) happen(s).

The code for these classes is relatively minimal, but I also wrote some custom Inspector classes to allow me to enter the data more easily, and since I was using some custom classes, there would be no easy way to display some of the information. For example, the dictionary stores a custom class that has two strings for the prompt and consequence, plus a sprite showing the fallout of the choice. This is the "value" associated with each key in the dictionary. Although it is a serializable class, there is no  reason to expect Unity to be able to display such a class by default.

This took up about 5-6 hours spread between the first two days of the game jam. I also started relearning how to use Fungus, a huge library of scripts that is most commonly used by people who don't know how to code. It allows you to create a vast array of different and interesting situations and setups, provided you are willing to enter all your data into it, or barring that, to also use Lua, which I am not familiar with. Given the pressure of the time limit, and since I had already entered the data into the custom ScriptableObject classes I described above, I decided I would only make use of two prefabs provided with the library: the menu dialog, and the say dialog. By using these, I would be able to display the text for each situation and the consequence of a player's choice, and I'd be able to give the player well formatted choices to pick from.

The main game logic happens in class cleverly titled GameManager. This loads all the animals and situations from memory, and deals with picking a random animal at first, or one based on player choice if this is a replay. It also handles displaying the Menu Dialog and Say Dialogs, as well as player death, and showing the correct graphics.

The GameManager class was coded over the last day and a half of the game jam, but was not truly finished until after the deadline.

All told, I think there is in the neighbor of a thousand lines of code in the project. If you include all the Fungus stuff, it would balloon into 10,000s or 100,000s lines, but I didn't author any of that. My writer friend put in a solid 6,000 words of story and description, without which the project never would have seen the light of day.

We're thinking of possibly expanding it in the future, but I think we can both be proud of it as it stands.