NullReferenceException: (null)[SOLVED]

This is the code in my GameController script:

public IEnumerator GameStart()
        {
            StartCoroutine(StageOneEnemyRoutine.StartAttack());
            return null;
        }

Here is the code in my StageOneEnemyRoutine script:

    public static IEnumerator StartAttack()
        {
            float currentTime = Time.time;
          
            while(Time.time <= currentTime + 120.0f)
            {
                if (portalCount < 2)
                {
                    SpawnPortal();
                    return null;
                }
                if (GameController.GameIsOver())
                    break;
                return null;
            }
            return null;
        }

In the IDE there are no errors and everything compiles correctly. However, when I start the game and reach the point where the Coroutine is called I get the NullReferenceException error on the GameController script.

I have both the GameController script and the StageOneEnemyRoutine script as components on my camera object.

Any help?

You’re trying to call the “StageOneEnemyRoutine” class directly, instead of getting a “reference” to the instance of it that exists on your camera, thus the null reference error. You need to do a GetComponent<StageOneEnemyRoutine>(); on your GameController script and store that in a variable on your script to access the StartAttack() method on.

1 Like

Invertex,

I tried that. And still came up with another error. I figured I was doing it wrong.

private StageOneEnemyRoutine enemyRoutine;
enemyRoutine = GetComponent<StageOneEnemyRoutine>();

Then, I try to call it like so:

enemyRoutine.StartAttack();

However, I then get the error:

“Member cannot be accessed with an instance reference; qualify it with a type name instead”

I’m not sure what that means.

It sounds like you made the StageOneEnemyRoutine class static, since static classes cannot be referenced.

1 Like

:frowning: The class is not static. Perhaps it would be helpful for me to post the entire class. I’m fresh out of ideas, been staring at this thing for a full day now.

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

public class StageOneEnemyRoutine : MonoBehaviour
{
    public GameObject enemyPortal;

    private static bool portalInUseTL, portalInUseTR, portalInUseBL, portalInUseBR;

    private Vector3 spawnPosition = Vector3.zero;
    private Vector3 enemySpawnTL = new Vector3(-95.0f, 0.0f, 95.0f);
    private Vector3 enemySpawnTR = new Vector3(95.0f, 0.0f, 95.0f);
    private Vector3 enemySpawnBL = new Vector3(-95.0f, 0.0f, -95.0f);
    private Vector3 enemySpawnBR = new Vector3(95.0f, 0.0f, -95.0f);

    private static bool[] portalsInUse;
    private static List<System.Action> spawnPortals = new List<System.Action>();
    private static int portalCount;
   
    void Awake ()
    {
        portalCount = 0;

        portalInUseTL = false;
        portalInUseTR = false;
        portalInUseBL = false;
        portalInUseBR = false;

        portalsInUse = new bool[4] { portalInUseTL, portalInUseTR, portalInUseBL, portalInUseBR };
        spawnPortals.Add(() => PortalTopLeft());
        spawnPortals.Add(() => PortalTopRight());
        spawnPortals.Add(() => PortalBottomLeft());
        spawnPortals.Add(() => PortalBottomRight());
    }

    void Update ()
    {
       
    }

    public static IEnumerator StartAttack()
    {
        float currentTime = Time.time;
       
        while(Time.time <= currentTime + 120.0f)
        {
            if (portalCount < 2)
            {
                SpawnPortal();
                return null;
            }

            if (GameController.GameIsOver())
                break;

            return null;
        }

        return null;
    }

    private static IEnumerator SpawnPortal()
    {
        int number = Random.Range(1, 4);

        if (portalsInUse[number])
            SpawnPortal();
        else if (!portalsInUse[number])
        {
            yield return new WaitForSeconds(2.0f);
            spawnPortals[number]();
            portalCount++;
        }             
    }

    private void PortalTopLeft()
    {
        Instantiate(enemyPortal, enemySpawnTL, enemyPortal.transform.rotation);
        portalInUseTL = true;
        PortalBehavior.PortalInUseTL();
    }

    private void PortalTopRight()
    {
        Instantiate(enemyPortal, enemySpawnTR, enemyPortal.transform.rotation);
        portalInUseTR = true;
        PortalBehavior.PortalInUseTR();
    }

    private void PortalBottomLeft()
    {
        Instantiate(enemyPortal, enemySpawnBL, enemyPortal.transform.rotation);
        portalInUseBL = true;
        PortalBehavior.PortalInUseBL();
    }

    private void PortalBottomRight()
    {
        Instantiate(enemyPortal, enemySpawnBR, enemyPortal.transform.rotation);
        portalInUseBR = true;
        PortalBehavior.PortalInUseBR();
    }

    public static void PortalDiedTL()
    {
        portalInUseTL = false;
        portalCount--;
    }

    public static void PortalDiedTR()
    {
        portalInUseTR = false;
        portalCount--;
    }

    public static void PortalDiedBL()
    {
        portalInUseBL = false;
        portalCount--;
    }

    public static void PortalDiedBR()
    {
        portalInUseBR = false;
        portalCount--;
    }

    private bool PortalInUseTL()
    {
        return portalInUseTL;
    }

    private bool PortalInUseTR()
    {
        return portalInUseTR;
    }

    private bool PortalInUseBL()
    {
        return portalInUseBL;
    }

    private bool PortalInUseBR()
    {
        return portalInUseBR;
    }
}

Ok I see, you made the StartAttack() method static, you don’t want to do that, remove that part of it.

1 Like

Line 260 of GameController is:

StartCoroutine(enemyRoutine.StartAttack());

Are you checking beforehand “if(enemyRoutine != null) { //start coroutine code here }” ?

2 Likes

I tried that at one point, but still received the same error. I’d post the entirety of the GameController script, however, it’s pretty large and that’d be a bit of a chore to read through.

However, here is the relevant portion that is attempting to call StageOneEnemyRoutine:

private IEnumerator GameStart()
    { 
        StartCoroutine(enemyRoutine.StartAttack());

        return null;
    }

:frowning:

Just post the GameController script, I only need to look at relevant areas of it anyways it’s not a big deal.

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

public class GameController : MonoBehaviour
{
    public GameObject player, WeaponPowerUp, LifePowerUp, ShieldPowerUp, enemy1, enemy2, enemy3, audioController;
    public float distance;

    private static GameObject sPlayer, sMenu;
    private GameObject inGameHUD, titleMenu, endGameMenu;
  
    private static int playerLives, playerScore, enemyCount, enemy3Count, enemyKillCount;
    private static bool playerIsDead, gameOver;

    private float currentTime, powerUpTime, currentEnemyTime, xPosition, zPosition;
    private bool timeOver, loopBreak, loopGameBreak, gameHasStarted;
    private int currentScore;

    private Vector3 spawnPosition = Vector3.zero;
    private Quaternion spawnRotation = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);

    StageOneEnemyRoutine enemyRoutine;

    void Awake()
    {
        enemyRoutine = GetComponent<StageOneEnemyRoutine>();

        gameHasStarted = false;
        loopBreak = true;
        loopGameBreak = true;

        sMenu = GameObject.Find("MenuObjects").transform.Find("MenuCanvas").gameObject;
        inGameHUD = sMenu.transform.Find("InGameHUD").gameObject;
        titleMenu = sMenu.transform.Find("TitleMenu").gameObject;
        endGameMenu = sMenu.transform.Find("EndGameMenu").gameObject;

        Instantiate(audioController, spawnPosition, spawnRotation);
    }

    void Start()
    {
        AudioController.Bgm1();
    }

    void FixedUpdate()
    {
        if (!gameHasStarted) { }

        if (gameHasStarted)
        {
            CameraControls();

            //Player death and respawn
            if (playerIsDead && playerLives > 0)
            {
                playerIsDead = false;
                StartCoroutine(Respawn());
            }

            //Wait 30 seconds for weapon power up
            if (Time.time >= powerUpTime + 30.0f)
            {
                Instantiate(WeaponPowerUp, spawnPosition, spawnRotation);
                powerUpTime = Time.time;
            }

            //Life Power up spawn after 50 kills
            if (enemyKillCount >= 50 && Time.time >= currentEnemyTime + 10.0f)
            {
                if (GameObject.Find("LifePowerUp(Clone)") == null)
                {
                    Instantiate(LifePowerUp, spawnPosition, spawnRotation);
                    currentEnemyTime = Time.time;
                    ResetEnemyKillCount();
                }
            }

            //Game over due to Player Lives
            if (playerLives <= 0 && loopBreak)
            {
                SetGameOver();
                AudioController.GameOver();              
                loopBreak = false;                
            }

            if (gameOver)
            {
                StartCoroutine(EndTheGame());
            }
        }
    }

    //Camera follows player but stops at border
    private void CameraControls()
    {
        xPosition = sPlayer.transform.position.x;
        zPosition = sPlayer.transform.position.z;

        if (sPlayer.transform.position.x > 57.0f)
            xPosition = 57.0f;
        if (sPlayer.transform.position.x < -57.0f)
            xPosition = -57.0f;
        if (sPlayer.transform.position.z > 80.5f)
            zPosition = 80.5f;
        if (sPlayer.transform.position.z < -80.5f)
            zPosition = -80.5f;

        transform.position = new Vector3(xPosition, sPlayer.transform.position.y + distance, zPosition);
    }

    public static bool PlayerIsActive()
    {
        return sPlayer.activeSelf;
    }

    public static void DecreasePlayerLife()
    {
        playerLives--;

        if (playerLives < 0)
            playerLives = 0;

        LifeDisplay.UpdateLifeDisplay();
    }

    public static void IncreasePlayerLife()
    {
        playerLives++;
        LifeDisplay.UpdateLifeDisplay();
    }

    public static int GetPlayerLife()
    {
        return playerLives;
    }

    public static void PlayerIsDead()
    {
        playerIsDead = true;
        sPlayer.SetActive(false);
    }

    public static void IncreaseEnemyCount()
    {
        enemyCount++;
    }

    public static void DecreaseEnemyCount()
    {
        enemyCount--;
    }

    public static int GetEnemyCount()
    {
        return enemyCount;
    }

    public static void IncreaseEnemy3Count()
    {
        enemy3Count++;
    }

    public static void DecreaseEnemy3Count()
    {
        enemy3Count--;
    }

    private void ResetEnemyCount()
    {
        enemyCount = 0;
    }

    public static void IncreaseEnemyKillCount()
    {
        enemyKillCount++;
    }

    private void ResetEnemyKillCount()
    {
        enemyKillCount = 0;
    }

    public static bool GameIsOver()
    {
        return gameOver;
    }

    public static void SetGameOver()
    {
        gameOver = true;
    }

    private IEnumerator Respawn()
    {
        yield return new WaitForSeconds(2.0f);
        sPlayer.transform.position = spawnPosition;       
        sPlayer.SetActive(true);
        sPlayer.GetComponent<Collider>().enabled = false;

        //Player ship blinks
        float invincibleTime = Time.time;
        while (Time.time <= invincibleTime + 2.0f)
        {
            sPlayer.GetComponent<MeshRenderer>().enabled = !sPlayer.GetComponent<MeshRenderer>().enabled;
            yield return new WaitForSeconds(0.05f);
        }      
        sPlayer.GetComponent<MeshRenderer>().enabled = true;
        sPlayer.GetComponent<Collider>().enabled = true;
    }
  
    public static void IncreasePlayerScore(int points)
    {
        playerScore += points;
        ScoreDisplay.UpdateScoreDisplay();
    }

    public static int GetPlayerScore()
    {
        return playerScore;
    }

    private void StartTheGame()
    {      
        inGameHUD.SetActive(true);
        titleMenu.SetActive(false);
        endGameMenu.SetActive(false);
        GameStart();
    }

    private IEnumerator EndTheGame()
    {        
        yield return new WaitForSeconds(1.5f);
        gameHasStarted = false;
        inGameHUD.gameObject.SetActive(false);
        endGameMenu.gameObject.SetActive(true);     
    }

    private void RetryTheGame()
    {
        SceneManager.LoadScene("MainScene");
    }
  
    private IEnumerator GameStart()
    {      
        sPlayer = player;
        Instantiate(sPlayer, spawnPosition, spawnRotation);
        sPlayer = GameObject.FindWithTag("Player");      

        playerLives = 3;
        playerScore = 0;
        currentScore = 0;
        playerIsDead = false;
        powerUpTime = Time.time;
        currentEnemyTime = Time.time;
        enemyCount = 0;
        enemyKillCount = 0;
        gameOver = false;
        gameHasStarted = true;
        loopBreak = true;

        
        StartCoroutine(enemyRoutine.StartAttack());
        

        return null;
    }  
}

Problem solved!!!

I’m really not sure why, but even though Unity was throwing the NullReferenceException error, it was still executing code in the other script. The ACTUAL problem was that my SpawnPortal() function wasn’t running because I didn’t have it in a StartCoroutine() call.

Had to play with Debug.log to figure it out. I’m still new to Unity and C#.

Thanks for hanging in there Invertex. I much appreciate the help :smile:

1 Like