Search Unity

What am I doing wrong? (NullReferenceException)

Discussion in 'Scripting' started by williamsmd90, Jan 12, 2019.

  1. williamsmd90

    williamsmd90

    Joined:
    Sep 3, 2018
    Posts:
    22
    I've been working on Unity's Space Shooter tutorial by adding new elements to the game. I made an array of powerups for one script but wanted to clean it up. I made another project from scratch and separated the PlayerController script into movement, weapon, and powerup scripts. Now, I'm getting an error that I wasn't getting when it was all on one script. Here's the original:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [System.Serializable]
    5. public class Boundary
    6. {
    7.     public float xMin, xMax, zMin, zMax;
    8. }
    9.  
    10. public class PlayerController1 : MonoBehaviour
    11. {
    12.     private Rigidbody rb;
    13.     private AudioSource audioSource;
    14.  
    15.     private float nextFire;
    16.  
    17.     public Boundary boundary;
    18.     public GameObject shot;
    19.  
    20.     public Transform shotSpawn;
    21.     public GameObject[] powerUps;
    22.     public Vector3 spawnValues;
    23.  
    24.     public float speed;
    25.     public float tilt;
    26.     public float fireRate;
    27.     public float timer;
    28.     public float startWait;
    29.     public float spawnWait;
    30.  
    31.     void Start()
    32.     {
    33.         rb = GetComponent<Rigidbody>();
    34.         audioSource = GetComponent<AudioSource>();
    35.  
    36.         StartCoroutine(SpawnPowerups());
    37.     }
    38.  
    39.     private void Update()
    40.     {
    41.         if (Input.GetButton("Fire1") && Time.time > nextFire)
    42.         {
    43.             nextFire = Time.time + fireRate;
    44.  
    45.             Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
    46.             audioSource.Play();
    47.         }
    48.  
    49.         timer -= Time.deltaTime;
    50.  
    51.         if (timer <= 0)
    52.         {
    53.             fireRate = 0.25f;
    54.         }
    55.     }
    56.  
    57.     private void FixedUpdate()
    58.     {
    59.         float moveHorizontal = Input.GetAxis("Horizontal");
    60.         float moveVertical = Input.GetAxis("Vertical");
    61.  
    62.         Vector3 movement = new Vector3(moveHorizontal, 0f, moveVertical);
    63.         rb.velocity = movement * speed;
    64.  
    65.         rb.position = new Vector3
    66.         (
    67.             Mathf.Clamp(rb.position.x, boundary.xMin, boundary.xMax),
    68.             0f,
    69.             Mathf.Clamp(rb.position.z, boundary.zMin, boundary.zMax)
    70.         );
    71.  
    72.         rb.rotation = Quaternion.Euler(0f, 0f, rb.velocity.x * -tilt);
    73.     }
    74.  
    75.     private void OnTriggerEnter(Collider other)
    76.     {
    77.  
    78.         if(other.CompareTag("Boundary"))
    79.         {
    80.             return;
    81.         }
    82.  
    83.         if (powerUps[0])
    84.         {
    85.             timer = 5f;
    86.             Debug.Log(other);
    87.             if (timer > 0f)
    88.             {
    89.                 fireRate = fireRate / 2;
    90.             }
    91.         }
    92.         Destroy(other.gameObject);
    93.     }
    94.  
    95.     IEnumerator SpawnPowerups()
    96.     {
    97.         yield return new WaitForSeconds(startWait);
    98.         while (true)
    99.         {
    100.             GameObject powerUp = powerUps[Random.Range(0, powerUps.Length)];
    101.             Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
    102.             Instantiate(powerUp, spawnPosition, Quaternion.identity);
    103.  
    104.             yield return new WaitForSeconds(spawnWait);
    105.         }
    106.     }
    107. }
    Btw, I was playing around with time because I wanted to learn more about it, but decided Coroutines are a better way to go for what I'm trying to accomplish. Anyway, in this script, the code works the way I want it to. When I collide with the Rapid Fire powerup, I shoot twice as fast. The set of scripts aren't placed on the player, but instead on an Empty Game Object (Spawn Powerups) and the individual powerups (Powerup Manager). When I collide with these, even though there's a reference to the array of powerups and I'm trying to reference the particular powerup I have in the Element slot in the inspector, it still gives me an error:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SpawnPowerups : MonoBehaviour
    5. {
    6.     public GameObject[] powerups;
    7.     public Vector3 spawnValues;
    8.  
    9.     private float delay;
    10.  
    11.     private void Start()
    12.     {
    13.         delay = Random.Range(10, 20);
    14.         StartCoroutine(PowerupSpawn());
    15.     }
    16.  
    17.     public IEnumerator PowerupSpawn()
    18.     {
    19.         Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
    20.         yield return new WaitForSeconds(delay);
    21.  
    22.         while (true)
    23.         {
    24.             GameObject powerup = powerups[Random.Range(0, powerups.Length)];
    25.             Instantiate(powerups[Random.Range(0, powerups.Length)], spawnPosition, Quaternion.identity);
    26.             yield return new WaitForSeconds(delay);
    27.         }
    28.     }
    29. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PowerupManager : MonoBehaviour
    5. {
    6.     SpawnPowerups spawn;
    7.     PlayerWeapon weapon;
    8.  
    9.     private float duration = 5f;
    10.     private bool meshRendererActive;
    11.     private bool spawnColliderActive;
    12.  
    13.     [HideInInspector]
    14.     public bool isInvincible = false;
    15.  
    16.     private void Start()
    17.     {
    18.         meshRendererActive = GetComponentInChildren<MeshRenderer>().enabled;
    19.         spawnColliderActive = GetComponent<Collider>().enabled;
    20.         SpawnPowerups spawn = GetComponent<SpawnPowerups>();
    21.         PlayerWeapon weapon = GetComponent<PlayerWeapon>();
    22.     }
    23.     private void OnTriggerEnter(Collider other)
    24.     {
    25.  
    26.         if (other.CompareTag("Player"))
    27.         {
    28.         meshRendererActive = false;
    29.         spawnColliderActive = false;
    30.  
    31.             if (spawn.powerups[0])
    32.             {
    33.                 StartCoroutine(RapidFire(other));
    34.                 Destroy(gameObject);
    35.             }
    36.  
    37.             else if (spawn.powerups[1])
    38.             {
    39.                 StartCoroutine(Invincible(other));
    40.                 Destroy(gameObject);
    41.             }
    42.         }
    43.     }
    44.  
    45.     IEnumerator RapidFire(Collider player)
    46.     {
    47.         weapon.fireRate /= 2;
    48.         yield return new WaitForSeconds(duration);
    49.         weapon.fireRate *= 2;
    50.     }
    51.  
    52.     IEnumerator Invincible(Collider other)
    53.     {
    54.         isInvincible = true;
    55.         yield return new WaitForSeconds(duration * 2);
    56.         isInvincible = false;
    57.     }
    58. }
    I've considered putting all of this in a single script, but also don't know how to reference child game objects to be disabled and destroyed.
     
  2. williamsmd90

    williamsmd90

    Joined:
    Sep 3, 2018
    Posts:
    22
    P.S. The error is happening on line 31 of the 3rd script.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,727
    spawn is a private in that third script.

    Where is it initialized?
     
  4. williamsmd90

    williamsmd90

    Joined:
    Sep 3, 2018
    Posts:
    22

    I just changed it to public and it still didn't work. I initialized it in Start but changed it to OnTriggerEnter and I'm getting the same error.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,727
    Right before line 31, print its value with:

    Code (csharp):
    1. Debug.Log(spawn);
    If it's null, maybe you inadvertently dragged this script on another GameObject, or something else nulled it after you set it in the inspector.
     
    williamsmd90 likes this.
  6. ibbybn

    ibbybn

    Joined:
    Jan 6, 2017
    Posts:
    193
    Well first thing to find out is if spawn or [0] is null so debug.log that first?
    Also to that child question:
    this gets the first child in the hierarchy and disables it.
    transform.GetChild (0).gameObject.SetActive (false);
     
    williamsmd90 likes this.
  7. williamsmd90

    williamsmd90

    Joined:
    Sep 3, 2018
    Posts:
    22
    It returned null. I checked everything in the inspector, but only the powerup prefabs have that script attached. I don't know what you mean by something else nulled.
     
  8. williamsmd90

    williamsmd90

    Joined:
    Sep 3, 2018
    Posts:
    22
    Debug.Log(spawn) returns null and (spawn.powerups[0]) doesn't return anything. If I can't figure it out with separate scripts, I'll just combine those two.
     
  9. williamsmd90

    williamsmd90

    Joined:
    Sep 3, 2018
    Posts:
    22
    I decided I couldn't figure out why the reference was null, so I just created a GameObject to fix it for me.
    Code (CSharp):
    1. GameObject spawnGameObject = GameObject.FindWithTag("Spawn Manager");
    2.  
    3. spawn = spawnGameObect.GetComponent<SpawnPowerups>();