Simple Dialogue Error

Tried to follow this video on dialogue and it just overlaps the text and no longer types out?

using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;

public class Dialogue : MonoBehaviour
{
    public TextMeshProUGUI dialogueText;
    public string[] lines;
    public float textSpeed;

    private int index;
    public bool isClicking = false;


    private void Start()
    {
        dialogueText.text = string.Empty;
        StartDialogue();
    }


    void Update()
    {
        if(isClicking)
        {
            if(dialogueText.text == lines[index])
            {
                NextLine();
            }

            else
            {
                StopAllCoroutines();
                dialogueText.text = lines[index];
            }
        }
    }


    void StartDialogue()
    {
        index = 0;
        StartCoroutine(TypeLine());
    }

    IEnumerator TypeLine()
    {
        foreach(char c in lines[index].ToCharArray())
        {
            dialogueText.text += c;
            yield return new WaitForSeconds(textSpeed);
        }
    }

    public void NextLine()
    {
        if(index < lines.Length - 1)
        {
            index++;
            dialogueText.text = string.Empty;
            StartCoroutine (TypeLine());
        }
        else
        {
            gameObject.SetActive(false);
        }
    }
}

This is the correct approach:

Two steps to tutorials and / or example code:

  1. do them perfectly, to the letter (zero typos, including punctuation and capitalization)
  2. stop and understand each step to understand what is going on.

If you go past anything that you don’t understand, then you’re just mimicking what you saw without actually learning, essentially wasting your own time. It’s only two steps. Don’t skip either step.

Step #2 is particularly critical when learning.

If you are unwilling or unable to do Step #2, just ask someone else to do the whole game for you.

It just sounds like you wrote a bug… and that means… time to start debugging!

If you were diligent in Step #2 above, that is what lets you quickly focus on the correct systems involved in your mistake, which might not even be code considering you say “just overlaps.” Overlapping is usually to do with layouts, but not always.

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Remember with Unity the code is only a tiny fraction of the problem space. Everything asset- and scene- wise must also be set up correctly to match the associated code and its assumptions.

All that said, dialog systems are a VERY well-traveled area of gamedev:

Dialog system fundamentals and structure:

There are also some free packages you could start from:

Fungus: https://fungusgames.com

Inkle: https://www.inklestudios.com

A free Ink-Fungus gateway product:

Even if you don’t end up using either of those, you could review them for structure because it is almost certain that they have already solved all the same problems you are trying to solve.

You’re most likely running multiple coroutines simultaneously. NextLine() isn’t stopping the already-running coroutine, and worse yet: depending on whether isClicking stays true for more than a frame it could call NextLine multiple times.

Since you need only a single coroutine and a way to stop it respectively to know whether it runs, keep the coroutine as a field and null it when the coroutine ended. That way you’ll avoid the common bug of running multiple coroutines by accident.

Here’s the update script, I had Gemini generate it (untested but should work):

using System.Collections;
using TMPro;
using UnityEngine;

public class Dialogue : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI dialogueText;
    [SerializeField] private string[] lines;
    [SerializeField] private float textSpeed = 0.05f;

    private int _index;
    private Coroutine _typeRoutine;
    private bool _isTyping => _typeRoutine != null;

    private void OnEnable() => StartDialogue();

    public void OnClickInput() // Link this to your Input System component or Button
    {
        if (_isTyping)
        {
            // Skip to end of current line
            StopCoroutine(_typeRoutine);
            _typeRoutine = null;
            dialogueText.text = lines[_index];
        }
        else
            NextLine();
    }

    private void StartDialogue()
    {
        _index = 0;
        DisplayLine();
    }

    private void DisplayLine()
    {
        dialogueText.text = "";
        _typeRoutine = StartCoroutine(TypeLine());
    }

    private IEnumerator TypeLine()
    {
        foreach (char c in lines[_index])
        {
            dialogueText.text += c;
            yield return new WaitForSeconds(textSpeed);
        }
        _typeRoutine = null; // Typing finished
    }

    private void NextLine()
    {
        _index++;
        if (_index < lines.Length)
            DisplayLine();
        else
            gameObject.SetActive(false);
    }
}

I thought i had debugged all sections of the code, turns out i didnt think about the very initial click input, and each click was setting the ‘isClicking’ bool to true permenantly. So the issue was with the input all along :person_facepalming::person_facepalming:

Glad you’re back in service!!

One must work through the six stages of debugging:

DENIAL. That can’t happen.
FRUSTRATION. That doesn’t happen on my machine.
DISBELIEF. That shouldn’t happen.
TESTING. Why does that happen?
GOTCHA. Oh, I see.
RELIEF. How did that ever work?

You may laugh now, but it will really seem hilarious to you after the 1000th time it happens.