Add interactive choices that let players shape the dialogue
This example demonstrates how to create dialogue with player choices (options). Players can select from multiple options, and each option leads to a different dialogue branch.
extends DialogueEngineenum { DEFAULT_TOPIC = 0, # this is the default branch id used at each add_text_entry call unless a different branch ID is specified GO_BACK_TO_SLEEP = 1, KEEP_WORKING = 2,}func _setup() -> void: var entry: DialogueEntry = add_text_entry("The storm rages right outside the window. I should...") var option_id_1: int = entry.add_option("Go back to sleep.") var option_id_1_entry: DialogueEntry = add_text_entry("That's right, sleep is for the strong 💪.", GO_BACK_TO_SLEEP) entry.set_option_goto_id(option_id_1, option_id_1_entry.get_id()) var option_id_2: int = entry.add_option("Get back to work.") var option_id_2_entry: DialogueEntry = add_text_entry("That's right, let's get back to work 🫡", KEEP_WORKING) entry.set_option_goto_id(option_id_2, option_id_2_entry.get_id()) # Join branches into the default topic (i.e. branch id 0) var default_topic: DialogueEntry = add_text_entry("Some time passes...") option_id_1_entry.set_goto_id(default_topic.get_id()) option_id_2_entry.set_goto_id(default_topic.get_id()) # None of the following entries will be connected on the graph and won't be shown when advancing the dialogue add_text_entry("A sleep entry skipped due to missing goto against this entry.", GO_BACK_TO_SLEEP) add_text_entry("A working entry due to missing goto against this entry.", KEEP_WORKING) add_text_entry("<Press 'Space' or 'Enter' to quit>")
var option_id_1: int = entry.add_option("Go back to sleep.")var option_id_1_entry: DialogueEntry = add_text_entry("That's right, sleep is for the strong 💪.", GO_BACK_TO_SLEEP)entry.set_option_goto_id(option_id_1, option_id_1_entry.get_id())
For each option:
Add the option text: add_option() returns an option ID
Create the target entry: Add the dialogue entry for this choice path
Link them: Use set_option_goto_id() to connect the option to its target entry
The option ID is returned by add_option() and is used to reference that specific option. Option IDs start at 0 and increment with each added option.
var default_topic: DialogueEntry = add_text_entry("Some time passes...")option_id_1_entry.set_goto_id(default_topic.get_id())option_id_2_entry.set_goto_id(default_topic.get_id())
Both choice branches converge back to a common dialogue entry. This ensures the dialogue continues regardless of which option was chosen.
Use set_goto_id() to explicitly link entries. This creates a “jump” from one entry to another, useful for joining branches or creating loops.
add_text_entry("A sleep entry skipped due to missing goto against this entry.", GO_BACK_TO_SLEEP)add_text_entry("A working entry due to missing goto against this entry.", KEEP_WORKING)
These entries are in the dialogue tree but are not connected to any other entry, so they will never be reached during dialogue execution.
Entries without incoming connections (no goto pointing to them) are unreachable and won’t be displayed. Use the debugger to visualize your dialogue tree and find disconnected entries.
if p_dialogue_entry.has_options(): for option_id: int in range(0, p_dialogue_entry.get_option_count()): var option_text: String = p_dialogue_entry.get_option_text(option_id) # ...
Check if the current entry has options using has_options(), then iterate through all options with get_option_count().
func __advance_dialogue_with_chosen_option(p_option_id: int) -> void: for button: Button in enabled_buttons: button.set_disabled(true) enabled_buttons.clear() var current_entry: DialogueEntry = dialogue_engine.get_current_entry() current_entry.choose_option(p_option_id) dialogue_engine.advance() set_process_input(true)
When an option is selected:
Disable all option buttons
Clear the button array
Get the current entry and call choose_option() with the selected ID
Advance the dialogue
Re-enable keyboard input
You must call choose_option() before calling advance() when handling options. The engine needs to know which option was chosen to determine the next entry.
1. "The storm rages right outside the window. I should..." [Options displayed] - Go back to sleep. - Get back to work.2a. [Player chooses "Go back to sleep"] "That's right, sleep is for the strong 💪." "Some time passes..." "<Press 'Space' or 'Enter' to quit>"2b. [Player chooses "Get back to work"] "That's right, let's get back to work 🫡" "Some time passes..." "<Press 'Space' or 'Enter' to quit>"
You can nest options to create complex dialogue trees:
func _setup() -> void: var entry1: DialogueEntry = add_text_entry("What would you like to know?") # First level options var opt_lore: int = entry1.add_option("Tell me about the lore") var opt_quests: int = entry1.add_option("Any quests available?") var opt_goodbye: int = entry1.add_option("Goodbye") # Lore branch with nested options var lore_entry: DialogueEntry = add_text_entry("Which topic interests you?", branch.LORE) entry1.set_option_goto_id(opt_lore, lore_entry.get_id()) var opt_history: int = lore_entry.add_option("The kingdom's history") var opt_magic: int = lore_entry.add_option("Magic system") var history_entry: DialogueEntry = add_text_entry("Long ago, this kingdom...", branch.HISTORY) lore_entry.set_option_goto_id(opt_history, history_entry.get_id()) var magic_entry: DialogueEntry = add_text_entry("Magic flows through...", branch.MAGIC) lore_entry.set_option_goto_id(opt_magic, magic_entry.get_id()) # Quests branch var quest_entry: DialogueEntry = add_text_entry("I have a task for you...", branch.QUESTS) entry1.set_option_goto_id(opt_quests, quest_entry.get_id()) # Goodbye branch var goodbye_entry: DialogueEntry = add_text_entry("Farewell!") entry1.set_option_goto_id(opt_goodbye, goodbye_entry.get_id()) # Join all branches back to common end var end_entry: DialogueEntry = add_text_entry("Come back anytime.") history_entry.set_goto_id(end_entry.get_id()) magic_entry.set_goto_id(end_entry.get_id()) quest_entry.set_goto_id(end_entry.get_id()) goodbye_entry.set_goto_id(end_entry.get_id())