1
votes

I've been working on a simple 2D game in unity and it just has three scenes, the start scene, the game scene, and the game over scene. I want to display the score from the game in the game over screen. I created a score manager game object in the game scene that uses the DontDestroyOnLoad() function to carry it over into the game over screen and I gave it access to the score which is managed by the game manager. I've been debugging my code and the score is translated over into the score manager and is maintained when the game over screen loads, but for some reason it won't let me update the score text object. Here is my code:

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

public class ScoreManager : MonoBehaviour {

    public static ScoreManager Instance;

    private GameController gameController;

    private int scoreInstance;

    private Text scoreText;

    // When scene is first loaded
    void Awake() {

        this.InstantiateController();

    }

    // Use this for initialization
    void Start () {

        GameObject gameControllerObject = GameObject.FindWithTag("GameController");

        if (gameControllerObject != null)
        {
            gameController = gameControllerObject.GetComponent<GameController>();
        }

        GameObject scoreTextObject = GameObject.FindWithTag("ScoreText");

        if (scoreTextObject != null)
        {
            scoreText = scoreTextObject.GetComponent<Text>();
        }

        scoreInstance = 0;

        scoreText.text = "";

    }

    // Update is called once per frame
    void Update () {

        scoreInstance = gameController.score;
        Debug.Log("Score: " + scoreInstance.ToString());

        scoreText.text = scoreInstance.ToString();

    }

    private void InstantiateController ()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(this);
        }
        else if (this != Instance)
        {
            Destroy(this.gameObject);
        }
    }
}

So I tried to programmatically gather the "score text" ui component in the start function because I figured I can't just make it public and drag in the text component because the score manager is actually in a different scene than the score text object. I also tried adding this whole bit of code to gather the text component into the update function so that it can do that when the score manager is actually a part of game over screen. Nothing seems to work and I have no idea why. Can anybody please help me with this? Also I keep getting a "NullReferenceException: Object reference not set to an instance of an object" error. Thanks in advance for any help.

1
Last line of the start method and all lines in Update can give a null exception as you do not know if the objects have been initialized, yet you access their properties. Start by debugging your "GetComponents" and see if anything is being usedNahuel Ianni
Thanks! :) I debugged both GetComponents and the error was indeed caused by the same problem that kept the score from updating, using the method @JasonLang suggested fixed my NullReference error as well.Andrew T

1 Answers

1
votes

Unity Start function is only called the first time the script is enabled, i.e. not every time the scene changes for a DontDestroyOnLoad object.

So if you need to wire up some changes after a scene change, you need to either detect the scene change, or have an object that starts in that scene trigger the code you want to run.

Having another object on the new scene trigger things is easy and pretty fool-proof, but there's a builtin function you can add to your other objects:

void OnLevelWasLoaded(int currentLevel)
{
}

This will be called on level changes, and give you the level's number (not name sadly). However, the above is deprecated and they want you to use Unity's SceneManager, so the proper way to set this up is now:

Unity 5 OnLevelWasLoaded?

Start()
{
    SceneManager.sceneLoaded += this.OnLoadCallback;
}

void OnLoadCallback(Scene scene, LoadSceneMode sceneMode)
{
    // you can query the name of the loaded scene here
}