Daniel Minder
Daniel Minder

Reputation: 29

C# Unity Queue NullReferenceException

I am trying to create a simple dialogue system for my game in Unity. I've set up a special trigger for a Dialogue to start and the code is passing right variable but somehow it gets stuck at clearing the queue and throws a NullReferenceException.

I've seen through debugger that all variables and triggers work perfectly fine till cs:27 inside DialogueManager.cs. I've also checked the inspector to make sure everything is correctly assigned.

Dialogue class:

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

[System.Serializable]
public class Dialogue
{
    public string name;

    [TextArea(3,10)]
     public string[] sentences;
}

DialogueTrigger class:

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

public class NPC_DialogTrigger : MonoBehaviour
{
    // Player
    public Transform player;

    // GameMaager to close
    public GameObject Gameplay;

    // Camera and Canvas to turn on
    public GameObject DialogueManager;

    // NPC Details
    public GameObject InteractionNPCNameTextField;
    public Transform interactionTransform;
    public float radius = 3f;
    private bool isBusy = false;

    // DialogueStart
    public GameObject DialogueStart;

    void Start()
    {
        InteractionNPCNameTextField.gameObject.SetActive(false);
    }

    void Update()
    {
         float distance = Vector3.Distance(player.position, interactionTransform.position);

         if (distance <= radius)
         {
              if (isBusy == false)
              {
                   InteractionNPCNameTextField.gameObject.SetActive(true);

                   if (Input.GetKeyDown(KeyCode.E))
                   {
                        Dialogue();
                        Debug.Log("Started Dialogue procedure.");
                   }
              }
         }
         else if (distance > radius)
         {
             InteractionNPCNameTextField.gameObject.SetActive(false);
         }
    }

    public void Dialogue()
    {
        Gameplay.SetActive(false);
        DialogueManager.SetActive(true);
        DialogueStart.GetComponent<DialogueStart>().TriggerDialogue();
        Debug.Log("Triggered Dialogue.");
    }

    void OnDrawGizmosSelected()
    {
        if (interactionTransform == null)
        {
            interactionTransform = transform;
        }

        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(interactionTransform.position, radius);
    }
}

DialogueStart class:

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

public class DialogueStart : MonoBehaviour
{
    public Dialogue dialogue;

    public void TriggerDialogue()
    {
        FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
         Debug.Log("Dialogue sent to dialogue manager.");
    }
}

DialogueManager class:

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

public class DialogueManager : MonoBehaviour
{
    public Text nameText;
    public Text DialogueText;

    private Queue<string> sentences;
    public GameObject DialogueManagerUI;

    void Start()
    {
        if (sentences == null)
        {
             sentences = new Queue<string>();
        }
    }

    public void StartDialogue (Dialogue dialogue)
    {
        Debug.Log("Received dialogues: " + dialogue);
        nameText.text = dialogue.name;
        Debug.Log("Start Dialogue: " + sentences.Count);
        sentences.Clear();
        Debug.Log("Sentences Cleared: " + sentences);

        foreach (string sentence in dialogue.sentences)
        {
             sentences.Enqueue(sentence);
        }

        DisplayNextSentence();
    }

    public void DisplayNextSentence()
    {
        if(sentences.Count == 0)
        {
            EndDialogue();
            return;
        }

        string sentence = sentences.Dequeue();
        DialogueText.text = sentence;
    }

    void EndDialogue()
    {
        Debug.Log("End of conversation.");
    }

    private void Update()
    {
        if (DialogueManagerUI.activeInHierarchy)
        {
            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
        }
        else if (!DialogueManagerUI.activeInHierarchy)
        {
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
        }
    }
}

Visual Studio doesn't give me any errors.

Unity error code -> Screenshot

Debugger right before issue -> Screenshot2

Seems to me like the Queue is never assigned to sentences and it remains empty. If it is so - why?

Upvotes: 0

Views: 940

Answers (1)

derHugo
derHugo

Reputation: 90679

It sounds like DialogueManager.StartDialogue probably via DialogueStart.TriggerDialogue is called from somewhere in either Awake or at least before your Start was executed.

Especially

DialogueManager.SetActive(true);

lets assume the DialogueManager object is inactive at first anyway. So maybe your stuff is called before it is set to active.

This might also be due to the Start where you set

InteractionNPCNameTextField.gameObject.SetActive(false);

so any component on this GameObject might not have its Start method getting called. Maybe you referenced the wrong GameObject here?

Debugging would help to figure out in which order your methods get called.

In general my thumb rule for initializing is

  • Do everything that depends only on yourself in Awake
  • Do everything that depends on other components being setup already in Start

This way you can (almost) always be sure that stuff is already initialized when you need it.


However, these are only guesses but

The simple solution here:

You could already solve this by simply initializing the sentences right away using

private readonly Queue<string> sentences = new Queue<string>();

now it is definitely initialized even before Start or Awake get called!

Upvotes: 3

Related Questions