Skip to main content
Branching dialogue allows you to create non-linear conversations where the dialogue flow can jump to different parts of your dialogue tree.

Understanding Branches

The Dialogue Engine uses two concepts to manage dialogue flow:
  • Branch IDs: Logical groups of dialogue entries (like chapters or conversation topics)
  • Goto IDs: Explicit jumps to specific dialogue entries

Branch IDs

Each dialogue entry belongs to a branch ID. By default, all entries use branch ID 0 (the default branch).
enum { DEFAULT_BRANCH = 0, DIFFERENT_BRANCH_ONE, DIFFERENT_BRANCH_TWO }

add_text_entry("This is on the default branch")  # Branch 0
add_text_entry("This is on branch one", DIFFERENT_BRANCH_ONE)
add_text_entry("This is on branch two", DIFFERENT_BRANCH_TWO)
The DialogueEngine will only advance through entries in the current branch unless you use gotos to jump between branches.

Using Gotos Within the Same Branch

1

Create entries and store references

Store references to entries you want to jump to:
extends DialogueEngine

func _setup() -> void:
    var first_entry: DialogueEntry = add_text_entry("This is an example of...")
    add_text_entry("This text will be skipped!")
    var target_entry: DialogueEntry = add_text_entry("a skipped dialogue!")
    add_text_entry("Press <Enter> or <Space> to exit.")
2

Set the goto

Use set_goto_id() to jump directly to another entry:
first_entry.set_goto_id(target_entry.get_id())
Now the dialogue will jump from “This is an example of…” directly to “a skipped dialogue!”, skipping the middle entry.

Jumping Between Different Branches

You can jump to entries in different branches to organize your dialogue into logical sections:
extends DialogueEngine

enum { DEFAULT_BRANCH = 0, BRANCH_ONE, BRANCH_TWO, BRANCH_THREE }

func _setup() -> void:
    # Start on default branch
    var first_entry: DialogueEntry = add_text_entry("This is an example of...", DEFAULT_BRANCH)
    
    # Jump to a different branch
    var branch_two_start: DialogueEntry = add_text_entry(
        "how gotos work against different branch IDs", 
        BRANCH_TWO
    )
    first_entry.set_goto_id(branch_two_start.get_id())
    
    # Continue on branch two
    add_text_entry(
        "Once you jump to a different branch ID, the DialogueEngine will only consider entries in that branch ID.",
        BRANCH_TWO
    )
    
    # This entry won't be reached (no goto points to it)
    add_text_entry(
        "This text will be shown in the debugger but not in the dialogue.",
        BRANCH_ONE
    )
    
    add_text_entry("Press <Enter> or <Space> to exit.", BRANCH_TWO)
When you jump to a different branch, the DialogueEngine automatically updates its internal branch ID tracker, so subsequent advance() calls will only consider entries in the new branch.

Default Flow (No Goto)

If you don’t set a goto, the DialogueEngine automatically advances to the next entry in the same branch:
enum { TOPIC_A = 0, TOPIC_B = 1 }

add_text_entry("First entry in topic A", TOPIC_A)   # Entry 0
add_text_entry("Second entry in topic A", TOPIC_A)  # Entry 1
add_text_entry("First entry in topic B", TOPIC_B)   # Entry 2
add_text_entry("Second entry in topic B", TOPIC_B)  # Entry 3
If you start on branch TOPIC_A, the dialogue will flow: Entry 0 → Entry 1 → Finished (Entry 2 is skipped because it’s in a different branch).

Complete Examples

extends DialogueEngine

func _setup() -> void:
    var first_entry: DialogueEntry = add_text_entry("This is an example of...")
    add_text_entry("This text will be shown on the debugger connected to branch ID 0")
    add_text_entry(
        "This text will be shown on the debugger as a separate graph node not connected to branch id 0",
        1
    )
    var first_entry_goto: DialogueEntry = add_text_entry(
        "a skipped dialogue! Check the debugger out!"
    )
    first_entry.set_goto_id(first_entry_goto.get_id())
    add_text_entry("Press <Enter> or <Space> to exit.")

Visualizing Your Dialogue

The built-in debugger automatically generates a graph visualization of your dialogue tree, showing:
  • All dialogue entries as nodes
  • Goto connections between entries
  • Branch IDs for each entry
  • Disconnected entries (unreachable dialogue)
Use the debugger to verify your dialogue flow is correct! It will show you any unreachable entries or broken connections.

Best Practices

Define branch IDs as enums for better readability:
enum DialogueBranch {
    MAIN_STORY = 0,
    SIDE_QUEST = 1,
    ROMANCE_PATH = 2,
}
var important_entry: DialogueEntry = add_text_entry("Important text")
# Later...
some_entry.set_goto_id(important_entry.get_id())
The debugger will show disconnected nodes for entries that can never be reached. This helps you catch dialogue flow bugs.

Next Steps

Build docs developers (and LLMs) love