Skip to main content
This example demonstrates the most basic usage of the Dialogue Engine: creating a simple linear dialogue with multiple text entries and connecting to signals to display them.

Overview

In this example, you’ll learn how to:
  • Create a DialogueEngine instance
  • Add text entries with BBCode formatting
  • Connect to dialogue signals
  • Advance through dialogue
  • Display dialogue in the UI

Setting Up the Dialogue

First, let’s create a DialogueEngine by extending it and adding text entries in the _setup() method:
extends DialogueEngine

func _setup() -> void:
    add_text_entry("Hey...")
    add_text_entry("[i]Have [i][b]you[/b][/i] seen the code for this sample?[/i]")
    add_text_entry("[rainbow freq=1.0 sat=0.4 val=0.8]It's beautiful![/rainbow]")
    add_text_entry("[i][shake rate=20.0 level=5 connected=1]You won't believe it![/shake][/i]")
    add_text_entry("[code][i]Press <Enter> or <Space> to exit.[/i][/code]")
The _setup() method is automatically called when the DialogueEngine is instantiated. This is the recommended place to build your dialogue tree.

BBCode Support

Notice that the dialogue entries use BBCode tags for rich text formatting:
  • [i] for italic text
  • [b] for bold text
  • [rainbow] for rainbow color effect
  • [shake] for shaking text effect
  • [code] for monospace font
DialogueEngine text entries support all BBCode tags that Godot’s RichTextLabel supports. This includes colors, fonts, images, and custom effects.

Creating the UI

Now let’s create the UI script that displays the dialogue:
extends VBoxContainer

@export var dialogue_gdscript: GDScript = null
var dialogue_engine: DialogueEngine = null

func _ready() -> void:
    dialogue_engine = dialogue_gdscript.new()
    dialogue_engine.dialogue_started.connect(__on_dialogue_started)
    dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
    dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)

func _input(p_input_event: InputEvent) -> void:
    if p_input_event.is_action_pressed(&"ui_accept"):
        dialogue_engine.advance()

func __on_dialogue_started() -> void:
    print("Dialogue Started!")

func __on_dialogue_continued(p_dialogue_entry: DialogueEntry) -> void:
    var label: RichTextLabel = RichTextLabel.new()
    label.set_use_bbcode(true)
    label.set_fit_content(true)
    label.set_text("  > " + p_dialogue_entry.get_text())
    add_child(label)

func __on_dialogue_finished() -> void:
    print("Dialogue Finished! Exiting...")
    get_tree().quit()

Code Breakdown

1. Setting Up the Engine

@export var dialogue_gdscript: GDScript = null
var dialogue_engine: DialogueEngine = null

func _ready() -> void:
    dialogue_engine = dialogue_gdscript.new()
The dialogue GDScript is exported so you can assign it in the Godot editor. When the node is ready, we instantiate the DialogueEngine.

2. Connecting to Signals

dialogue_engine.dialogue_started.connect(__on_dialogue_started)
dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)
We connect to three key signals:
  • dialogue_started: Emitted when dialogue begins
  • dialogue_continued: Emitted for each text entry (this is where we display text)
  • dialogue_finished: Emitted when dialogue ends

3. Advancing the Dialogue

func _input(p_input_event: InputEvent) -> void:
    if p_input_event.is_action_pressed(&"ui_accept"):
        dialogue_engine.advance()
Each time the player presses Enter or Space, we call advance() to move to the next dialogue entry.

4. Displaying the Text

func __on_dialogue_continued(p_dialogue_entry: DialogueEntry) -> void:
    var label: RichTextLabel = RichTextLabel.new()
    label.set_use_bbcode(true)
    label.set_fit_content(true)
    label.set_text("  > " + p_dialogue_entry.get_text())
    add_child(label)
For each dialogue entry, we create a new RichTextLabel to display the text with BBCode formatting enabled.
In a real game, you would typically reuse a single label and update its text, rather than creating new labels. This example creates new labels for demonstration purposes.

Dialogue Flow

Here’s how the dialogue progresses:
  1. Player starts the game
  2. Press Enter/Space → dialogue_started emits, first entry displays: “Hey…”
  3. Press Enter/Space → Second entry displays: “Have you seen the code…”
  4. Press Enter/Space → Third entry displays: “It’s beautiful!”
  5. Press Enter/Space → Fourth entry displays: “You won’t believe it!”
  6. Press Enter/Space → Fifth entry displays: “Press Enter or Space to exit.”
  7. Press Enter/Space → dialogue_finished emits, game exits
  8. Press Enter/Space again → Dialogue restarts from the beginning

Complete Example in One File

If you prefer to keep everything in a single script without extending DialogueEngine:
extends VBoxContainer

var dialogue_engine: DialogueEngine = null

func _ready() -> void:
    # Create the dialogue engine
    dialogue_engine = DialogueEngine.new()
    
    # Build the dialogue
    dialogue_engine.add_text_entry("Hey...")
    dialogue_engine.add_text_entry("[i]Have you seen the code?[/i]")
    dialogue_engine.add_text_entry("[rainbow]It's beautiful![/rainbow]")
    dialogue_engine.add_text_entry("[shake]Amazing![/shake]")
    
    # Connect signals
    dialogue_engine.dialogue_continued.connect(__on_dialogue_continued)
    dialogue_engine.dialogue_finished.connect(__on_dialogue_finished)

func _input(p_input_event: InputEvent) -> void:
    if p_input_event.is_action_pressed(&"ui_accept"):
        dialogue_engine.advance()

func __on_dialogue_continued(p_dialogue_entry: DialogueEntry) -> void:
    var label: RichTextLabel = RichTextLabel.new()
    label.set_use_bbcode(true)
    label.set_fit_content(true)
    label.set_text("  > " + p_dialogue_entry.get_text())
    add_child(label)

func __on_dialogue_finished() -> void:
    print("Dialogue Finished!")

Key Takeaways

Use dialogue_continued to display text - This signal provides the DialogueEntry with all the text and metadata you need.
Call advance() to progress - The dialogue only moves forward when you explicitly call advance().
Enable BBCode for rich text - Set set_use_bbcode(true) on RichTextLabel to enable formatting.
Dialogue auto-restarts - After finishing, calling advance() again will restart the dialogue from the beginning.

Next Steps

Conditional Branching

Learn how to create dialogue that branches based on conditions

Player Options

Add player choices to your dialogue

Build docs developers (and LLMs) love