Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Can't seem to figure out why randomly getting a NullReference exception...

Discussion in 'Scripting' started by Caelorum, Apr 5, 2015.

  1. Caelorum

    Caelorum

    Joined:
    Feb 6, 2014
    Posts:
    32
    So I have a script, that searches the game, finds a certain block, and labels it enemy.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Enemy : MonoBehaviour
    5. {
    6.     public static Enemy S; //Create instance of this class
    7.  
    8.     public int             pillarEnemy; //Pillar to change to target cube
    9.     public GameObject   goodPillar; //Target cube
    10.     public GameObject    levelManage; //Access levelmanager gameobject
    11.     public bool            nextLevel; //Check if nextlevel is true
    12.     void Awake()
    13.     {
    14.         InitializeVars(); //Initialize variables
    15.     }
    16.  
    17.     void Start()
    18.     {
    19.         SelectPillar (); //Select which pillar/cube to use
    20.         ColorPillar ();    //Color cube differently
    21.         TagPillar ();    //Tag cube to be enemy
    22.     }
    23.  
    24.  
    25. //==================================================================================\\
    26.  
    27.     void InitializeVars() //Initialize variables
    28.     {
    29.         S = this; //Initialize instance of this class
    30.         levelManage = GameObject.Find ("LevelManager");
    31.         pillarEnemy = levelManage.GetComponent<LevelManager>().curLevel;
    32.     }
    33.  
    34.     void SelectPillar() //Select which pillar/cube to use
    35.     {
    36.         GameObject GO = GameObject.Find("Pillars"+pillarEnemy+"(Clone)"); //Find parent pillar based on pillarEnemy number
    37.         int GOChildNum = GO.transform.childCount;    //Count how many children are in GO
    38.         int randomSpawn = Random.Range (0,GOChildNum); //Choose a cube from the children
    39.         Transform child = GO.transform.Find("Pillar"+randomSpawn+"(Clone)");    //Select cube from children
    40.         goodPillar = child.gameObject;    //Assign cube
    41.     }
    42.  
    43.     void ColorPillar() //Color cube
    44.     {
    45.         Color goodPillarColor; //Create color variable
    46.         goodPillarColor = Color.green;    //Set color to green
    47.         goodPillar.GetComponent<Renderer>().material.color = goodPillarColor; //Change cube color to green
    48.     }
    49.  
    50.     void TagPillar() //Tag cube
    51.     {
    52.         goodPillar.tag = "Enemy"; //Set tag to enemy
    53.     }
    54.  
    55.     void OnEnable() //When this script is re enabled
    56.     {
    57.         if(nextLevel == true) //If nextLevel is true
    58.         {
    59.             Awake ();
    60.             Start ();
    61.         }
    62.     }
    I have another script that disables, then re enables this script if the player wins a round, so thats why the last line is the way it is.

    However, every now and then ( not all the time, just randomly), when the script runs itself, or re enables, I get a NullReferenceException, saying Object reference not set to an instance blah blah blah.

    It sends me to this line
    Code (CSharp):
    1.         goodPillar = child.gameObject;    //Assign cube
    I don't understand. All objects are created before this script is called. And when this script is called again, the objects are untouched, so it shouldnt have a problem finding it's object.
    I also don't understand why this issue is completely random.

    It should find the next pillar in line, check its kids, select a random kid, then assign goodPillar. But it just randomly breaks for no reason at times.

    Here is the exact error i just got after 7 clean repetitions through this script.

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. Enemy.SelectPillar () (at Assets/_Scripts/Enemy.cs:40)
    3. Enemy.Start () (at Assets/_Scripts/Enemy.cs:19)
    4. Enemy.OnEnable () (at Assets/_Scripts/Enemy.cs:60)
    5. UnityEngine.Behaviour:set_enabled(Boolean)
    6. LevelManager:EnemyReset() (at Assets/_Scripts/LevelManager.cs:36)
    7. LevelManager:StartNextLevel() (at Assets/_Scripts/LevelManager.cs:24)
    8. <NextLevel>c__Iterator3:MoveNext() (at Assets/_Scripts/Spear.cs:91)
     
    Last edited: Apr 5, 2015
  2. Caelorum

    Caelorum

    Joined:
    Feb 6, 2014
    Posts:
    32
    Think I might have found my own issue. Wasn't aware that Random.Range for some reason includes the first number, but does not include the last number. Idk why that is, but i'm guessing my script was trying to access a 0th pillar that wasn't there.
     
  3. Galf

    Galf

    Joined:
    Feb 24, 2013
    Posts:
    27
    Good find if that was the case, but you probably don't want to guess about it. Make sure the error is what you predicted, or you'll run into it again later down the line. You could always print out the random spawn index, although in this case, you could limit the output only when you know an error would occur (the child is null). Something like the following:
    Code (CSharp):
    1. if (child == null)
    2. {
    3.   Debug.Log("child is null, spawn was: " + randomSpawn);
    4. }
    You didn't ask about this issue, but I'm concerned with your OnEnable function. Awake and Start are essentially built-in Unity functions, with some specific idiomatic usage. They serve the role of constructors in other languages. Just as you should never call a constructor outside of initialization, you should never be calling Awake or Start on your own here. If you have shared functionality, rip that out to its own method, and then call that in both Awake/Start and OnEnable.