January 30, 2018
Developer Update #2: Under the Hood at 4th Wall Games
I hope everyone’s 2018 is off to a great start! Things are going well here at 4th Wall Games. In this month’s blog post we’re going to dive into some of the technical details about how we’re creating Harrowing Adventures.
This blog post, written by Mark, will be an “under the hood” look at how 4th Wall Games works. Therefore, it may get a bit technical, but that’s because it is being written with the intention of giving a head start to anyone else that may be interested in developing branching narrative games.
Also stay tuned for a future post by Jeremy that’s an “above the hood” look at the game, discussing the software and hardware tools and techniques he’s using to create the artwork and design the UX for Harrowing Adventures, which again we hope will be of interest to fellow game developers.
Architecture of 4th Wall Games
On one end of the pipeline we have the story’s authors and on the other end of the pipeline we have you, the reader.
I have written an authoring tool called Scribe that an author uses to generate content (i.e., to write the branching narrative). Scribe is written in Java 8, using Java FX 8, FXML, and SceneBuilder to develop the GUI. The IDE (integrated development environment) I’m using to develop Scribe is Eclipse for OS X.
While using Scribe, an author has the ability to write a living, breathing story using our own story scripting language, called manuscript. manuscript is designed to make it easy for the author to create dynamic text (phrases and sentences that change each time you read them depending on the situation). Such scripting languages already exist and I took cues from those in designing manuscript, especially Twine and ink (more on those below), but we felt it was important to create our own scripting language so that we could also add multiplayer functionality into it.
Writing a branching story quickly becomes a complex task. And in a 2- or 3-player scenario, the complexity is squared or cubed of that for a single player (for more about that complexity, see Jeremy’s post). Therefore, we knew it would be crucial to have Scribe do most of the content tracking and organization to help mitigate headaches the author might experience from juggling so many threads. So Scribe tracks loose ends (passages that have been referenced but haven’t been written), dead ends (passages that have no branches leading away from them), orphans (passages that have nothing pointing to them), variables in use and the passages that depend on them, and much more.
Scribe can also visualize the story in flowchart format (users of Twine will be familiar with what this looks like). To do that, I’ve used a package called Graphviz (something I first learned about long ago in the Project Aon forums), which accepts input in the form of a DOT file (a flowchart markup language). Scribe can output the story in DOT format for visualization by Graphviz. To give an example, here’s a screenshot of the flowchart for the second scene of the prologue, which was automatically generated by Scribe and Graphviz (this image was intentionally left low resolution — you can see the shape of the flowchart but not read the print — so that we aren’t giving away the plot and solution to our upcoming game!):
We will write a future blog post about manuscript, but here are some of its features. First and foremost, it has if-then-else branching structure that relies on values of user- or system-defined variables, which gives the text a more dynamic feel. Those variables can also be changed via manuscript or via the GUI of Scribe. Randomness, loops, and non-looping sequences have also been included in a way similar to how ink uses those. And, taking a cue from Twine, I have given manuscript the ability to designate a block of text as a “function” that can be called upon to insert text at the time and location it is called. This is a powerful way to make the content more dynamic, taking story-writing one step closer to functional programming.
Scribe uses ANTLR4 to parse manuscript code. ANTLR4 is an excellent parser generator tool that is community developed and supported. The primary appeal of ANTLR4 is its ability to take a grammar as its input for generating the parser, the ease in which walking the resulting parse tree can be customized, and the fact that it can generate parsers in either Java or C# (more on our C# demands in a minute). As an added bonus, there is an ANTLR4 plugin for Eclipse that allows you to write grammars and compile parsers directly within the IDE.
Once the story is written, it is saved in JSON format and then bundled with the app (or transferred to the app when a player purchases and downloads additional adventures). To read and write JSON, I chose the GSON library (Google’s JSON serializer) because of its ability to handle abstract classes, enumerated types, and other special cases (the object structure of the story is rather complex and takes full advantage of inheritance and abstraction).
Finally, we’re ready to talk about playing the game on your mobile device! To develop for mobile devices we chose to use Unity, because it is free to use (up to a point) and because it allows us to export our game to a variety of platforms. We wanted to support both iOS and Android, because we want you to be able to play this game with your friends, regardless of whether your friend has an iPhone, a Samsung, etc. Unity is a “write once, run everywhere” tool and also provides the ability to ship your software as a web app (using Web GL) or even to port to Playstation or Xbox. We are going to release the single-player prologue of the game as a free web app that anyone with a web browser can play.
Since we are using Unity then our app – which internally we’re calling the Story Engine – is all written in C# using Visual Studio Community for OS X as the IDE. Fortunately, Java and C# are similar enough that I was able to reproduce the same object-oriented structure within each language. To get C# within Unity to deserialize JSON, I chose to use JSON.NET by Newtonsoft, again (and like GSON) because of its ability to handle abstract classes, enumerated types, and other special cases, but also importantly because it works within Unity.
Once the JSON has been passed to the Story Engine, the game can be played by you, the end user. This architecture was designed using a “thin client” model (meaning most of the work is done by the backend, in this case Scribe and manuscript), so that the Story Engine is lightweight and can be used to play any appropriately-formatted JSON story that is passed along to it. This will make writing and shipping future chapters (or even future series using a different genre) a matter only of writing new branching narratives (and transferring them as JSON) and not a matter of writing new software.
An ANTLR4 library also exists for C#, and that was used to implement manuscript parsing in the Story Engine. Unfortunately, generating the C# parser files that are compatible with Unity was nontrivial because as of now Unity only supports up to C# version 4 (this is one drawback to selecting Unity for our development platform – it often lags in its support of the latest versions of other software – but we chose Unity knowing this and willing to work around it). If you want details on how to get ANTLR4 working inside Unity, please check out my post on the subject over at this ANTLR4 github issues page. (Special thanks to ANTLR4 developer Sam Harwell for patiently responding to all of my questions!)
Since this is a text-based game, then text presentation is obviously a very important component of the software. We wanted: (1) text that could be “glued” to a page and move when the page moved; (2) to allow the number of pages in a section of prose to fluctuate based on what font the user chooses and based on the aspect ratio of the display (e.g., whether the device is in landscape or portrait orientation); and, (3) text that could be interacted with (for instance, choice text that can be tapped/clicked by the reader). Unity’s built-in Text object is ill-equipped to do most of the items in that list. For our purposes we needed a more powerful Text object, and TextMesh Pro provided what we needed. Again, special thanks to the developer of TextMesh Pro, Stephan Bouchard, for supporting his users and patiently responding to all of my questions. (FYI, TMP is no longer available in the Asset store because it was acquired by Unity and now is bundled with Unity right out of the box, which is probably where it belongs!)
As a final note, all of the software tools and packages mentioned above can be used free of charge. This is generally an important quality for independent game developers like us!
This has been an inside look at how 4th Wall Games is building interactive stories. Please let us know if you have any questions or comments, and stay tuned for another blog post coming soon!