Part of these game systems:
beginner Dialogue

Dialogue Trigger

Simple NPC dialogue with sequential messages, typewriter effect, and input to advance. No branching — just clean text sequences.

Unity 2022.3+ · 2.5 KB · DialogueTrigger.cs

How to Use

1

Create a Canvas with a dialogue panel (panel, name text, message text)

2

Attach DialogueTrigger to your NPC or sign object

3

Fill in the speaker name and messages array

4

Assign the UI references in inspector

5

Call dialogueTrigger.StartDialogue() from your interaction system

6

Press Space or Click to advance through messages

7

For branching dialogue, use the full Dialogue System instead

Source Code

DialogueTrigger.cs
C#
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using TMPro;
using System.Collections;

/// <summary>
/// Simple sequential dialogue system with typewriter effect.
/// Trigger from NPCs, signs, or any interactable object.
/// </summary>
public class DialogueTrigger : MonoBehaviour
{
    [Header("Dialogue Content")]
    [SerializeField] private string speakerName = "NPC";
    [SerializeField] [TextArea(2, 5)] private string[] messages;

    [Header("UI References")]
    [SerializeField] private GameObject dialoguePanel;
    [SerializeField] private TextMeshProUGUI nameText;
    [SerializeField] private TextMeshProUGUI messageText;

    [Header("Typewriter")]
    [SerializeField] private float typeSpeed = 0.03f;
    [SerializeField] private bool useTypewriter = true;

    [Header("Input")]
    [SerializeField] private KeyCode advanceKey = KeyCode.Space;

    [Header("Events")]
    public UnityEvent OnDialogueStart;
    public UnityEvent OnDialogueEnd;
    public UnityEvent<int> OnMessageChanged;

    private int currentMessageIndex;
    private bool isDialogueActive;
    private bool isTyping;
    private Coroutine typeCoroutine;

    /// <summary>Is a dialogue currently playing?</summary>
    public bool IsActive => isDialogueActive;

    /// <summary>
    /// Start the dialogue sequence.
    /// </summary>
    public void StartDialogue()
    {
        if (isDialogueActive || messages == null || messages.Length == 0) return;

        isDialogueActive = true;
        currentMessageIndex = 0;

        if (dialoguePanel != null)
            dialoguePanel.SetActive(true);

        if (nameText != null)
            nameText.text = speakerName;

        OnDialogueStart?.Invoke();
        ShowMessage(currentMessageIndex);
    }

    private void Update()
    {
        if (!isDialogueActive) return;

        if (Input.GetKeyDown(advanceKey) || Input.GetMouseButtonDown(0))
        {
            if (isTyping)
            {
                // Skip typewriter, show full message
                if (typeCoroutine != null)
                    StopCoroutine(typeCoroutine);
                messageText.text = messages[currentMessageIndex];
                isTyping = false;
            }
            else
            {
                // Advance to next message
                currentMessageIndex++;
                if (currentMessageIndex < messages.Length)
                {
                    ShowMessage(currentMessageIndex);
                }
                else
                {
                    EndDialogue();
                }
            }
        }
    }

    private void ShowMessage(int index)
    {
        OnMessageChanged?.Invoke(index);

        if (useTypewriter)
        {
            if (typeCoroutine != null)
                StopCoroutine(typeCoroutine);
            typeCoroutine = StartCoroutine(TypeMessage(messages[index]));
        }
        else
        {
            messageText.text = messages[index];
        }
    }

    private IEnumerator TypeMessage(string message)
    {
        isTyping = true;
        messageText.text = "";

        foreach (char c in message)
        {
            messageText.text += c;
            yield return new WaitForSecondsRealtime(typeSpeed);
        }

        isTyping = false;
    }

    private void EndDialogue()
    {
        isDialogueActive = false;

        if (dialoguePanel != null)
            dialoguePanel.SetActive(false);

        OnDialogueEnd?.Invoke();
    }

    /// <summary>
    /// Force-close the dialogue.
    /// </summary>
    public void ForceClose()
    {
        if (typeCoroutine != null)
            StopCoroutine(typeCoroutine);
        EndDialogue();
    }
}