Create a dialog system using Ink file

hi everyone,

I try to do a dialog system and for that I created those gameObject:

And the panel use this script to display the UI:

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

public class DialogSystem : MonoBehaviour
{
    public TextAsset inkFile;   // Reference to the Inky file we want to use
    private Story story;        // Reference to the Ink story

    public TextMeshProUGUI dialogText;     // Reference to the UI text element that will display the dialog
    public Button[] choiceButtons;  // References to the UI button elements that will display the choices


    private void Start()
    {
        // Initialize the Ink story using the Inky file
        story = new Story(inkFile.text);


    }

    private void Update()
    {
        // If the player clicks a choice button, continue the dialog with the corresponding choice
        for (int i = 0; i < choiceButtons.Length; i++)
        {
            if (choiceButtons[i].gameObject.activeSelf && Input.GetMouseButtonDown(0))
            {
                ChooseOption(i);
            }
        }
    }

    public void ContinueDialog()
    {
        Debug.Log("Continue dialog");
        // Check if there's more dialog to display
        if (story.canContinue)
        {
            // Get the next line of dialog
            string dialog = story.Continue();

            // Display the dialog on the UI text element
            dialogText.text = dialog;

            // Hide all choice buttons
            foreach (Button button in choiceButtons)
            {
                button.gameObject.SetActive(false);
            }

            // Check if there are choices to display
            if (story.currentChoices.Count > 0)
            {
                // Display the choices on the corresponding UI button elements
                for (int i = 0; i < story.currentChoices.Count; i++)
                {
                    Choice choice = story.currentChoices[i];
                    choiceButtons[i].gameObject.SetActive(true);
                    choiceButtons[i].GetComponentInChildren<TextMeshProUGUI>().text = choice.text;
                }
            }
        }
        else
        {
            this.gameObject.SetActive(false);
        }
    }
    public void ContinueDialogFromExternal()
    {
        ContinueDialog();
    }

    private void ChooseOption(int optionIndex)
    {
        // Choose the corresponding option in the Ink story
        story.ChooseChoiceIndex(optionIndex);

        // Continue the dialog with the chosen option
        ContinueDialog();
    }
}

And I created those gameobject call NPC (for non playable character):


who contained this script and their dialog (inkFile) inside “TextAsset inkJSON” :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
public class DialogueTrigger : MonoBehaviour
{
    [Header("Visual Cue")]
    [SerializeField] private GameObject visualCue;// "SerializeField" = show the variable in the inspector even if private
    //visualcue is a game object for the text buble

    [Header("Ink JSON")]
    [SerializeField] private TextAsset inkJSON;

    [Header("Dialog panel")]
    [SerializeField] private GameObject dialPanel;


    //new input system step 1
    PlayerInputActions playerInputs;
    private InputAction interact;

    private bool playerInRange;

    private void Awake()
    {
        playerInRange = false;
        visualCue.SetActive(false);

        //new input system step 2
        playerInputs = new PlayerInputActions();
    }

    private void OnEnable()
    {
        playerInputs.Enable();
        interact = playerInputs.Player.Interact;
        interact.Enable();
        interact.performed += Interact;
    }

    private void OnDisable()
    {

        interact.Disable();
        playerInputs.Disable();
    }
    private void Update()
    {
        if (playerInRange)
        {
            visualCue.SetActive(true);
        }
        else
        {
            visualCue.SetActive(false);
        }
    }

    private void Interact(InputAction.CallbackContext context)
    {
        if (playerInRange)
        {
            Debug.Log("start dialog");
            dialPanel.SetActive(true);
           
            // Get the DialogSystem component attached to the same GameObject as this DialogueTrigger component
            DialogSystem dialogSystem = GetComponent<DialogSystem>();

            // Start the dialogue
            dialogSystem.ContinueDialog();
        }
    }

    private void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")//if the gameobject touch another gameobject with the tag "Player"
        {
            playerInRange = true;
            Debug.Log("enter trigger");

        }
        else
        {
            playerInRange = false;
            Debug.Log("enter but wrong tag");
        }

    }

    private void OnTriggerExit2D(Collider2D collider)
    {
        if (collider.gameObject.tag == "Player")
        {
            playerInRange = false;
            Debug.Log("exit trigger");
        }
        else
        {
            playerInRange = true;
            Debug.Log("exit but wrong tag");
        }
    }


}

But it doesn’t seems to display the dialog and show to me the following error:

“NullReferenceException: Object reference not set to an instance of an object
DialogueTrigger.Interact (UnityEngine.InputSystem.InputAction+CallbackContext context) (at Assets/Scripts/DialogueSystem/DialogueTrigger.cs:71)
UnityEngine.InputSystem.Utilities.DelegateHelpers.InvokeCallbacksSafe[TValue] (UnityEngine.InputSystem.Utilities.CallbackArray1[System.Action1[TValue]]& callbacks, TValue argument, System.String callbackName, System.Object context) (at Library/PackageCache/com.unity.inputsystem@1.4.3/InputSystem/Utilities/DelegateHelpers.cs:46)
UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)”

and

"
NullReferenceException while executing ‘performed’ callbacks of ‘Player/Interact[/Mouse/leftButton,/Keyboard/e]’
UnityEngine.InputSystem.LowLevel.NativeInputRuntime/<>c__DisplayClass7_0:<set_onUpdate>b__0 (UnityEngineInternal.Input.NativeInputUpdateType,UnityEngineInternal.Input.NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate (UnityEngineInternal.Input.NativeInputUpdateType,intptr)"

Which is weird because it seems to be related to the use of the iteract button and it’s doesn’t show when I simply test the Interact() like this :

private void Interact(InputAction.CallbackContext context)
    {
        if (playerInRange)
        {
            Debug.Log("start dialog");
            dialPanel.SetActive(true);                   
        }
    }

The answer is ALWAYS the same… ALWAYS!!

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null ← any other action taken before this step is WASTED TIME
  • Identify why it is null
  • Fix that