Unlike other elements of my introduction, the implementation doesn’t care about hooking players into the game, or layering future themes, or even being pretty. It just needs to work. When I say “implementation”, I’m referring to what drives how players interact with the game — what runs the game in the background? I could use the word “code” instead of “implementation”, but that would be over-simplifying. Writing the story in Twine has as much to do with how everything comes together as my C# code does.
As much as this post is part of my Making an Entrance series, its content isn’t specific to the introduction. Instead what I’m about to detail is entirely how my game works, from start to finish. Be warned, this gets a bit technical. But feel free to ask any lingering questions you may have after reading this!
A Tale in Twine
Twine is a computer program used to write branching narratives. It uses chunks of text (“Passages”) linked together by player choices. For example, if I have one Passage that asks the player “Do you want to kill him?”, I can give the player a “Yes” choice and a “No” choice. The “Yes” choice leads to a new Passage, and the “No” choice leads to another, completely different, new Passage. It’s a visual, graph-based system, so it might be easier to understand if you look at the first image below.
I’ve written the whole of my game’s story in Twine. That means you can play the game, in its entirety, with Twine’s “Test Play” feature. (For you engineers out there, this amounts to Twine being the Model in Model-View-Controller lingo.) I then export that Twine story to an easy-to-read format (called “Twee”) and use a plugin called UnityTwine to finally get it into Unity — which is where my C# code controls all the images, animations, and music that add to the overall experience.
Since Twine is just a graph of Passage nodes, my C# code simply looks at which Passage of the graph the player should be seeing, then displays its associated text. I use Twine’s Tags feature to determine what images (characters, locations, etc) my game should be showing. For example, if we’re in a Passage that is marked with the “Butler” Tag, my code will show the butler image. If we’re in a Passage that’s marked with the “Malone’s Apartment” Tag, my code will show Malone’s apartment. Collecting evidence, opening the notebook, and contradicting suspects are a bit more complicated — but essentially they use the same idea: everything is controlled in Twine, and my code in Unity just decides what to display.
This comes with implicit rewards. As with any properly-divided MVC system, it means my story is entirely independent of my visuals and my interface. I can change the art style, the type of interaction (touch screen?), or even change from Unity to Unreal to any other engine, and the story still works — I wouldn’t have to alter a thing in Twine.
It also means I can test the story while writing it in Twine. I can iterate much more quickly since I don’t need to export everything into Unity and run the game. Does this passage sound awkward when coming from this other passage? I don’t know, let’s try it! This makes any Save/Load system easier to write, as I can just save what passages my player has seen, and run through them one-by-one when they load a game.
It also means I can write tests that look only at the Twine output. I don’t have to rely on Unity, just run though the Twine story and let me know if there are errors. Wonderful!
Of course there are downsides. And in this case, unfortunately many. They’re all related to the fact that Twine was created for web-based choose-your-own-adventure narratives.
Thus, Twine knows nothing about important game state — i.e.: where is the player? which character is talking? etc. Essentially, I’ve had to create my own scripting language inside Twine — (ab)using its Tags, Links, and Display systems — for my code to understand what screen to show or what music should be playing. But this is bad, because Twine then can’t check for errors — if I misspell a Tag, or try to Display a Passage that doesn’t exist, Twine has no idea that I’m doing anything wrong. I have to write a lot of unit tests to cover these cases or else find many bugs inside the story.
Twine also doesn’t understand complex concepts like “always show the notebook button when the player is engaged in conversation”. In order to get the benefits of playing the entire game in Twine, I need to manually check that there is a “notebook” link inside every Passage where the player is conversing. Of course, this is dangerous for the same reason mentioned above: if I miss one notebook link inside a conversation passage, Twine gives me no warning — the game is just quietly broken.
And while Twine does offer support for returning to passages multiple times (including conditional statements and times-visited counters), it’s really not meant for a game where a player searches for evidence in a room. Or, even worse, where a player tries to contradict a suspect with the evidence she’s collected in that room. This all leads to an insane amount of graph spaghetti, as demonstrated above. Again, annoying, and easy to make mistakes with.
With these downsides (and more) would I use Twine again for this type of story? First I’d take a closer look at renpy and see if I could port that into Unity. And inkle has made ink, their internal writing tool, completely open source — so I’d give that a go too. But, in the end, my game is fairly specific. With the amount of evidence, the number of contradictions, the variety of locations and characters, it quickly gets complicated for any system to handle. Twine isn’t ideal, but I’m sure I’d find challenges with every piece of software. While Twine can be dangerous, it’s also flexible enough for me to implement this entire game, so I’m still happy with it!
This marks the end of my Making an Entrance series. I’ve compiled all the posts onto this page. It’s been fun for me to write the series and I’m sure it will be useful in a post-mortem capacity. I hope you’ve enjoyed it too! If you have any questions, about this post or any of the others, please don’t hesitate to ask.
The game is coming together quickly now. I’m excited to share much more with you in the coming weeks!