When we implemented the first prototype for Dark Odds, we knew that the it was going to have a reasonably simple gameplay. It was going to have a an illustration, a short text describing the scene the player is currently at, and have two options to choose from. It was going to have much shorter explanations as you would have in a ‘Create Your Own Adventure’ book as it has to stay readable on a phone screen.
We had the story written in spreadsheets, and in a very simple browser-based proto-prototype. We didn’t really know how long the game would take to play from the beginning until the player reaches one of the possible winning scenarios. It also meant we didn’t really know whether additional scenes would be needed.
For the first iteration, we chose a very simple abstraction for the story, and only took around 20 of the scenes. We had an array with the texts, and textures required, and two extra fields to point to the index of the array that supposed to be the next card after the player made a choice of the two options. This allowed us to quickly implement, and experiment with some basic features of the UI, such as swiping gestures, and evaluate whether the gaming engines we tried are capable of what we thought we would need.
It’s easy to see that this approach was going to get out of hands quickly, and it would be difficult to get anything other than the basic two choices logic working with it.
Graph model, with Unreal Blueprints
We chose Unreal Engine to work with due to its visual coding tools. In Unreal it’s easy to implement most of what our game needed without a single line of code, and that speeds things up. At the same time it occurred to me that we could use this system to represent the connections between the different scenes, also providing visual feedback.
We thought it would be simple enough, so it would allow anyone with no object-oriented programming background to edit the story, without the need of any external tools.
In this model the scenes are instances of a Scene class, each referring to other instances as their left and right choices. (The player can choose by swiping left or right). At the beginning of the game we construct the graph, and then traversing it according to the player’s choices.
As we implemented the same 20 scenes, everything worked out nicely, but we had to take care of the cycles in the graph, since the story has loops, where the player can go around in circles and it’s all up to them whether they realise it. Due to the relatively low number of loops we figured we could live with the necessary scheduling by the execution pins. With an acyclic graph, it could be completely free from execution pins.
It definitely a gain for us, that you can edit it with barely any coding experience. It helped us have much more efficient communication, and freed up some time to develop additional the features.
It also was proved to be an efficient and precise tools, since we barely had any ‘teleportation’ bugs in the game. After adding the complete originally planned story, there were only 2-3 cases where not the planned outcome was seen after a choices during the first playtests.
Downsides of the Blueprint Graph model
As it is, all the scene objects have to be constructed at the start of the game. This means that a naive approach to simply have the textures set for each scene, would cause the game run out of memory and crash on phones when all the textures are getting loaded during the initiation of the graph. It required soft referencing of textures of the scene objects, and a small bit of code to only load the textures when they are actually queried from the scene object.
After implementing the originally planned story, we realised that the game is quite short, even though it already had around 500 scenes. At this point the benefit of the visual feedback seemed to be lost as there were cases where the player could take a shortcut in the storyline and skip 20 scenes. The blueprint of the story graph won’t fit to a reasonably sized screen with keeping the nodes readable anymore.
Since Dark Odds is not a single developer project – there is the two of us who regularly make changes to the actual Unreal assets – version control at this point is difficult to manage, with a single asset storing every relation between the scenes. Unreal uses binary files to describe Blueprints, and if on two different Git branches have a Blueprint modified, it’s definitely going to cause a conflict. Even if the differences could be managed, at this scale of complexity, merging is prone to errors.
Initiation at the start of the game, also would make it very difficult to implement conditional choice outcomes. (This would mean that based on a certain condition, the same choice would give different results. Like if the player picked up an item previously, they could end up on a different scene with different options)
For a simple story with no conditional choice outcomes, and cycles, probably it’s still a feasible solution.