Engine Integration Guide¶
This guide shows how to load and play TaleNode dialogue JSON in your game engine.
General Approach¶
- Load the JSON file and parse it into your engine's data structures
- Initialize variables from the
variablesarray - Find the
startnode — this is the entry point - Follow
nextfields to traverse the dialogue graph - Handle each node type according to its
typefield
Traversal Algorithm¶
1. current_node = find node where type == "start"
2. current_node = find node by current_node.next
3. loop:
a. switch on current_node.type:
- "dialogue": display text, wait for player input, follow next
- "choice": display options, wait for selection, follow selected option's next
- "condition": evaluate variable, follow true_next or false_next
- "event": execute actions, follow next
- "random": pick weighted random branch, follow branch's next
- "end": dialogue is over
b. if next is null, dialogue is over
Unity (C#)¶
The TaleNode Unity package includes a ready-to-use TaleNodeRunner class. You don't need to write your own data classes or traversal logic.
Quick Start¶
using TaleNode;
using UnityEngine;
public class DialogueUI : MonoBehaviour
{
private TaleNodeRunner runner;
void Start()
{
runner = new TaleNodeRunner();
runner.OnDialogueLine += (s, e) =>
{
Debug.Log($"{e.Speaker}: {e.Text}");
// Show in your UI, then call runner.Advance() when player clicks
};
runner.OnChoicePresented += (s, e) =>
{
Debug.Log($"Prompt: {e.Prompt}");
for (int i = 0; i < e.Options.Count; i++)
Debug.Log($" {i}: {e.Options[i]}");
// Show choices in UI, then call runner.Choose(index)
};
runner.OnDialogueEnded += (s, e) =>
{
Debug.Log($"Ended with tag: {e.Tag}");
};
runner.OnEventTriggered += (s, e) =>
{
Debug.Log($"Event: {e.Action} {e.Key}={e.Value}");
};
runner.OnVariableChanged += (s, e) =>
{
Debug.Log($"Variable {e.Key} = {e.Value}");
};
runner.LoadDialogue("Assets/Dialogues/intro.talenode.json");
runner.Start();
}
}
TaleNodeRunner API¶
| Method | Description |
|---|---|
LoadDialogue(string path) |
Load dialogue from a JSON file path |
LoadFromString(string json) |
Load dialogue from a JSON string |
Start(string startNodeId = null) |
Start the dialogue (optionally from a specific node) |
Advance() |
Continue to the next node after a dialogue line |
Choose(int index) |
Select a choice option by index |
GetVariable(string name) |
Get a runtime variable value |
SetVariable(string name, TaleValue value) |
Set a runtime variable value |
Stop() |
Stop the dialogue immediately |
IsRunning |
Whether a dialogue is currently active |
Events¶
| Event | Args | When |
|---|---|---|
OnDialogueStarted |
EventArgs |
Dialogue begins |
OnDialogueLine |
Speaker, Text, Emotion, Portrait, Audio, NodeId |
A dialogue line is reached |
OnChoicePresented |
Prompt, Options (List<string>) |
A choice node is reached |
OnDialogueEnded |
Tag |
Dialogue ends (at an End node or dead end) |
OnEventTriggered |
Action, Key, Value |
A non-variable event action fires |
OnVariableChanged |
Key, Value |
A variable is set or modified |
Expression Interpolation¶
The runner automatically interpolates {variable} expressions in dialogue text and choice prompts. You can also use the expression engine directly:
using TaleNode;
// Evaluate an expression
TaleValue result = TaleNodeExpression.Evaluate("gold >= 100", variables);
// Evaluate as boolean
bool check = TaleNodeExpression.EvaluateBool("has_key && level > 5", variables);
// Interpolate text
string text = TaleNodeExpression.InterpolateText("You have {gold} gold.", variables);
Editor Tools¶
The Unity package also includes editor tools for viewing and testing dialogues inside Unity. See the Unity Editor Tools guide.
Godot (GDScript)¶
Loading¶
func load_dialogue(path: String) -> Dictionary:
var file = FileAccess.open(path, FileAccess.READ)
var json = JSON.parse_string(file.get_as_text())
return json
func build_node_map(dialogue: Dictionary) -> Dictionary:
var map = {}
for node in dialogue["nodes"]:
map[node["id"]] = node
return map
Running¶
var dialogue: Dictionary
var node_map: Dictionary
var variables: Dictionary
func start_dialogue(path: String):
dialogue = load_dialogue(path)
node_map = build_node_map(dialogue)
# Initialize variables
variables = {}
for v in dialogue["variables"]:
variables[v["name"]] = v["default"]
# Find start node
var start = dialogue["nodes"].filter(func(n): return n["type"] == "start")[0]
process_node(node_map[start["next"]])
func process_node(node: Dictionary):
match node["type"]:
"dialogue":
show_dialogue(node)
# Call process_node(node_map[node["next"]]) on continue
"choice":
show_choices(node)
# Call process_node(node_map[option["next"]]) on selection
"condition":
var result = evaluate(node["variable"], node["operator"], node["value"])
var next_id = node["true_next"] if result else node["false_next"]
process_node(node_map[next_id])
"event":
for action in node["actions"]:
execute_action(action)
process_node(node_map[node["next"]])
"random":
var branch = pick_weighted(node["branches"])
process_node(node_map[branch["next"]])
"end":
end_dialogue(node["tag"])
Tips¶
Null next fields
Always check if next (or true_next/false_next) is null before following it. A null next means the output port was not connected in the editor.
Character lookup
Build a character map (id → character) at load time. Dialogue nodes reference characters by ID (e.g., "char_1"), not by name.
Choice conditions
If a choice option has a condition, evaluate it against your variables to determine visibility. Only show options whose conditions are met (or have no condition).
Custom events
Event actions with type Custom have a freeform key — map these to your game's event system as needed.