3
\$\begingroup\$

I'm creating a space shooter (think Space Invaders or Galaga) where the GameManager persists between scenes but the player and enemies don't. I need to access a boolean value from the player and enemies to define when and how the game should end. The PlayerController script contains a playerDead variable (attached to the Player GameObject) to tell the GameManager if the player has died and a enemiesDead variable to tell if all enemies have died.

Because the GameManager persists but the others don't, it loses the references when a new level is loaded. I tried to have the GameManager find the script references dynamically, to no avail. It always errors with Object reference not set to an instance of an object when a new level is loaded.

I've tried to get them with GameObject.FindGameObjectWithTag() and then using GetComponent<ScriptName>() to get the script and the variable in it. It compiles nicely and everything seems dandy, but then there's still no object reference. Am I just doing it wrong?

So how can I reference a script and get a value from it without even touching the Inspector?

EDIT:

Below is some code (everything else except the essential is scrapped) from the GameManager script, I tried to use Object.FindObjectsOfType() like this:

GameObject player;
GameObject enemies;

void Awake()
    {
        DontDestroyOnLoad (gameObject);
    }

void Start ()
    {
        Reinitialize ();
    }

void Update () 
    {
        if (enemies.GetComponent<EnemyGrid>().enemiesDead == true)
        {
            gameEnd = true;
        }

        if (player.GetComponent<PlayerController>().playerDead == true)
        {
            gameEnd = true;
        }
    }

void Reinitialize()
    {
        player = Object.FindObjectOfType(typeof(PlayerController)) as GameObject;
        enemies = Object.FindObjectOfType (typeof(EnemyGrid)) as GameObject;
    }

But there's still no object reference. My intention was to run the Reinitialize() funtion each time a new scene was loaded, so that way the GameManager would grab the new objects each time.

\$\endgroup\$
4
  • \$\begingroup\$ you may be calling reinitialize before the scene was loaded. implement the method OnLevelWasLoaded() and call reinitialize from inside of it. \$\endgroup\$
    – Alican
    Commented Oct 19, 2014 at 19:54
  • \$\begingroup\$ Nope, it still didn't find an object reference. This is beyond me at this point. Thanks for the continued support though! \$\endgroup\$
    – jonraem
    Commented Oct 19, 2014 at 20:08
  • \$\begingroup\$ can you verify that they do exist in the scene? do they inherit from MonoBehaviour? \$\endgroup\$
    – Alican
    Commented Oct 19, 2014 at 20:14
  • \$\begingroup\$ Yes and yes. My design was to have the Player and the EnemyGrid (in which individual enemy prefabs are instantiated) objects always in each scene from the start and GameManager would grab them when a scene was loaded. \$\endgroup\$
    – jonraem
    Commented Oct 19, 2014 at 20:20

1 Answer 1

1
\$\begingroup\$

Getting null reference exception is normal since they were created in the previous scene and destroyed in the current one. To move them to the next scene, you need to call DontDestroyOnLoad.

Why don't you create your assets after the scene is loaded? GameManager should be responsible for creating player and enemy objects and keep track of the game state. In addition, try to use c# events to communicate with the manager in order to notify events such as EnemyDestroyed or PlayerDied etc. In this way, you don't need to ask both player and enemies whether they are dead at each frame.

\$\endgroup\$
5
  • \$\begingroup\$ Thanks for the advice! Yeah, I thought there might be a more optimal way to approach my problem but I was persistent to get it working "my way". \$\endgroup\$
    – jonraem
    Commented Oct 19, 2014 at 18:42
  • \$\begingroup\$ well, that's your call. it seems like you are trying to move survived enemies to the next level. as a quick fix, just call DontDestroyOnLoad for each of the objects you want to keep for the next scene. GameManager should be fine because none of the objects are going to be destroyed. \$\endgroup\$
    – Alican
    Commented Oct 19, 2014 at 18:49
  • \$\begingroup\$ Actually no. I just wanted to have the GameManager to have DontDestroyOnLoad() and then when a new scene generates it would dynamically grab the references to the newly created Player and EnemyGrid objects. But I think it's a better solution just to have the GameManager create them each time a new scene is loaded. At least that way the references are not lost. \$\endgroup\$
    – jonraem
    Commented Oct 19, 2014 at 19:12
  • \$\begingroup\$ oh, I understand. did you try using GameObject.FindObjectsOfType<ComponentName>()?. I usually put placeholders to the spawn points. during level initialization, I find them using GameObject.Find() and replace with actual assets. \$\endgroup\$
    – Alican
    Commented Oct 19, 2014 at 19:18
  • \$\begingroup\$ I tried it and it didn't work... I'll edit the code to the original answer for debugging. \$\endgroup\$
    – jonraem
    Commented Oct 19, 2014 at 19:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .