Need Help with Text Based Game Error

Hi all!
This is my first time trying to create a full, completed game with Unity. I’ve been following this tutorial on YT for creating a text-based game. I’m currently on the 2nd part, where we are creating items and a way for the system to recognize/store items. I created multiple scripts, and have been testing the game each time to make sure it runs properly. However I’ve finally received a glitch where the starting text (that loads when the starting room is loaded) is simply not displayed in the text area, and an error message that reads the following:

NullReferenceException: Object reference not set to an instance of an object
GameController.PrepareObjectsToTakeorExamine (Room currentRoom) (at Assets/Scripts/GameController.cs:79)
GameController.UnpackRoom () (at Assets/Scripts/GameController.cs:61)
GameController.DisplayRoomText () (at Assets/Scripts/GameController.cs:49)
GameController.Start () (at Assets/Scripts/GameController.cs:32)

Based on my professional level Google searches, I’m fairly certain that this means there’s an problem with the Game Controller object in the inspector. What confuses me even more however is that the game still runs–I can type the command to go into the next room, which then loads fine. I’ve attached the “GameController” script below, as well as the “Room” scriptable object script.

(Apologies for the notes, they’re what I’m using to keep track of everything that I’m doing!)

“Game Controller” Script:

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

//This last line is what allows the script to call upon functions in the Unity UI stuff

public class GameController : MonoBehaviour
{
    public Text displayText;
    public InputAction[] inputActions;
    //this is what will show all the text on the screen
    [HideInInspector] public RoomNavigation roomNavigation;
    [HideInInspector] public List<string> interactionDescriptionsInRoom = new List<string>();
    //this is the string of interactable objects (items, exits, etc) the player can interact with
    //this will fill up depending on which room is called upon
    [HideInInspector] public InteractableItems interactableItems;
    List<string> actionLog = new List<string>();
    //This list is what creates the action log, the ever-growing list of actions the player has taken.
    //It is helpful to be a list bc we dont know how many actions a player can take
   

    void Awake()
    {
        roomNavigation = GetComponent<RoomNavigation> ();
        interactableItems = GetComponent<InteractableItems>();
    }

    void Start()
        //This calls upon all the inserted functions every frame I think?
    {
        DisplayRoomText();
        DisplayLoggedText();

    }
    public void DisplayLoggedText()
        //This will display everything within the action log
    {
   
        string logAsText = string.Join("\n", actionLog.ToArray());
        //this function takes the individual strings of actions and displays them as one combined string using the Array function
        displayText.text = logAsText;
        //this actually displays the text within the displayText function above!
    }

    public void DisplayRoomText()
    {
        ClearCollectionsForNewRoom();
        UnpackRoom();

        string joinedInteractionDescriptions = string.Join("\n", interactionDescriptionsInRoom.ToArray());
        //converts the list of interaction exits, joins it into a string where everything is seperated into one line
        string combinedText = roomNavigation.currentRoom.description + "\n" + joinedInteractionDescriptions;

        LogStringWithReturn(combinedText);
    }

    void UnpackRoom()
    {
        roomNavigation.UnpackExitsInRoom ();
        PrepareObjectsToTakeorExamine (roomNavigation.currentRoom);

    }

    private void PrepareObjectsToTakeorExamine(Room currentRoom)
    {
        for (int i = 0; i < currentRoom.interactableObjectsInRoom.Length; i++)
        {
            string descriptionNotInInventory = interactableItems.GetObjectNotInInventory(currentRoom, i);
            //if the function succeeds and finds an item not in the inventory, it will store it in the string
            if (descriptionNotInInventory !=null)
            {
                interactionDescriptionsInRoom.Add(descriptionNotInInventory);
            }
            InteractableObjects interactableInRoom = currentRoom.interactableObjectsInRoom[i];
            for (int j = 0; j <interactableInRoom.interactions.Length; j++)
            {
                InterAction interaction = interactableInRoom.interactions[j];
                if (interaction.inputAction.keyword == "examine")
                {
                    interactableItems.examineDictionary.Add(interactableInRoom.noun, interaction.textResponse);
                    //if you pass skull to the dic, you will get back interaction.text response
                    //we pass in the noun to the dictionary, it will check to see if it has a response, then give it back
                    //Here we unpack everything in the room, then unpack them into the dictionary
                }

            }

        }

    }

    public string TestVerbDictionarywithNoun(Dictionary<string, string>verbDictionary, string verb, string noun)
    {
        if (verbDictionary.ContainsKey(noun))
            //is it in the "take" dictionary?
        {
            return verbDictionary[noun];
                //if so, we return the value tied to the called noun
        }
        return "You can't " + verb + " " + noun;
        //if there's an error, it will spit this line back at the player
    }


    void ClearCollectionsForNewRoom()
    {
        interactionDescriptionsInRoom.Clear();
        roomNavigation.ClearExits();
        interactableItems.ClearCollections();

    }

    public void LogStringWithReturn(string stringToAdd)
    //This function is called upon whenver a new string needs to be added aka whenever the player
    //takes an action
    {
        actionLog.Add(stringToAdd + "\n");
            //A function of the List class that allows us to add things-- the slash n essentially types in a line break to the log
    }
    // Update is called once per frame
    void Update()
    {
       
    }
}

“Room” Script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "TextAdventure/Room")]
public class Room : ScriptableObject
{
    [TextArea]
    public string description;
    public string roomName;
    public Exit[] exits;
    public InteractableObjects[] interactableObjectsInRoom;

}

Please help!

“interaction” is your problem. Could be interaction itself, inputAction, or even keyword.

Error is caused by having a null variable, make some Debugs to find out what if you’re struggling.

Could you help explain what you mean? I know that line 79 is the issue (in fact deleting it runs the game fine, albeit without the ability to “examine”). What are some ways I can figure out which part of that line is coming up a “null” variable?

You can use the following to print out anything to the console, it can be useful for tracking down exactly these kinds of issues.

Debug.Log("my thing");

In your case, try something like:

Debug.Log($"Null Interaction? {interaction == null}");
Debug.Log($"Null inputAction? {interaction.inputAction == null}");
Debug.Log($"Null keyword? {interaction.inputAction.keyword == null}");

The error is basically saying “you are trying to access something that doesn’t exist!”

Hmm okay, thank you!
I copied/pasted the debug.log lines right underneath line 79, saving and running the script in Unity gives me the same error message alongside 3 separate console messages that reads:
“Null keyword? False”

I’m sorry if it’s obvious, but what does this tell me? I understand that Unity is saying that the objects don’t exist–but I’m not sure what that means since the game has been running fine up to this point.

What do the other 2 debugs say? Although I can probably derive that they’d both also say false, which would make this a little mystery.

Haha yes they both came out false. Would it help for me to show my “InterAction” and “InteractableObjects” scripts (they are very small). Since the problem line is deriving from InterAction maybe it’s something there?

Yeah go ahead.

Is this definitely the error line:

if (interaction.inputAction.keyword == "examine")

Oh also, remember, since you’re in a for loop you’ll likely have those debugs printed multiple times, make sure you’re looking at the right ones!

Here is the InterAction script:

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

[System.Serializable]
public class InterAction
{
    public InputAction inputAction;
    [TextArea]
    public string textResponse;
}

And the Interactable Objects script:

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

[CreateAssetMenu (menuName = "TextAdventure/Interactable Object")]
public class InteractableObjects : ScriptableObject
{
    public string noun = "name";
    [TextArea]
    public string description = "Description in room";
    public InterAction[] interactions;

}

Could the problem lie with the “examine” keyword? I’m not sure how that could be a problem (especially since I know it’s a scriptable object I have). Also thank you so much for helping! I’ve been banging my head against the wall for a day now haha.

“examine” as a string is not a ScriptableObject, and also isn’t null, it can’t be that.

Try this maybe?

if (interaction == null)
{
    Debug.Log("Interaction null");
}
else if (interaction.inputAction == null)
{
    Debug.Log("inputAction null");
}

Do either of those get printed?

I copied/pasted those lines right underneath the other debug lines, what printed out was the same 3 logs from before.
“Null Interaction? False”
“Null inputAction? False”
“Null keyword? False”

Also sorry what I meant to say was that I have created a scriptable object called “examine”–it’s one of the input actions that the player can use. (This probably shows how little I know still…)
What the debug log is saying, is that those 3 objects AREN’T showing up null, and do therefore exist right?

Yeah exactly but something must be null or the error won’t have been thrown.

You need to make sure that every debug says false for all 3. If any of them say True then that’s where your issue lies.

Hmm am I supposed to be seeing more than 3 debugs? Those 3 are the only ones that pop up in the console.
Going out a little bit, should I be running a debug log for line 78?
InterAction interaction = interactableInRoom.interactions[j];

Because other than that line, I really have no clue where to go from here, especially since all 3 of the other objects aren’t coming up null. Could it be a problem with the “if” loop?

You should be getting 3 debugs for each interactable in the room.
Speaking of which, what is the value of interactableInRoom.interactions.Length?

It can’t be that line since Unity says line 79.

" if " loop?

It’s not possible that all 3 variables on that line aren’t null, you wouldn’t get this error if that was the case. My best and most educated guess is that you are looping multiple times without realising, check for debugs before the error occurs, assuming that the debugs are before the problem line, make absolutely 100,000,000% sure that you checked there. Could you send a log of the console with the debugs in place?