Skip to content

Variables

The built-in variable store lets designers read and write game state directly from the graph — no C# required. Variables live in a DialogueVariables ScriptableObject asset. Choice conditions check them, NPC nodes and Set Variable nodes mutate them, and text tokens embed their values into dialogue lines.


The DialogueVariables asset

A DialogueVariables asset is a ScriptableObject that holds a named list of typed variables. Create one per logical domain (quests, economy, flags, etc.) or one for the whole project — your choice.

Create one: right-click in the Project window → Create → Threader → Variables Store.

Each variable in the list has:

Field Description
Name The key used everywhere — in the graph dropdown, in {token} substitution, and in code. Case-sensitive.
Display Name Optional human-readable label used by {varName:name} token substitution. If blank, falls back to Name.
Type Bool / Int / String
Bool Value Default value when Type = Bool
Int Value Default value when Type = Int
String Value Default value when Type = String

The inspector is type-aware — it shows only the relevant value field for each variable: a checkbox for Bool, an integer field for Int, and a text field for String. Clean collapsible rows with a remove button and a + Add Variable button at the bottom.

DialogueVariables asset in the Inspector


Runtime behaviour

The asset stores design-time defaults in its serialized fields. At runtime, InitRuntime() copies those defaults into in-memory dictionaries (Dictionary<string, bool>, Dictionary<string, int>, Dictionary<string, string>). All reads and writes during a play session hit those dictionaries — the asset on disk is never modified at runtime.

InitRuntime() is called automatically on first access (EnsureInit()). In Play mode, OnDisable() on the ScriptableObject clears the runtime state so that stopping Play mode always resets variables back to design-time defaults.

This means: - Variables start fresh every Play session (from the Inspector defaults) - If you need to persist variables across sessions, save them yourself — see Saving - If you need to reset variables mid-session (e.g. starting a new game), call vars.InitRuntime()


Assigning to DialogueManager

Select your DialogueManager GameObject in the scene and drag your DialogueVariables asset(s) into the Variables List slot.

You can assign multiple assets — the runner searches all of them in order when resolving a variable name. This lets you split variables logically:

GameVariables.asset   — foundCat, questState, playerName
EconomyVariables.asset — gold, price, credits

When the runner looks up gold, it checks GameVariables first, then EconomyVariables. The first asset that contains gold wins.


Reading and writing variables from the graph

Inline conditions on Player Choice nodes

Open a Player Choice node. Inside each choice card is a Conditions box with a + Add button. Each row compares one variable against a value:

Field Description
Variable Dropdown populated from all assigned DialogueVariables assets
Operator Equal / NotEqual / GreaterThan / GreaterOrEqual / LessThan / LessOrEqual. Numeric operators (GreaterThan, GreaterOrEqual, etc.) are hidden automatically for Bool and String variables.
Value Type-aware field — checkbox for Bool, integer field for Int, text field for String. Updates automatically when you change the variable.
Hide Checked = hide this choice entirely when the condition fails. Unchecked = show greyed-out.
NOT Inverts this row's result

All rows must pass (AND logic). There is no built-in OR — split into separate choice cards instead.

Set actions on NPC nodes

Open any NPC nodeSet Vars section → + Add:

Operator Bool Int String
Set var = value var = value var = value
Add (n/a) var += value (n/a)
Subtract (n/a) var -= value (n/a)
Toggle var = !var (n/a) (n/a)

Set actions fire before events do, so the next Player Choice node in the same conversation already sees the updated value.

Set Variable Node

Use a Set Variable Node [V] when you need to write variables without showing any NPC dialogue. It applies all its actions silently and advances to the next connected node. Useful for:

  • Setting a flag at the start of a branch before any lines play
  • Resetting a counter in a loop
  • Marking story progress at a dead-end branch with no reply text needed

Variable substitution in text

You can embed variable values directly in any NPC line or Player Choice text using curly-brace tokens. The runner resolves them at display time, so a variable changed by an NPC node's Set action earlier in the same conversation is already reflected.

Syntax

Token What it produces
{varName} The current value — the number, true/false, or string
{varName:name} The variable's Display Name (falls back to Name if Display Name is blank)

Examples

"You found {catCount} cats!"
→  "You found 3 cats!"

"You have {E_Credits} {E_Credits:name}."
→  "You have 42 Credits."

"Nice to meet you, {playerName}!"
→  "Nice to meet you, Alex!"

"Pay {price} {price:name}?"   ← in a choice button
→  "Pay 50 Gold?"

How it works

The resolver scans each variable asset in the VariablesList order, finds the first asset that contains varName, then returns:

  • Bool: "true" or "false" (lowercase)
  • Int: the integer as a string
  • String: the string value directly

If no variable with that name is found, the token is left as-is (e.g. {typo}) — this acts as an authoring hint so you can spot mistyped names immediately.

Tokens are case-sensitive and must exactly match the variable's Name field.

Original data is never mutated

The resolver creates a new display copy of each NPCLine and ChoiceData before firing OnNPCLine and OnChoiceNode. The source objects on the ScriptableObject asset are never touched, so your token text remains intact in the graph editor after a play session.


Reading and writing from C# code

// Get the Variables asset(s) from the manager
var vars = DialogueManager.Instance.VariablesList[0];

// Read
bool   found = vars.GetBool("foundCat");
int    gold  = vars.GetInt("gold");
string name  = vars.GetString("playerName");

// Write
vars.SetBool("foundCat",   true);
vars.SetInt("gold",        gold - 50);
vars.SetString("playerName", "Alex");

// Read with display name
string displayName = vars.GetDisplayName("E_Credits"); // "Credits" or "E_Credits" if blank

// Reset all variables to design-time defaults
vars.InitRuntime();

// Reset every assigned Variables asset
foreach (var v in DialogueManager.Instance.VariablesList)
    v.InitRuntime();

You can call these at any time — before starting dialogue, mid-session from a game system, or during loading.


Naming conventions

Variable names are free-form strings but some conventions prevent common bugs:

  • camelCase works well: foundCat, playerGold, questPhase
  • Prefix by system if you have many: E_Credits, Q_VillagerQuest, F_FirstMeeting
  • Avoid spaces — they work but make {token} substitution harder to read
  • Never rename a variable after you've referenced it in the graph — the graph stores the name as a string; renaming breaks all references silently

Full walkthrough example

"The player should only see 'Take the cat' after they've visited the cat's location."

Step 1 — Variables asset:

foundCat    Bool    false

Step 2 — NPC node "The cat is over there!":

Set Vars:  foundCat | Set | true

Step 3 — Player Choice node, choice "Take the cat":

Conditions:  + Add
  Variable = foundCat
  Operator = Equal
  Value    = true
  Hide     = ✓  ← hide entirely until the condition is met

Result: "Take the cat" is invisible on first visit. After the player reaches the NPC node that sets foundCat = true, the choice appears automatically on the next visit.


Multiple variable assets — search order

When you assign multiple assets to DialogueManager → Variables List, lookups search each asset in the order they appear in the list. The first asset containing the variable name is used.

This means you can have the same variable name in two assets — only the one that appears first in the list will ever be found. Use distinct names across assets to avoid confusion.