Null Reference Exception again?

Hi, all.

New user of Unity here. I should go introduce myself sometime, but want to get to business right now.

I get a null reference exception error at two lines of code:

NullReferenceException: Object reference not set to an instance of an object
timer.Start () (at Assets/timer.cs:17)
-and-
NullReferenceException: Object reference not set to an instance of an object
timer.Update () (at Assets/timer.cs:27)

So here is the situation, along with the code:

I’m writing a very simple maze game with three pregenerated mazes, 3 by 3, 6 by 6, and 9 by 9.

I first created the 9 by 9 maze, put in start and end markers, a collision detector, and a timer, along with a canvas to display the time, in seconds, the player has been in the maze while navigating, and the final time in seconds when the player collides with the end marker. Once that worked, I created the two smaller mazes, and copied the canvas and scripts from the existing maze into the other two mazes.

3 by 3 and 9 by 9 work fine. 6 by 6 produces the error.

Here is my script, in its entirety:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class timer : MonoBehaviour
{
    float myTimer;
    int myTimeri;
    bool timing;
    // Start is called before the first frame update
    void Start()
    {
        myTimer = 0.0f;
        myTimeri = (int)myTimer;
        timing = false;
        GameObject.Find("timerUI").GetComponent<Text>().text = "";
    }

    // Update is called once per frame
    void Update()
    {
        if (timing)
        {
            myTimer = myTimer + Time.deltaTime;
            myTimeri = (int)myTimer;
            GameObject.Find("timerUI").GetComponent<Text>().text = "" + myTimeri;
        }
        if (Input.GetKey("b"))
        {
            SceneManager.LoadScene("Load");
        }
    }

    //detect collision with start or end time markers
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        if (hit.collider.tag == "Start")
        {
            myTimer = 0.0f;
            Destroy(hit.collider.gameObject);
            timing = true;
        }
        if (hit.collider.tag == "End")
        {
            Destroy(hit.collider.gameObject);
            timing = false;
            GameObject.Find("timerUI").GetComponent<Text>().text = "The number of seconds you took to solve the maze was: " + myTimeri + ".  Press the b key to return to the previous screen.";
            //line to be coded to enable button to go back to main screen Button.E;
        }
    }
}

So, the offending lines of code both contain: GameObject.Find(“timerUI”).GetComponent().text. When I look in the inspector, I find that “timerUI” exists in all 3 mazes; timerUI has a property; timerUI and its properties are active in all 3 mazes. Yet it does not work in the 6 by 6 maze.

I know I am missing something, and hope extra eyes can point it out to me.

Thanks.

Please edit your post to use code tags for your code, so that it is easier to read.

In Start() either the call to Find is returning null (no object with the specified name is in the scene), or the GetComponent call is returning null (no Text component attached to the object returned by Find). Add Debug.Log statements to determine which is the case. The same is most likely the case in Update.

1 Like

First, use code tags.

Second, try separating the lines to see which of the two parts is coming up null - the .Find or the .GetComponent.

GameObject timerUI = GameObject.Find("timerUI");
timerUI.GetComponent<Text>().etc etc etc

This will narrow the error down to one of these two possibilities which will illuminate the issue.

Third, realize that you can modify the above code ^ to find the timer UI once, hold onto the reference, and not have to make the slow GameObject.Find call every frame.

Finally, I’m guessing that one of two things is happening: It’s either not finding the “timerUI” object because of a miniscule typo (capitalization, an inadvertent space, etc), or it’s finding a different object named timerUI. (You can test to see if it’s finding a different object using Debug.Log("We found this thing", timerUI); and clicking on the message in the console; it’ll highlight whichever one it found, if any).

At this point, you should be well on your way to the final conclusion, which is that GameObject.Find is not only slow but more importantly unreliable and incredibly easy to break. Here’s an article with more details on why GO.F sucks, and what techniques you can use instead which are more reliable and better performing.

2 Likes

Thank you! I was actually just on my way out of my ‘office’ for the weekend when I received all these replies. The article to which you linked will be a lifesaver in my future I am sure. Going to add it to my reading and do some coding later today.

Fourth: Make sure the canvas is enabled. Which is what the problem turned out to be.

That, and also do not use GO.F which I am now going to rewrite the code not to use.

1 Like