Search Results for

    Show / Hide Table of Contents

    Dialogue Views

    A dialogue view controls how text is presented to the player. Assign a view to the engine's Dialogue View field, or leave it empty to run in headless mode.

    Ibralogue ships with two built-in views. You can also create your own by subclassing DialogueViewBase.

    Headless / Event-Driven Mode

    The dialogue view is optional. When no view is assigned, the engine runs the full dialogue pipeline (parsing, variable resolution, invocations, events) without driving any UI. All typed events (OnLineDisplayed, OnChoicesPresented, OnChoiceSelected) still fire normally.

    This is useful for:

    • Driving custom UI through events (e.g., UI Toolkit)
    • Non-visual dialogue consumers (analytics, quest tracking, testing)
    • Systems that only need the data, not the presentation

    In headless mode, lines complete instantly (no animation) and choices must be submitted programmatically:

    dialogueEngine.OnChoicesPresented.AddListener((choices) =>
    {
        // Present choices in your own UI, then:
        dialogueEngine.SelectChoice(choices[selectedIndex]);
    });
    

    TypewriterDialogueView

    Reveals text one character at a time, like a typewriter.

    Field Description
    Character Delay Seconds between each character reveal. Default: 0.03.
    Character Window Number of characters revealed per step. Default: 1.

    The OnTypewriterEffectUpdated event fires each time characters are revealed. This is useful for playing a typing sound effect.

    The delay can also be changed at runtime:

    typewriterView.SetCharacterDelay(0.01f);
    

    PunchDialogueView

    Reveals text one word at a time.

    Field Description
    Word Delay Seconds between each word reveal. Default: 0.2.

    The OnPunchEffectUpdated event fires each time a new word becomes visible.

    punchView.SetWordDelay(0.1f);
    

    Skipping the Effect

    Both built-in views support skipping the reveal animation. Call SkipViewEffect() to instantly show all text for the current line:

    dialogueView.SkipViewEffect();
    

    Shared Fields

    All views inherit these fields from DialogueViewBase:

    Field Description
    Name Text A TextMeshProUGUI component for displaying the speaker name.
    Sentence Text A TextMeshProUGUI component for displaying the dialogue text.
    Choice Button Holder A Transform that serves as the parent for instantiated choice buttons.
    Choice Button A prefab with a ChoiceButton component. Used when choices are displayed.

    The OnSetView event fires every time a new dialogue line is displayed. The OnLineComplete event fires when the view finishes its display effect.

    Creating a Custom View

    To create your own view, subclass DialogueViewBase and override the relevant methods. The SetView method receives a Line object containing the speaker, text, image, and metadata for the current line:

    public class MyCustomView : DialogueViewBase
    {
        public override void SetView(Line line)
        {
            base.SetView(line);
            // Your custom display logic here
        }
    
        public override bool IsStillDisplaying()
        {
            // Return true while your effect is still running
            return false;
        }
    
        public override void SkipViewEffect()
        {
            // Instantly complete your effect
        }
    
        public override void ClearView()
        {
            base.ClearView();
            // Any additional cleanup
        }
    }
    

    The engine calls SetView when a line should be displayed, waits until IsStillDisplaying returns false, and then waits for the player to advance. ClearView is called before each new line and when the conversation ends.

    Invocation Timing in Animated Views

    When a view reveals text incrementally (like the typewriter or punch views), invocations placed inline in dialogue text fire at their character position as the text is revealed. For example, {{Audio(boom)}} placed mid-sentence fires when the view reaches that point in the text.

    With views that display text instantly (like the base DialogueViewBase), all invocations fire immediately since the full text is visible from the start.

    Custom views that implement incremental text reveal should update VisibleCharacterCount to enable position-based invocation timing:

    public override int VisibleCharacterCount
    {
        get { return sentenceText.maxVisibleCharacters; }
    }
    

    Auto-Advance

    Set the Auto-Advance Delay field on the engine to a value greater than zero to make lines advance automatically after the display effect finishes. The delay is in seconds. Choices still require player input.

    This is useful for cutscenes or ambient dialogue where no player interaction is needed.

    // Enable auto-advance from code
    dialogueEngine.AutoAdvanceDelay = 2.0f;
    
    // Disable it
    dialogueEngine.AutoAdvanceDelay = 0f;
    

    Player Input

    Use Advance() as your single input handler for player clicks, key presses, or taps. It skips the current display effect if a line is still playing, or advances to the next line if idle:

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
            dialogueEngine.Advance();
    }
    

    Next() is available if you want the old behavior of only advancing when the current line is finished (no skip).

    Custom Views Without TextMeshPro

    The base class nameText and sentenceText fields are optional. If your view uses a different text system (UI Toolkit, custom renderer), leave them unassigned and override SetView and ClearView:

    public class UIToolkitView : DialogueViewBase
    {
        private Label _nameLabel;
        private Label _textLabel;
    
        public override void SetView(Line line)
        {
            _nameLabel.text = line.Speaker;
            _textLabel.text = line.LineContent.Text;
            OnSetView.Invoke();
        }
    
        public override void ClearView()
        {
            _nameLabel.text = "";
            _textLabel.text = "";
        }
    }
    

    Chat / Message UI Pattern

    The engine calls ClearView before each new line. For a chat UI that accumulates messages, override ClearView to preserve previous messages:

    public class ChatView : DialogueViewBase
    {
        [SerializeField] private Transform messageContainer;
        [SerializeField] private GameObject messagePrefab;
    
        public override void SetView(Line line)
        {
            var bubble = Instantiate(messagePrefab, messageContainer);
            bubble.GetComponentInChildren<TMP_Text>().text =
                $"{line.Speaker}: {line.LineContent.Text}";
            OnSetView.Invoke();
        }
    
        public override void ClearView()
        {
            // Keep previous messages. Only override if you need
            // to clean up transient UI (typing indicators, etc.)
        }
    }
    

    Customizing the Engine Display Loop

    If you need to customize what happens when a line is displayed (beyond what a view provides), you can subclass the engine and override OnDisplayLine:

    public class MyEngine : SimpleDialogueEngine
    {
        protected override IEnumerator OnDisplayLine(Line line)
        {
            // Custom logic before display
            Debug.Log($"{line.Speaker} says: {line.LineContent.Text}");
    
            // Call base to use the standard view/plugin/function pipeline
            yield return base.OnDisplayLine(line);
    
            // Custom logic after display
        }
    }
    
    • Edit this page
    In this article
    Back to top Ibralogue Docs