RelationsInspector Node-graph editor for Unity

Event-driven Dialogs with node-based Editor

This post covers the creation of a simple general purpose dialog system, including a visual Editor that makes it easy to use for even complex dialog graphs. It’s versatile: thanks to Unity’s event widget, you can hook up any code to the dialog buttons. Of course we won’t create a button for each dialog instance. You can also form any shape of dialog connections: chains, trees, loops, graphs. The project lives on GitHub.

Data Setup

Let’s define a dialog as a UI element that presents the player with some information and, optionally, a choice of replies. When the user selects a reply, there should be some effect on the game and the dialog UI should disappear. Translated to C# data types:

public class DialogItem : MonoBehaviour
{
	public string text;
	public List<DialogReply> replies;
}

[Serializable]
public class DialogReply
{
	public string text;
	public DialogItem nextDialog;
	public Button.ButtonClickedEvent effect;
}

The dialog and each reply get a text field to present their information. As a visual improvement you could add fields for style, avatar image, positioning and such. The reply class also has an effect field, which holds all gamestate changes that should happen when this reply is picked.

We could store a “open that dialog” action as part of the effect event, but we want to be able to visualize the connections between dialogs and inspecting the internals of a UnityEvent is hard. That’s why there’s an extra field for it, called nextDialog.

Now you can put DialogItem components into empty GameObjects and fill them with content. This dialog turns another GameObject on/off:

UI Setup

The Dialog UI is minimal: a panel with a vertical layout group, containing one Text for the question and enough Buttons to cover the maximum number of replies we expect. I chose five.

Hooking up data and UI

We need a manager component that can be used by the game to show and hide dialogs. Showing a dialog involves activating the panel and populating the question text and reply buttons from a given DialogItem. For hiding the dialog, we’ll deactivate the panel. The full C# code is here. Make sure not to put the manager on the panel’s GameObject, or it will deactivate itself along with the panel. In the example project, the manager is attached to the Main Camera.

Testing

Now we can feed DialogItems to the manager. The DialogTester component, attached to the Main scene’s Camera, opens dialogs with you press A or B and closes them when you press C.

  • Dialog A lets you toggle the camera background image.
  • Dialog B is a flowchart that helps the player to decide how to act in a hunger situation.

Node-based editing

For things like conversations, you need to link many DialogItems together. The bigger such a graph gets, the harder it is to maintain and understand their structure. This is where node-based editors shine, and the RelationsInspector lets us create one easily. We just need to supply a backend class, similar to Unity’s custom inspectors. Then we can select our backend in the RelationsInspector and drag DialogItems into its window. The backend’s main purpuse is to define what the graph nodes should represent, and how they are connected:

public class DialogBackend : MinimalBackend<DialogItem, string>
{
	public override IEnumerable<Relation<DialogItem, string>> GetRelations( DialogItem entity )
	{
		if ( entity.replies == null )
			yield break;

		foreach ( var reply in entity.replies )
		{
			if ( reply.nextDialog == null )
				continue;

			yield return new Relation<DialogItem, string>( entity, reply.nextDialog, reply.text );
		}
	}
}

The full implementation also adds context menu items for manipulating the dialog graph, you can see it here. It is commented out because it dependds on the RelationsInspector package. Once you install the package, you can un-comment the backend code and check out the flowchart dialog example from the main scene. It should look something like this:

Right-clicking on the nodes and arrows gives you access to the graph-manipulation options defined in the backend. Not all changes done outside the graph window will be reflected by the graph.. to update it, use the Rebuild toolbar button. For more information about RelationInspector features, see the manual.

That’s it, now you’re all set up for using dialogs in your projects.