Search Unity

Question Should I just eat this NullReferenceException after disabling controller?

Discussion in 'Scripting' started by GrayedFox, Sep 28, 2020.

  1. GrayedFox

    GrayedFox

    Joined:
    Jan 28, 2014
    Posts:
    70
    Hi all, getting back into Unity development after a long hiatus. Using LTS 2019.4 on Win 10.

    This code errors from the 2nd update call onwards with: "NullReferenceError: Object reference not set to an instance of an object." (at line 20).

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.Diagnostics;
    4. using UnityEngine;
    5. using Debug = UnityEngine.Debug;
    6.  
    7. public class GamePauseController : MonoBehaviour
    8. {
    9.     public CharacterController player;
    10.  
    11.     public CharacterController[] enemies;
    12.  
    13.     private bool isPaused = true;
    14.  
    15.     void Update() {
    16.      
    17.         isPaused = !(player.isCasting || player.isMoving);
    18.      
    19.         foreach (var enemy in enemies) {
    20.             var enemyController = enemy.gameObject.GetComponent<EnemyController>();
    21.             Debug.Log("enemyController: " + enemyController);
    22.             if (enemyController)
    23.             {
    24.                 enemyController.enabled = !isPaused;
    25.             }
    26.         }
    27.     }
    28. }
    I think the problem is that after disabling the enemy controller script, the editor considers the instance to be destroyed (or at least it's not being returned by the GetComponent<> generic). Based on the log, it is clear that the first Update doesn't error (it's only on consecutive calls).

    The code actually works as expected (all enemies are frozen so long as the player is not casting or moving), but the editor keeps throwing this same null reference error. As soon as the player starts moving the enemyController is enabled again and the game goes on - I'm wondering what I should do here?

    Am I missing a simple conditional that I should be checking before getting the component? Is it safe to just handle that error and eat it (i.e. suppress it)?
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    Line 20 is
    foreach (var enemy in enemies) {
    . Does that line up with the actual source code?

    If you're getting a NullReferenceException there I would assume the
    enemies
    array is the thing that's null. Maybe you have an extra copy of this script floating around in the scene?

    GetComponent works fine on disabled Components, so that's not the problem. Debug and figure out exactly what is null. If GetComponent is returning null, there simply is not a component of that type on a particular object. If would add a try/catch just for debugging purposes: in the catch block, do a Debug.Log("null is here", enemy);. You will be able to click that log message in the unity console and be taken to the exact GameObject that has the problem.
     
  3. GrayedFox

    GrayedFox

    Joined:
    Jan 28, 2014
    Posts:
    70
    My apologies PraetorBlue, line 20 is actually the first line within the foreach block - I just accidentally wrapped the code block with an extra space at the top. Have updated OP. Thank you for the fast response
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    One or more of your enemy GameObjects is either null or doesn't have that component. Figure out which one it is and why.
     
    GrayedFox likes this.
  5. GrayedFox

    GrayedFox

    Joined:
    Jan 28, 2014
    Posts:
    70
    Siggggggh. Sheesh. Turns out the game pause controller enemy size was set to 2 for some ungodly reason (there is only a single enemy in the scene).

    Thanks for pointing out the obvious - sometimes that's what it takes :confused:

    Prototyping. Yay.
     
    Last edited: Sep 28, 2020
    PraetorBlue likes this.
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    GetComponent<> only returns active and enabled components, so if it's disabled that's why this comes out to null. If this code not running on objects with that component disabled is okay, then it's okay to just do a null check.

    However, if the line throwing the exception is the first line in the foreach loop, that wouldn't be the reason for a NullReferenceException. GetComponent would return null, but that's fine; it wouldn't be until enemyController.enabled that you would have an issue (and not even then, since that's inside that if statement).

    Therefore, it must be that your "enemy" variable itself is null. Look at this object in the inspector and see what's in the array; bet you a dollar it's an empty slot, and I'm pretty sure it's empty before you even start the app. It's not this:
    Because a destroyed object would result in this:

    MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.

    ....Not a NullReferenceException.

    If you don't see an empty slot, you most likely have another copy of this script on another object somewhere, and that's the one throwing the exception.
     
    GrayedFox likes this.
  7. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    I don't think this is true... It's true for GameObject.Find and Object.FindObjectOfType, but it's not true for GetComponent.
     
  8. GrayedFox

    GrayedFox

    Joined:
    Jan 28, 2014
    Posts:
    70
    Yes @StarManta you hit the nail on the head, I'd added and then removed another enemy sprite while testing and forgotten to reduce the enemies size to 1 after deleting the extra enemy. Tedious.