A Conversation Starter

Dialogue systems have been in games since the early days. While games like Pong didn't need dialogue, text based adventure games relied on it. That's also true of modern games - you won't find characters speaking to one another, or the player, in Mario Kart, but it is key in Dragon Age.

(When I refer to a string throughout this, I mean a line of text)

It's been 10 years since I wrote my first dialogue system, which formed part of a quest system. It was incredible simplistic and, while it did allow for different text in different states, it did not allow for branching paths.

  • Is there a quest attached?
    • No
      • Display a string with some flavour text
    • Yes
      • Has the player already got the quest?
        • No
          • Display a string introducing the quest
        • Yes
          • Has the player completed the quest?
            • No
              • Display a string reminding the player of what to do
            • Yes
              • Has the player handed in the quest?
                • No
                  • Display a string thanking the player for completing the quest
                • Yes
                  • Display a string thanking the player for previously completing the quest

That worked well enough for what it was attempting to achieve, but then, for some reason, it was changed to display textures instead which meant that each string now had its own texture. We weren't going to, but if we ever released that game*, that would cause issues when it came to localising the game for countries that don't use English since we would have to do textures for every string in every language. And making sure that translation is an easy process is something I keep in mind at the start of every project, even if I don't plan on getting it translated, as trying to add it in later can cause big problems.

As part of an attempt to create another game in more recent years, I wrote a new dialogue system which gave the player some options to choose from which would determine the lines of text that followed. I've used the ideas behind that system as a starting point for the one I've ended up writing for Halloween Game. But if you are writing a dialogue system from scratch, what parts do you actually need?

At the basic level, a simple dialogue system needs a list of strings. It can then keep track of which one is currently displayed on screen, and then either automatically move onto the next one after a certain amount of time or wait for the user to confirm they have read it before moving on.

To give it a bit of flair, instead of displaying the whole string at once, it can be typed out one letter at a time. This can prevent the player from being overwhelmed with a mountain of text (but if they are being given a mountain in the first place, the writer / designer has made a mistake), and also gives the psychological illusion that the character is actually speaking. This can be achieved by having a separate display string which starts off with no text and then adds one character at a time until it matches the full string.

To give an indication of who is actually talking, the speaking character's name, or a portrait, or both, can be added.

But what if there are three strings, and each one is for a different character? Having two lists could work - one a list of characters, the other a list of strings - although you would have to make sure that the lists did not get out of sync. Although the system is now complex enough that instead of being a list of strings, it should be a list of custom dialogue objects, with each object containing which character is speaking, and the text they are going to say.

class DialogueObject
{
    string characterName;

    string dialogue;
}

So what about options? You could add in a list of strings, and then keep track of which string is currently highlighted. But then how does it know which object to move on to after that?

Create a different object for the option, and use a list of options instead. The option will have the text that it is displaying, and also include a dialogue object to link it to the next bit of dialogue to trigger.

class DialogueObject
{
    string characterName;

    string dialogue;
    List<DialogueOption> options;

    int currentOption;
}

class DialogueOption
{
    string text;

    DialogueObject nextDialogue;
}

The game can then be given an initial dialogue object, and it can then display another once an option has been selected.

The in-game dialogue system for Halloween Game at the point it was implemented. The actual game will not have these strings, and probably won't feature Professor Forgetful.

Now there's a working dialogue system, what happens when it comes to translating it?

Instead of having all the strings hardwired in code, put them in a file and give each one an ID. These IDs can then get set against the dialogue object, and when it is time to display it, it will look in the file for that ID and get the matching string.

There can then be different files for different languages and, depending on what language is set, the appropriate file can be loaded, the ID can be looked up and the translation of the string can be returned.

They don't have to be in different files - as long as there is some way to distinguish between the languages and load the right value using the same ID, it should work. The following example ditches the idea of a dialogue system for simplicity, but shows a basic setup for getting two different values using the same ID (disclaimer: this code is just an example, although it should work).

public class Program
{
    public void Main()
    {
        DisplaySomeText();
    }
    void DisplaySomeText()
    {
        string textId = "TheString";

        string textEnglish = GetString(textId, "English");
        string textGerman = GetString(textId, "German");

        Console.WriteLine(textEnglish);
        Console.WriteLine(textGerman);
    }

    string GetString(string id, string language)
    {
        if (language == "German")
        {
            return Values.German[id];
        }

        return Values.English[id];
    }
}

class Values
{
    public static Dictionary<string, string> English = new Dictionary<string, string>
    {
        { "TheString", "My favourite football team is the flea market." }
    };

    public static Dictionary<string, string> German = new Dictionary<string, string>
    {
        { "TheString", "Mein Lieblingsfußballmannschaft ist der Flohmarkt." }
    };
}

The dialogue system I have in Halloween Game started out along the same lines as the examples above, although it has been expanded to trigger certain events. I'm expecting to have to revisit it at some point and add some new features like playing sound effects, or changing character animations, when certain lines are shown.

This post is also probably incredibly misleading, since it suggests that dialogue is a big part of Halloween Game when it isn't really. It just so happens this was the first mechanic I picked out since it's used at the start of the game, and I was hoping to tap into it when I wrote the shop since, despite what gamers think, reusing stuff is good.

Next week is a step back from mechanics to talk about money.

* Technically the game was released.

Popular posts from this blog

Getting Started with the FireRed Decompilation

Phoning It In

Tonight Matthew, I'm Going to Make...