0
\$\begingroup\$

I am trying to make a dialogue system in Unity by following this tutorial: (29) 5 Minute DIALOGUE SYSTEM in UNITY Tutorial - YouTube. There is a slight twist to this and that is that I am triggering this conversation based on an event which is triggered when the boss is in sight. However, once the conversation starts, it just prints out the letter c endlessly and goes into an infinite loop. I’ve tried looking for the cause of this problem and using a boolean flag to indicate when the characters are being "typed" but I still can’t seem to figure it out. Any help with this is much appreciated. Here is the code for the Event/Delegate class and the Dialogue class respectively:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DialogueDelegateEvent : MonoBehaviour
{
    public delegate void BossInSight(bool inSight);

    public static event BossInSight OnBossInSight;

    //for ending the conversation:
    public delegate void ConversationComplete();
    public static event ConversationComplete OnConversationComplete;

    private static DialogueDelegateEvent instance;

    public static DialogueDelegateEvent Instance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<DialogueDelegateEvent>();
            }
            return instance;
        }
    }

    public void SetBossInSight()
    {
        OnBossInSight?.Invoke(true);
    }

    public void EndConversation()
    {
        OnConversationComplete?.Invoke();
    }
}

Dialogue.cs class (class responsible for playing the dialogue lines):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

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

    private int index;

    private void OnEnable()
    {
        DialogueDelegateEvent.OnBossInSight += BeginConversation;
        BeginConversation(false);
    }

    private void OnDisable()
    {
        DialogueDelegateEvent.OnBossInSight -= BeginConversation;
    }

    void Start()
    {
        textComponent.text = string.Empty;
    }

    private void BeginConversation(bool inSight)
    {
        if (inSight)
        {
            Time.timeScale = 0f;
            StartDialogue();
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            if(textComponent.text == lines[index])
            {
                NextLine();
            }
            else
            {
                textComponent.text = lines[index];
                StopAllCoroutines();
            }
        }
    }

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

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

    void NextLine()
    {
        if (index < lines.Length - 1)
        {
            index++;
            textComponent.text = string.Empty;
            StartCoroutine(TypeLine());
        }
        else
        {
            DialogueDelegateEvent.Instance.EndConversation();
            gameObject.SetActive(false);
            Time.timeScale = 1f;
        }
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Is this the tutorial you are talking about? If so, I could show you how to turn it into a link. \$\endgroup\$
    – Philipp
    Commented Nov 16, 2023 at 16:07

1 Answer 1

1
\$\begingroup\$

once the conversation starts, it just prints out the letter c endlessly and goes into an infinite loop.

It sounds to me like that problem is probably that you keep retriggering the BossInSight event every frame the boss is in sight, and not just on the first frame. The result would then be that the dialog restarts every frame, which would output the first character again and again.

To solve this problem, either make sure the event only gets invoked once, that you unsubscribe the event listener after it fired once, or that your BeginConversation method checks if the conversation is already running, and if that's the case doesn't start it again.


There is also another problem here which you probably didn't realize yet. You are using coroutines with yield return new WaitForSeconds(textSpeed) to type out the text, but you are also setting Time.timeScale = 0f while the dialog is running. The timeScale also affects WaitForSeconds statements. So those yields won't return while the timeScale is 0. If you want the dialog to keep running while the rest of the game is paused, you probably want to use WaitForSecondsRealtime instead.

\$\endgroup\$
3
  • \$\begingroup\$ Would the events actually still trigger if Time.timeScale is set to zero? \$\endgroup\$
    – Zibelas
    Commented Nov 16, 2023 at 17:43
  • \$\begingroup\$ @Zibelas That depends on what triggers the events and how. Which is unfortunately not included in the code of the question. I would assume it happens somewhere in some Update method. Updates still get executed with time.timeScale == 0f. They just get executed with deltaTime being 0 as well. \$\endgroup\$
    – Philipp
    Commented Nov 16, 2023 at 18:11
  • \$\begingroup\$ Thanks a lot for your solution. The problem was indeed that the in-sight event was being called at every frame, hence the loop. Also, using WaitForSecondsRealtime really helped. Much appreciated! :) \$\endgroup\$ Commented Nov 16, 2023 at 18:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .