Options allow players to make choices in dialogue, creating interactive conversations. Each option represents a possible response the player can choose, and each option can lead to different dialogue branches.
Options are attached to text entries using add_option():
var entry = add_text_entry("What would you like to know?")# Add options to the entryvar option_1 = entry.add_option("Tell me about yourself.")var option_2 = entry.add_option("Where am I?")var option_3 = entry.add_option("Goodbye.")
Each option returns an option ID (starting from 0) that you use to configure where that option leads.
Every option needs a goto that specifies which dialogue entry to jump to when that option is chosen:
var entry = add_text_entry("What would you like to know?")# Add optionsvar option_1 = entry.add_option("Tell me about yourself.")var option_2 = entry.add_option("Where am I?")# Create target entries for each optionvar about_entry = add_text_entry("I'm a humble merchant.")var location_entry = add_text_entry("You're in the village square.")# Connect options to their targetsentry.set_option_goto_id(option_1, about_entry.get_id())entry.set_option_goto_id(option_2, location_entry.get_id())
Options without valid gotos will cause the dialogue to cancel when chosen. Always set gotos for your options.
Your UI code is responsible for presenting options to the player and calling choose_option() when the player makes a choice:
# When dialogue_continued is emitted with an entry that has options:dialogue_engine.dialogue_continued.connect(func(entry: DialogueEntry) -> void: if entry.has_options(): # Present options to the player for i in entry.get_option_count(): var option_text = entry.get_option_text(i) print("%d. %s" % [i + 1, option_text]) # When player selects option (e.g., option 0): entry.choose_option(0) # Then advance to process the choice dialogue_engine.advance())
Options commonly lead to different branches that later merge back together:
enum { DEFAULT_TOPIC = 0, GO_BACK_TO_SLEEP = 1, KEEP_WORKING = 2,}func _setup() -> void: var entry = add_text_entry("The storm rages outside. I should...") # Option 1: Sleep branch var option_id_1 = entry.add_option("Go back to sleep.") var sleep_entry = add_text_entry("Sleep is for the strong.", GO_BACK_TO_SLEEP) entry.set_option_goto_id(option_id_1, sleep_entry.get_id()) # Option 2: Work branch var option_id_2 = entry.add_option("Get back to work.") var work_entry = add_text_entry("Let's get back to work.", KEEP_WORKING) entry.set_option_goto_id(option_id_2, work_entry.get_id()) # Merge branches back to main path var merge_point = add_text_entry("Some time passes...") sleep_entry.set_goto_id(merge_point.get_id()) work_entry.set_goto_id(merge_point.get_id()) add_text_entry("<Press 'Space' or 'Enter' to quit>")
var entry = dialogue_engine.get_current_entry()# Check if entry has any optionsif entry.has_options(): print("This entry has player choices")# Get the number of optionsvar count = entry.get_option_count()print("Number of options: ", count)# Check if entry has no optionsif entry.is_options_empty(): print("No choices available")
var entry = dialogue_engine.get_current_entry()# Get option textfor i in entry.get_option_count(): var text = entry.get_option_text(i) print("Option %d: %s" % [i, text])# Get option gotovar goto_id = entry.get_option_goto_id(0)var goto_entry = entry.get_option_goto_entry(0)if goto_entry: print("Option 0 leads to: ", goto_entry.get_text())
var entry = add_text_entry("What would you like?")var option_id = entry.add_option("Original text")# Change option textentry.set_option_text(option_id, "Updated text")# Remove a specific optionentry.remove_option_at(option_id)# Clear all optionsentry.clear_options()
# Check if an option was chosenif entry.has_chosen_option(): var chosen = entry.get_chosen_option() print("Player chose option: ", chosen)# Clear the chosen optionentry.remove_chosen_option()
Here’s a full example from the demos showing a branching options dialogue:
extends DialogueEngineenum { DEFAULT_TOPIC = 0, GO_BACK_TO_SLEEP = 1, KEEP_WORKING = 2,}func _setup() -> void: var entry = add_text_entry("The storm rages right outside the window. I should...") var option_id_1 = entry.add_option("Go back to sleep.") var option_id_1_entry = 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 = entry.add_option("Get back to work.") var option_id_2_entry = 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 var default_topic = 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()) add_text_entry("<Press 'Space' or 'Enter' to quit>")
Both options and conditions create branching dialogue, but they serve different purposes:
Options
Player makes the choice
Creates interactive dialogue
Requires UI to present choices
Pauses dialogue flow until choice is made
Conditions
Game logic makes the choice
Creates dynamic responses
Processes automatically
No pause in dialogue flow
# Options: Player decidesvar entry = add_text_entry("What will you do?")entry.add_option("Fight") # Player choosesentry.add_option("Flee")# Conditions: Game decidesvar condition = add_conditional_entry(func() -> bool: return player_is_brave # Game checks state)
# Invalid option IDentry.choose_option(99) # Warns and cancels dialogue# Missing gotovar option_id = entry.add_option("Test")# If set_option_goto_id() is never called, choosing this option will cancel dialogue# Invalid gotoentry.set_option_goto_id(option_id, 9999) # Non-existent entry ID# Choosing this option will cancel dialogue
Invalid options trigger the dialogue_canceled signal, allowing you to handle errors gracefully in your UI.
You can create options dynamically based on game state:
var entry = add_text_entry("What would you like to buy?")# Add options based on available itemsfor item in shop_inventory: if player.gold >= item.price: var option_id = entry.add_option("Buy %s (%d gold)" % [item.name, item.price]) var response = add_text_entry("You bought %s." % item.name) entry.set_option_goto_id(option_id, response.get_id())
func _setup() -> void: var hub = add_text_entry("What would you like to know?") # Add multiple topics var topics = [ ["Tell me about the town.", "This is a peaceful village..."], ["Tell me about the quest.", "A dragon threatens the kingdom..."], ["Tell me about yourself.", "I'm just a simple merchant..."], ] for topic in topics: var option_id = hub.add_option(topic[0]) var response = add_text_entry(topic[1]) entry.set_option_goto_id(option_id, response.get_id()) # Return to hub after each topic response.set_goto_id(hub.get_id()) # Add exit option var exit_id = hub.add_option("Goodbye.") var exit_entry = add_text_entry("Farewell!") hub.set_option_goto_id(exit_id, exit_entry.get_id())
var entry = add_text_entry("How can I help you?")if player.has_item("letter"): var option_id = entry.add_option("I have a letter for you.") var response = add_text_entry("Ah, thank you!") entry.set_option_goto_id(option_id, response.get_id())if player.quest_active: var option_id = entry.add_option("About that quest...") var response = add_text_entry("How's it going?") entry.set_option_goto_id(option_id, response.get_id())# Always available optionvar goodbye_id = entry.add_option("Never mind.")var goodbye = add_text_entry("Alright then.")entry.set_option_goto_id(goodbye_id, goodbye.get_id())
var timer = Timer.new()var auto_choice_made = falsedialogue_engine.dialogue_continued.connect(func(entry: DialogueEntry) -> void: if entry.has_options() and not auto_choice_made: # Show options to player display_options(entry) # Start timer timer.start(5.0) # 5 second limit await timer.timeout # If player hasn't chosen, auto-select if not entry.has_chosen_option(): entry.choose_option(0) # Default to first option dialogue_engine.advance() auto_choice_made = true)