Tuesday, August 28, 2018

Darner's Digest, vol. 2: Why I made two new Yarn tools

Darner's Digest is a series of occasional posts about the game dialogue system Yarn.

Last time, I talked about some Yarn community news. As I've written before, I've become a sort of community booster for Yarn and Yarn Spinner because I want to see it become a standard in game narrative design -- I think it occupies a nice middle-ground between frameworks that try to do everything for you vs. coding a system yourself.

This time, I'm making the Yarn news myself. I've released two free open source Yarn / Unity tools for people to use, and I reckon they're darn good:
  • Merino, a Yarn script plugin for the Unity Editor, with built-in syntax highlighting and playtest preview. With Merino you can easily test the flow of your interactive stories without leaving the textbox or the Unity Editor.
  • Ropework, a Yarn-powered visual novel template for Unity. With Ropework you can control scene changes, sprite rendering, and sound playback, all from Yarn scripts -- and you can basically make a visual novel without writing C# code.

Ropework is meant to show how extensible and flexible Yarn Spinner is, and makes heavy use of that system's custom Yarn Command syntax. It was relatively easy for me to define new functions like <<Scene>> (change the scene background image) or <<PlayAudio>> (play a sound file) and hook into those with Yarn Spinner's [YarnCommand( )] C# attribute.

I ended up writing a fairly long visual novella so I could "dog food" my own system, which helped me figure out patterns and workflows. For instance, Yarn commands follow the pattern <<Command GameObject Parameters>>, and I realized there was no concept of a "global" command. I ended up devising a syntactical crutch to rename my game manager into an "@" symbol, which meant every Ropework command would look more like <<Command @ Parameters>> and seems to make the script look cleaner... I think.

Anyway, I tried to setup as many nice defaults as I could. There's a subtle sprite enlarge / highlight effect when an actor talks, and I even put some actor name detection in there. But in the end, Ropework is just an example template for others to study and modify for their own games. I hope we see more visual novels during game jams now -- or, at least, people can rip the DialogueUI code for whatever game they want.

Merino was motivated by my desire for a more fully-featured Yarn editor, and then realizing I could feasibly build it over the weekend. From a technical perspective, I'm not sure if writing Yarn scripts in the Unity Editor interface helps that much; in theory, the pay-off would be in tightly integrating Unity object references with Yarn scripts somehow, but until I figure out what that looks like, the benefits will be mostly psychological. The textbox is right there, now you have no excuse to avoid implementing your narrative design.

I was also motivated by some of our past students who often want to focus on building narrative games, and then they spend way too much time learning how to build their first dialogue system. To be clear, I like building narrative systems and I think it's good practice to build your own -- but as an educator, I kept witnessing the same problems and same outcomes. Maybe here, the education will be less in building your own narrative system, and more in studying the workflow and architecture of someone else's system.

In designing Merino, I went against a lot of trends in narrative system design. The core of the Merino interface is big textboxes. I don't like the dozens of Unity dialogue systems that make you create separate nodes for each line, or the numerous plugins that make me file a tax return just to run a conversation. Here, I think we must follow the example of word processors, wiki systems, and social media: type stuff into a big box. That's it.

* * *

As usual, we end the digest with a Yarn tip. This one's from me.

The ExampleDialogueUI code included in Yarn Spinner does one thing that annoys me a little -- when it presents options to the player, it hides the previous line of dialogue. I don't think I've ever played a game where this is desired behavior? So here's an easy C# modification to make Yarn Spinner keep the last line of dialogue on-screen when displaying choices.

In ExampleDialogueUI.cs near the end of the RunLine() function at around line 120, it will look like this:

// Wait for any user input
while (Input.anyKeyDown == false) {
yield return null;

// Hide the text and prompt
lineText.gameObject.SetActive (false);

if (continuePrompt != null)
continuePrompt.SetActive (false);

Just comment out that one line of code beneath the "Hide the text and prompt" comment. That code should now look like this:

// Hide the text and prompt
// lineText.gameObject.SetActive (false);

And with that, now you'll finally be able to ask the player questions, and keep displaying the question on screen. Easy, right?

Until next time, fellow darners!