SamRose
SamRose

Reputation: 1

Spawning player only works on first compile. Every subsequent playtest (without recompiling or changing script) fails to work

using Unity 2022.3.8f1

running into an error at work and can't quite find the right google search to fix it. I have a GameManager that is "DontDestroyOnLoad." It has an event listener that recognizes when a scene loads and spawns an instance of the player prefab in the level via Invoke(). Everything works upon the first test after the script is changed, saved, and recompiled. But if i stop the test and play it again (either in editor or in build, same thing happens) the GameManager throws an error that the "object of type GameManager has been destroyed" when attempting to invoke the spawn method. The neat part is that the GameManager object is still in the scene WITH the GameManager script attached to it and then more errors (expected errors) are thrown afterwards, so the GameManager definitely still exists.

There is no duplicate GameManager in the scene. It seems as if the GameManager destroys itself for a single frame only, somehow, and then instantiates itself again, somehow??? I'm just not sure what else to check. I've attempted spawning without invoke/coroutine. I've got small delays in spawning to help garbage collection. And the whole thing works great on that first compile. I even have handlers for unloading the scene but those don't get called when exiting play mode, as far as i know. Any help would be appreciated.

The error that is thrown on subsequent runs is:

MissingReferenceException: The object of type 'GameManager' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object. UnityEngine.MonoBehaviour.Invoke (System.String methodName, System.Single time) (at <10871f9e312b442cb78b9b97db88fdcb>:0) GameManager.OnSceneLoaded (UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode mode) (at Assets/Scripts/GameManager.cs:417) UnityEngine.SceneManagement.SceneManager.Internal_SceneLoaded (UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode mode) (at <10871f9e312b442cb78b9b97db88fdcb>:0)

The line of code it's referencing is in this method (Invoke("InvoSpawn", .2f);) `void OnSceneLoaded(Scene scene, LoadSceneMode mode) {

    /*scoreboardText = null;
    timerTextBox = null;
    livesTextField = null;*/
    print("loaded this scene");
Invoke("InvoSpawn", .2f);
    print("still in the onloadedscene method after invoking");
    // StartCoroutine("FindObjects");
    //making sure we're not on the start scene
    if (scene.name != "Start")
    {
        print("this scene is not the start scene");
        //check to see if its the end scene
        if (scene.name == "EndScene")
        {
            //print("Got to the endscene call");
            HandleEndScreenScore();
        }
        else //otherwise, continue on spawning the player and such
        {
            /*scoreboardText = GameObject.Find("ScoreTextBox").GetComponent<TMP_Text>();
            timerTextBox = GameObject.Find("TimeTextBox").GetComponent<TMP_Text>();
            livesTextField = GameObject.Find("LivesTextBox").GetComponent<TMP_Text>();
            scoreUponLevelStart = score;*/
            if (!timerRunning) TimerStartStop();
            //SpawnPlayer();
            //Invoke("SpawnPlayer", .1f);
            
        }
        
    }
}`

My DontDestroyOnLoad() is called in the start method. My understanding is that maybe DontDestroyOnLoad causes weird things when exiting play mode, and the gamemanager being referenced is being destroyed when exiting play mode which is not allowing the gamemanager to exist on its own?

help

Tried so much. Tried spawning character without coroutine or invokation. Tried bigger delays to await garbage clean up. Tried deleting the gamemanager in the scene in between play tests. tried moving the invoke method back into the onSceneLoaded section. Tried invoking it after waiting for unloadSceneAsync() tried invoking it prior to that. and probably a couple more.

Upvotes: 0

Views: 50

Answers (2)

Sanat Sadangi
Sanat Sadangi

Reputation: 64

You should check if the game manager is attached to a game object that might get destroyed on runtime.

Upvotes: 1

SamRose
SamRose

Reputation: 1

So far, i found the answer was indeed due to how i handle my scene transitions. i add a listener for when the scene loads, but i never take it away. So i switched from using

SceneManager.sceneLoaded += OnSceneLoaded;

in the awake method to doing:

private void OnEnable()
{
    SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
    SceneManager.sceneLoaded -= OnSceneLoaded;
}

and making checking for instances of the game manager class.

private static GameManager instance;
private void Awake()
{
    if (instance == null)
    {
        instance = this;
        DontDestroyOnLoad(gameObject);
    }
    else
    {
        Destroy(gameObject);
    }
    //SceneManager.sceneLoaded += OnSceneLoaded;
}

Upvotes: 0

Related Questions