Yet another 'Object reference not set to an instance of an object'

This seems to be a common error newbies keep getting, and I’d like to learn how to avoid this one properly as I’m always getting caught out by it.

I’m not sure what I’m missing to get this error, but I have a method in one script being referenced in another and calls it when needed. I have the script to be referenced (in this case, HutTrigger) as a variable at the top, I have GetComponent in the Start function, and then the method is called under the ControllerDetection function if the Xbox 360 controller is detected. The required game objects have been placed in the boxes the script is attached to, so I’m not sure what I’m missing to cause this error.

PlayerController script:

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

public class PlayerController : MonoBehaviour
{
    public Animator anim;
    public float moveSpeed;
    public float jumpForce;
    public bool jumped;
    public bool attack;
    public float gravityScale;
    public float knockBackForce;
    public float knockBackTime;
    public float invincibilityLength;
    public Renderer playerRenderer;
    public Material textureChange;
    public Material textureDefault;
    public bool allowCombat = false;
    public bool multipleDirections = false;
    public float rotateSpeed;
    public HutTrigger hutTrigger;

    private float jumpDelay;
    private Vector3 moveDirection;
    private Vector3 extraDirections;
    private float knockBackCounter;
    private float invincibilityCounter;
    private CharacterController controller;
    private int xbox360Controller = 0;
    private int ps4Controller = 0;

    void Start()
    {
        Cursor.visible = false;
        controller = GetComponent<CharacterController>();
        hutTrigger = GetComponent<HutTrigger>();
        if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("level 1"))
        {
            allowCombat = true;
            multipleDirections = false;
        }
        else if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("start_area"))
        {
            allowCombat = false;
            multipleDirections = false;
        }
        else if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("hut_interior"))
        {
            allowCombat = false;
            multipleDirections = true;
        }
    }

    void Update()
    {
        if (knockBackCounter <= 0)
        {
            float moveHorizontal = Input.GetAxis("Horizontal");
            moveDirection = new Vector3(moveHorizontal * moveSpeed, moveDirection.y);

            if (moveHorizontal > 0)
            {
                transform.eulerAngles = new Vector3(0, 90);
            }
            else if (moveHorizontal < 0)
            {
                transform.eulerAngles = new Vector3(0, -90);
            }
            if (controller.isGrounded)
            {
                moveDirection.y = -1f;
                //GetKeyDown will require the player to press the button each time they want to jump. GetKey will allow the player to spam the jump button if they keep pressing it down.
                if (Input.GetKeyDown(KeyCode.KeypadPlus) || Input.GetKeyDown("joystick button 1"))
                {
                    moveDirection.y = jumpForce;
                    jumped = true;
                }
                else if (!Input.GetKeyDown(KeyCode.KeypadPlus) || !Input.GetKeyDown("joystick button 1"))
                {
                    jumped = false;
                }
                if (allowCombat)
                {
                    if (Input.GetKey(KeyCode.Space) || Input.GetKey("joystick button 7"))
                    {
                        attack = true;
                        playerRenderer.material = textureChange;
                    }
                    else if (!Input.GetKey(KeyCode.Space) || !Input.GetKey("joystick button 7"))
                    {
                        attack = false;
                        playerRenderer.material = textureDefault;
                    }
                }
                else if (!allowCombat)
                {
                    attack = false;
                    playerRenderer.material = textureDefault;
                }

            }
        }
        else
        {
            knockBackCounter -= Time.deltaTime;
        }

        moveDirection.y = moveDirection.y + (Physics.gravity.y * gravityScale * Time.deltaTime);
        controller.Move(moveDirection * Time.deltaTime);

        anim.SetBool("isGrounded", controller.isGrounded);
        anim.SetFloat("Speed", Mathf.Abs(Input.GetAxis("Horizontal")));
        if (attack)
        {
            anim.SetTrigger("Attack");
        }

    }

    public void ControllerDetection()
    {
        string[] names = Input.GetJoystickNames();
        for (int x = 0; x < names.Length; x++)
        {
            //print(names[x].Length);
            if (names[x].Length == 19)
            {
                //print("PS4 CONTROLLER IS CONNECTED");
                ps4Controller = 1;
                xbox360Controller = 0;
            }
            if (names[x].Length == 33)
            {
                //print("XBOX 360 CONTROLLER IS CONNECTED");
                ps4Controller = 0;
                xbox360Controller = 1;
            }
            if (xbox360Controller == 1)
            {
                hutTrigger.Xbox360Prompts();
            }
            else if (ps4Controller == 1)
            {

            }
            else
            {

            }
        }
    }

    public void Knockback(Vector3 direction)
    {
        knockBackCounter = knockBackTime;

        moveDirection = direction * knockBackForce;
        moveDirection.y = knockBackForce;
    }

    /*public Vector3 GetTravelDirection()
    {
        return moveDirection.normalized;
    }*/
}

HutTrigger script:

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

public class HutTrigger : MonoBehaviour
{
    public static bool hutLoaded;
    public GameObject[] buttonPrompts;
    public bool entranceVicinity;

    private PlayerController playerController;

    void Start()
    {
        playerController = FindObjectOfType<PlayerController>();
    }

    public void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            entranceVicinity = true;
            playerController.ControllerDetection();
            //buttonPrompt1.SetActive (true);
            //Invoke("Hide", 3f);
        }
    }

    void Update()
    {
        if (entranceVicinity)
        {
            if (Input.GetKeyDown("joystick button 2"))
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 2);
                hutLoaded = true;
            }
        }
    }

    public void Hide()
    {
        buttonPrompts[0].SetActive (false);
        buttonPrompts[2].SetActive(false);
    }

    public void Xbox360Prompts()
    {
        buttonPrompts[0].SetActive(true);
        Invoke("Hide", 3f);
    }

    public void PCPrompts()
    {
        buttonPrompts[2].SetActive(true);
        Invoke("Hide", 3f);
    }
}

Can someone help me clear up the confusion? Thanks.

vs

hutTrigger = GetComponent<HutTrigger>();

I’m not sure I understand what are you doing, because your text wasn’t clear on this, but if you run GetComponent<>() and the component is not on the current game object (as I assume), then it will overwrite the hutTrigger with null.

If this is not the case, please post the exact error with line number (if it’s not the same in the code above, please, tell us which line the error in)

I’m not sure what you mean. I thought that’s what GetComponent does - it gets the HutTrigger script and sort of attaches it to that PlayerController script…? Or rather, it allows access to the contents of that script…?

Ohhhh, I think I get it. Correct me if I’m wrong though. So whenever I add a GetComponent and call for a script, I also need to add a public variable GameObject, which will be the object the script is originally attached to?

Just remove the line from code, keep the public HutTrigger hutTrigger; line and just drag and drop the proper game object in the inspector, your code will have access to the component without the GetComponent.

2 Likes

Despite referencing a GameObject with the required script AND having GetComponent at the start, I’m still having the same error come up for another issue. :frowning:

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

public class ExitTrigger : MonoBehaviour
{
    public GameObject[] buttonPrompts;
    public bool exitVicinity;
    public GameObject thePlayer;
    public GameObject entranceObject;

    private int xbox360Controller = 0;
    private int ps4Controller = 0;
    private bool insideHut;
    private EntranceTrigger entranceTrigger;
    //private EntranceTrigger entranceTrigger;

    void Start()
    {
        entranceTrigger = GetComponent<EntranceTrigger>();
        if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("hut_interior"))
        {
            insideHut = true;
            exitVicinity = true;
        }
    }

    public void OnTriggerEnter(Collider other)
    {
        if (insideHut)
        {
            if (other.gameObject.CompareTag("Player"))
            {
                exitVicinity = true;
                ControllerDetection();
                if (exitVicinity && ps4Controller == 1)
                {
                    PS4Prompts();
                }
                else if (exitVicinity && xbox360Controller == 1)
                {
                    Xbox360Prompts();
                }
                else
                {
                    PCPrompts();
                }
            }
        }
    }

    public void OnTriggerExit(Collider other)
    {
        exitVicinity = false;
    }

    public void Update()
    {
        if (exitVicinity)
        {
            if (xbox360Controller == 1)
            {
                if (Input.GetKeyDown("joystick button 2"))
                {
                    SceneManager.LoadScene("start_area");
                }
            }
            else if (ps4Controller == 1)
            {
                if (Input.GetKeyDown("joystick button 0"))
                {
                    SceneManager.LoadScene("start_area");
                }
            }
            else
            {
                if (Input.GetKeyDown(KeyCode.Return))
                {
                    SceneManager.LoadScene("start_area");
                    entranceTrigger.PlayerReload();
                }
            }
        }
    }

    public void Hide()
    {
        buttonPrompts[0].SetActive(false);
        buttonPrompts[1].SetActive(false);
        buttonPrompts[2].SetActive(false);
    }

    public void Xbox360Prompts()
    {
        buttonPrompts[1].SetActive(true);
        Invoke("Hide", 3f);
    }

    public void PS4Prompts()
    {
        buttonPrompts[2].SetActive(true);
        Invoke("Hide", 3f);
    }

    public void PCPrompts()
    {
        buttonPrompts[0].SetActive(true);
        Invoke("Hide", 3f);
    }

    public void ControllerDetection()
    {
        string[] names = Input.GetJoystickNames();
        for (int x = 0; x < names.Length; x++)
        {
            //print(names[x].Length);
            if (names[x].Length == 19)
            {
                //print("PS4 CONTROLLER IS CONNECTED");
                ps4Controller = 1;
                xbox360Controller = 0;
                if (ps4Controller == 1)
                {
                    Debug.Log("PS4 controller detected");
                }
            }
            else if (names[x].Length == 33)
            {
                //print("XBOX 360 CONTROLLER IS CONNECTED");
                ps4Controller = 0;
                xbox360Controller = 1;
                if (xbox360Controller == 1)
                {
                    Debug.Log("Xbox 360 controller detected");
                }
            }
            else
            {
                ps4Controller = 0;
                xbox360Controller = 0;
            }

            if (xbox360Controller == 0 && ps4Controller == 0)
            {
                Debug.Log("No controllers detected");
            }

            /*if (!string.IsNullOrEmpty(names[x]))
            {
                xbox360Controller = 1;
                ps4Controller = 1;
            }

            else if(string.IsNullOrEmpty(names[x]))
            {
                xbox360Controller = 0;
                ps4Controller = 0;
                Debug.Log("Controllers not detected");
            }*/
        }
    }
}

I get the issue on line 81 and I have no idea why.

Well, obviously entranceTrigger is null. Are you sure that

entranceTrigger = GetComponent<EntranceTrigger>();

Actually found anything?

I don’t understand why it hasn’t though. I made a reference to the game object, the script it’s attached to, I’ve placed the object in the Inspector box. Not sure what else I could be missing.

that’s waht @ was trying to explain before. You can put a reference in the inspector box all you want, but as soon as that GetComponent fails, that assignment statement is going to throw-away whatever was in your inspector box and replace it with null.

If you are going to set the reference in the inspector, but then get rid of the GetComponent.

Either that, or you can change the GetComponent code to this:

if (entranceTrigger == null)
{
     entranceTrigger = GetComponent<EntranceTrigger>();
}

That way, if you already assigned the reference in the inspector, than the assignment statement will leave it alone and not change it.

But why would GetComponent fail? I don’t get it at all. :frowning: Pretty much every time I’ve used a GetComponent on Start it works, so what’s different in this case?

You definitely have a EntranceTrigger component on the same object as your ExitTrigger script?

Nnnno, I don’t. I thought that’s what GetComponent did though…? That it gets a component, such as a gameobject with a script so it can access it. Hence the reason for making a reference to a game object and dragging it into the Inspector so it knows what object to access it from?

A GameObject is not a Component. A Component is something that you attach to a GameObject, like a monobehaviour script, Renderer, RigidBody, etc. When you call GetComponent, it only looks for Components that are attached to the same GameObject that you call it from. If you want a Component that’s on a different GameObject then you have to get a reference to that GameObject and then call GetComponent from that reference.

Or you can just assign it in the inspector, like you’re doing now, but in that case just get rid of that GetComponent code.

1 Like

Right, it’s starting to make sense. Thanks. I’ll try experimenting a bit more. :slight_smile:

I take it FindObjectofType will find any component and gameobject on other gameobjects then?

I’m probably just being dumb, but as an experiment, I have my SceneManagement script attached to my ExitTrigger, and that script contains a GameManager component called theGameManager, and then a GetComponent is called on Start. I’ve dropped the GameObject the GameManager script is attached to in the Inspector, but once Play is pressed, it disappears from the box.

What do you mean by that script contains a component?

I’m not even sure anymore. I’m guessing I actually meant a GameManager variable…

But then I’ve just tried the same thing with something else where I’m trying to get the PlayerController from the Player object. The PlayerController is a script, though isn’t a script a component…?

It should be, if it inherits from MonoBehaviour.

Edit: To clarify it further, when you create a new script in Unity, it creates a class definition with the same name. So in PlayerController, you should see line that looks like:

public class PlayerController : MonoBehaviour {

That “: MonoBehaviour” means that PlayerController inherits a class called
MonoBehaviour which is defined in Unity. This class, in turn, inherits from a class called Component which is the class that defines a Unity Component and it’s what Unity uses to interface with Components. So any class that you define that inherits from MonoBehaviour is also a component.