Game development and more

Making a dialogue tool for my games

I like story-driven games, and the dialogue mechanic for me is a must have regardless of the genre, be it a tradional point-and-click adventure, or an RPG, or a first-person shooter. I don't like to read walls of text, and don't want to make players read them, but even a few lines of dialogue may make a difference.

When making a dialogue-based game, a dedicated tool is an important part of your workflow. I've checked all the existing dialogue authoring tools and decided to made my own.

Links

If you don't want to read the article, here are the links to the final result:

Requirements

I needed a dialogue format that is:

  • Engine-independent. Currently I am using Unity 3D for my games, but I also would like to reuse it in javascript-based games or online applications.
  • Node-based. Each dialogue piece is a graph node, the reply is a graph edge.
  • Minimalistic. As little node types as possible.
  • Game-agnostic. The dialogue format shouldn't assume anything about the game mechanics it is being used in. It even shouldn't assume the text is being writen is for game or for a different app.
  • Programming language-agnostic. The dialogue format shouldn't assume anything about the script language being used in the game
  • Easily editable without a dedictated tool. Open it as a text file, add changes.
  • Has localization support. The most standard way is to use CSV-tables.
  • Easy extensible. You, as a user, should be able to add custom properties to nodes.

And the tool should be:

  • Platform-agnostic: run anywhere
  • Good-looking. At least not ugly.
  • Compact. An average game dialogue with options should fit on the screen.
  • Comfortable. That means good UX. Everything you would expect from a modern tool

Analyzing existing tools

Yes, my idea isn't new, and there is plenty of dialogue authoring tools out there already. Here's my look at some of them.

Articy:Draft

I haven't tried this software. I've read it was used in Disco Elysium, one of my favourite games of the last decade. Pros:

  • By the looks of it, very professional tool

Cons:

  • It makes a lot of assuptions, such as your game having characters, portraits, etc.

Dialogue system for Unity

Cons:

  • It costs $95
  • It runs only in Unity

It also has an interesting design decision - dialogue options are also represented as nodes in the editor, a concept that I myself used in one of my dialogue editor tools earlier.

Twine

Not just a software for writing dialogues, but for creating text-based games. I used Twine to make a couple of short story games myself. Pros:

  • Playtest your game in browser, no external engines needed

Cons:

  • It can export story formats to other engines, such as Unity, but the export data is very limited
  • Has 3 different story type formats, with different concepts, diffrerent mark-up language and different capabilites
  • No localization support

Overall, not a good choice for dialogues only.

Ink

Pros:

  • Simple and easy to read.
  • Plugins exist for integration into Unity.

Cons:

  • Mixing logic with strings
  • No localization support
  • Nested identation format makes long dialogues hardly readable

Narrat

Pros:

  • Simple dialogue format, similar to YAML

Cons:

  • Integration with game engines only by embedding a Chromium engine and running Narrat as an app, no native runtime

Similar to Twine, good choice for standalone and web games, bad if you want to use it just for dialogues.

Yarn Spinner

This is probably the most close to what I was seeking. Maybe I should have used it, but I didn't like how interacting with variables and external script was made (spoiler: I don't think I did any better, after all). NIH syndrom made me make my own tool.

Problems

I have already established my requirements for a perfect dialogue editor. But before that, there were months of uncertainity. I have either been using other tools, or working without any plan or concept. After several months of usage, I've outlined these design problems:

Representation of the structure

There are two types of architecture I can think of for a dialogue tree:

1. Each dialogue element is a node

Text is a node, player choice is a node.

Pros:

  • It visualizes the flow better (in my opinion)
  • It requires only one type of graphical element

Cons:

  • To get the current dialogue state and the possible options, you either have to walk the graph to collect all the choices and follow all the conditions (and it also means the conditions have to be evaluated at that stage already), or keep a separate structure for visual representation and a separate structure for runtime.
  • It takes more space on the screen

2. Only dialogue stage is a node

And each option is an edge connecting the nodes. Pros:

  • One node represents the current state
  • Navigating the dialogue tree is walking a regular graph
  • It takes less space on the screen

Cons:

  • You need to design how to show dialogue choices. They have to be compact but informative at the same time. E.g. writing text on the edges (like in BPMN, for example) isn't a good choice

Types of nodes

Again, two decision were available from the top of my head:

1. As much nodes as possible.

I can have a Dialogue Node, a Choice Node, a Script Node, an If/Else Node, a Switch Node, a Random Choice Node, etc.

Pros:

  • You may script any logic with the editor

Cons:

  • This is supposed to be a dialogue editor, not a visual scripting tool.

2. As few nodes as possible.

The least I could think of were Dialogue Node (containing actual text), a Script Node (containing a script for engine to interpret) and a Start node (designating the entry point).

Pros:

  • Very clean, not tempting to write game logic in your dialogue

Cons:

  • May be too few, too much responsibility lies on the scripts

Regarding the last issue, I've added a Condition node that can evaluate the condition and then choose the first branch that returns "true". Now I can write any dialogue logic with this structure.

Separation of logic and text

First I made my dialogue format store strings (like "Hello, traveller, welcome to our city", etc) inside the dialogue tree, but later added support for string lookup in the CSV file. In Unity, the runtime uses the Localization package.

Also, now I am planning to add "export strings inside dialogue tree" option or something similar, so you can have your strings in one file, if you are not planning any translations.

Localization

The standard decistion is to use CSV tables. They can be easily imported ito Unity localization system.

DSL vs existing script

Game dialogue should not only display text (images, sounds, etc) and let players choose dialogue options, but also check some conditions, set variables and trigger some external events. When I was making my own Dialogue System in Unity, I could choose a Game Object in the inspector, but in an engine-agnostic system I need to integrate an external script.

Again, I had two options:

  1. Simple DSL to evaluate conditions
  2. Dedicated language, like Lua, Python, etc

Eventually, I decided to support both options. I've made a simple expression language to use it in Unity (or any other C# app) and I want later to integrate Lua as a scripting language.

What I currently don't like about my DSL is that it doesn't support scoped variables. All variables are global. On the other hand, if you want to use language features, it is better to make your own "setVariable" functions and then use them to set variables in special contexts, e.g. "setPlayerVariable", "setEnemyVariable", "setMapVariable", etc.

What I like about my DSL is that it doesn't allow you to write complex logic in the scripts. There are not if/else constructions, no loops. In other words, it's not Turing-complete. It forces you to call externall functions as callbacks, and handle your game logic in your game scripts, not inside dialogues.

Another thing I like that its variable system doesn't allow setting/getting Unity Engine GameObjects. I think it's not the responsibility of the dialogue system, it is too low level. This is what I didn't like about Yarn Spinner: it can reference your Unity game objects, but the binding is very weak - it searches the scene for an object with a certain name. I think it is a bad practice.

Dialogue format

The perfect dialogue format for me turned out to be YAML (or rather it's subset). XML or JSON are too verbose for raw editing.

Framework and language for the tool

The only option for me was Javascript:

  • I already know it well
  • There are a lot of node-rendering libraries (more about that below)
  • It can produce a web-based application or a standalone offline app (Chromium)

Stages of development

Unity dialogue system

Unity dialogue editor

The first tool I made long before I had the idea for an engine-independent dialogue editing software. It had:

  • Dialogue text, choices and conditions as nodes
  • 10 types of nodes
  • Dialogue tree validation
  • Point-and-click variable and condition editing, no code needed
  • Ugly design

I didn't know about Unity GraphView API at the time and didn't want to use XNode or other packages, so all the nodes are drawn as simple UGUI rectangles.

I stumbled upon a block when I came to a point when I wanted to provide a callback function from an instantiated GameObject from a scene. The dialogue asset is designed as a ScriptableObject, so it doesn't know anything about any scenes.

Currently, the project is on hold indefinetely.

Vibe-coded node-based system

Drawflow dialogue editor The second attempt was different. I've already decided it should be written in Javascript and also established some design decisions (as written above).

I've consulted AI to help me choose a node rendering library that is

  • free and open source
  • not React based (used too much React at work and tired of it)
  • simple and easy to learn

It suggested me Drawflow.js. Which is nice library, but later turned out that it:

  • doesn't have any API to bind and update arbitrary data to node, you have to dig into node internals to to that
  • doesn't have good API for node ports and edges

I've tried running several AI tools to generate the correct code for my technical requirements. After three days of work (!!!) I had a working prototype. Which turned out to be unmaintainable in terms of code, but not completely useless.

Final system

Datflow dialogue editor

The final result took me 10 days to finish. It is based on Vueflow framework and thus is called Datflow. (DAT = Dialogue Authoring tool). I also count the time I've tested all the libraries listed below. You can read more about it here: https://github.com/maximryzhov/datflow

Choosing the right library for node rendering

Before I've chosen Vueflow, I've made a list of Javascript node rendering libraries. It may be useful to someone.

  1. DrawFlow.js - minimalistic, but has a fatal flaw with data binding/access
  2. Plumb.js Toolkit Edition - very good, minimalistic, but not free
  3. Plumb.js CE - limited in functions compared to Toolkit editing. Some vital things are missing, such as reactive data binding.
  4. JointJS+ - more complex than the first two, but more professional. Not free though.
  5. JointJS Free - free version is good, but too limited. E.g. it doesn't have zoom implemented, among other things.
  6. VueFlow - Looks very good, Vue based
  7. ReactFlow - Overall good, but React-based, something I want to avoid
  8. MaxGraph - very low level, requires lots of boilerplate. Ugly out of the box. Has some advanced features, such as ManhattanConnector and obstacle avoidance.
  9. Cytoscape - good for graphs overall, but not for node systems
  10. Vis.js - the same as Cytoscape
  11. Rete.js (former D3.js) - have security concerns about this one
  12. litegraph.js - used in ComfyUI. Looks very good, but is too advanced for the task
  13. Go.js - very good, but very expensive

Share Back to main