the_clau
the_clau

Reputation: 84

How to preserve object references when loading new scene

I am trying to implement a simple racing game in Unity 2021.2 and I have a GameManager Object that holds state across different scenes (i.e. races). To achieve this I use this code in my GameManager:

public static GameManager instance;

private void Awake()
{
    if (instance == null)
    {
        DontDestroyOnLoad(gameObject);
        instance = this;
    } else if (instance != this)
    {
        Destroy(gameObject);
    }
}

This works fine as long as the fields of the GameManager are of primitive types, such as int and string. However, my GameManager also has a field of type RacerData[], where RacerData is a class that I created in a separate script, which holds data associated with a racer, such as the name, score, etc.

Using this approach I ran into the following problem: When I transition from the first race to the second, i.e. when a new scene is loaded, the GameManager keeps the values of all the fields of primitive types, but loses the references to the RacerData objects.

My first attempt to solve this was that I turned my RacerData script into a MonoBehavior. Instead of just instantiating RacerData Objects in GameManager I created a prefab with the RacerData script attached and instantiated GameObjects from this prefab in my GameManager.

GameObject myRacerDataInstance = Instantiate(myRacerDataPrefab, …, …);
DontDestroyOnLoad(myRacerDataInstance);

instead of:

RacerData myRacerData = new RacerData();

This had the desired effect fo keeping the RacerData game objects when loading a new scene, however the references of the GameManager to those game objects is still lost when a new scene is loaded. I then proceeded to write a hacky workaround to reassign the objects in the next scene which, so far, I failed to make work. However, I'm less interested in making this workaround work rather than to understand why the references to the RacerData gameObjects are lost in the first place and what better way there is to keep data across scene loads.

This appears to be a very common use case to me and I can't quite believe that a developer is supposed to rewire the references manually, especially since those could form a much more complex object graph than mine.

So: Is there a way to preserve those references across scenes? Or is DontDestroyOnLoad() not the right mechanism in the first place and in that case: what better option is there to preserve data (including object references) accross scenes?

Upvotes: 0

Views: 1317

Answers (1)

the_clau
the_clau

Reputation: 84

It turns out the problem wasn't quite what I thought it to be: The references weren't set on the GameManager object at the time I tried to access them, i.e. from the Start() method of another game object called RaceManager.

A quick fix to the problem was to simply wait for the references to be recreated like so (in RaceManager):

void Start()
{
    StartCoroutine(WaitForRacers());
}

private IEnumerator WaitForRacers()
{
    while (racers == null)
    {
        yield return new WaitForSeconds(1);
        gameManager = FindObjectOfType<GameManager>();
        racers = gameManager.GetRacers();
    }

    InitializeRace(); // initialization logic that relies on racers to be != null

}

Upvotes: 1

Related Questions