1

I have a really simple question, where I can't understand what I am missing. I am getting error:

NullReferenceException: Object reference not set to an instance of an object test.Update () (at Assets/Scripts/test.cs:13)

So, I have one class "DissableInput", where there is a simple trigger that changes whenever it triggered by another object. It returns true/false, whenever it changes.

Another class has is named "test", which basically should print out when it's true/false depending on trigger input.

//Test Class

public bool touchedCollision;

// Update is called once per frame
void Update()
{
    if (this.GetComponent<DissableInput>().touchedCollision)
    {
        Debug.Log("IN COLL");
    }
    if(!this.GetComponent<DissableInput>().touchedCollision)
    {
        Debug.Log("NOT IN COLL");
    }
}

// DisableInput Class

public bool touchedCollision;

void OnTriggerEnter (Collider other)
{
    Debug.Log("In Triger");
    touchedCollision = true;
}

public void OnTriggerExit(Collider other)
{
    Debug.Log("Out Triger");
    touchedCollision = false;
}

I am expecting that true/false will go into the test class, but instead it gives NullReferenceException error.

Mordekajus
  • 11
  • 3
  • Did you ever heard of static variables? – Nikola G. May 04 '19 at 21:41
  • 1
    Are these scripts attached to different objects? And Nikola: static is not the right solution. – Draco18s no longer trusts SE May 04 '19 at 22:05
  • 1
    Static is not helping and yes, these two different scripts are attached to two different objects. – Mordekajus May 04 '19 at 23:01
  • @Draco18s I don't know how its not right, the answer below does exactly what the static does. But hey! I'd like to see your answer below as well. – Nikola G. May 05 '19 at 09:10
  • @NikolaG. It *works* because it makes the value a property of the *class* rather than a property of the *class instance.* The reason this is not good practice is because now the asker will come back saying, "I did this, then when I tried to make two, they both trigger instead of just the one!" – Draco18s no longer trusts SE May 05 '19 at 15:55
  • @Draco18s True, true.. but he never mention more objects. – Nikola G. May 05 '19 at 16:07
  • 1
    @NikolaG. Always assume that objects are instanced in a non-singleton way unless shown evidence to the contrary. Therefor `static` keyword is only to be used when the value is *actually* a proper static value. General rule of thumb: ["does it make sense to call this, even *if no Obj has been constructed* yet?"](https://stackoverflow.com/a/2671636/1663383) This use-case fails that test. – Draco18s no longer trusts SE May 05 '19 at 16:12
  • @Draco18s I know what your saying, I wasn't assuming. Thank you for the reference. – Nikola G. May 05 '19 at 16:19

2 Answers2

0

This part this.GetComponent<DisableInput>().touchedCollision will try to get a component of the specified type, in this case your "DisableInput" class, in the same gameObject that its attached. If you wish to have the DisableInputClass script in another gameObject you need to reference in some other way.

Using a public variable would look like that

//TestClass

public DisableInput disableInput;

// Update is called once per frame
void Update()
{
    if (disableInput.touchedCollision)
    {
        Debug.Log("IN COLL");
    }
    else //you don`t need to specify the condition again, you can do it with and else
    {
        Debug.Log("NOT IN COLL");
    }
}

you can look how GetComponent works here

An alternative is also to use FindObjectOfType<DisableInput>() //TestClass

  private DisableInput disableInput;

void Awake(){
  disableInput = FindObjectOfType<DisableInput>(); 
// you only need to get the 
//class refence one time, no need for it to be in the update, 
//it gains a lot of performance
}

    // Update is called once per frame
    void Update()
    {
        if (disableInput.touchedCollision)
        {
            Debug.Log("IN COLL");
        }
        else //you don`t need to specify the condition again, you can do it with and else
        {
            Debug.Log("NOT IN COLL");
        }
    }

More about FindObjectOfType here, but to use this you must understand that it will return the first object that he finds that has DisableInput attached to it. If you have multiple gameObjects with DisableInput you can`t be sure which one it will get.

Daruden
  • 149
  • 7
  • Felipe, the first example gives the same result: nullRefferenceException, but the seconds works just fine. Thanks for giving an alternative! – Mordekajus May 05 '19 at 00:24
  • You need to reference it in the inspector for it to work. Glad it helped, consider marking the answer as useful if you don`t mind. – Daruden May 05 '19 at 00:27
  • I don't mind voting up, but I just joined and I think I am not able to vote up. Once I earn the privilege to vote, I will definitely do it. Sorry for that and thanks again. – Mordekajus May 05 '19 at 01:02
  • This answer will still only work if there is a single instance of `DisableInput`, which may be fine, but there are very common situations where that won't be true (for example, multiplayer games, or games with AI controlled units). – Draco18s no longer trusts SE May 05 '19 at 16:00
0

Your scripts are on different objects, therefor this.GetComponent won't work

You want to know when ObjA touches ObjB, so you have one script on ObjA that wants to know and a script on ObjB that is run when the two touch. However, this.GetComponent can only see scripts attached to the same object. So you can't run this code from ObjA (because it doesn't, and can't, know about ObjB!)

I'm going to make two small changes to your scripts:

//Test Class

public bool touchedCollision; //you already had this, but weren't using it

// Update is called once per frame
void Update()
{
    if (touchedCollision)
    {
        Debug.Log("IN COLL");
    }
    if(!touchedCollision) //can be changed to just `else`
    {
        Debug.Log("NOT IN COLL");
    }
}

// DisableInput Class

//removed touchedCollision from here

void OnTriggerEnter (Collider other)
{
    Debug.Log("In Triger");
    other.GetComponent<TestClass>().touchedCollision = true;
}

public void OnTriggerExit(Collider other)
{
    Debug.Log("Out Triger");
    other.GetComponent<TestClass>().touchedCollision = false;
}

This works because it is assumes that:

  • You have more than one DisableInput instance for each volume that you wish to disable input
  • You may have more than one TestClass (or whatever you're going to call it) instance (for example, multiplayer or AI controlled objects).
  • The DisableInput class finds the TestClass of the object that caused the physics event and changes its value.

Addendum:

You should check for nulls. This is the simplest way (glory be to C# 6!)

other.GetComponent<TestClass>()?.touchedCollision = ...

Using a null conditional operator.

Community
  • 1
  • 1