- Home /
When loading the scene, I get missing references
I have bunch of managers, like GameManager, LevelManager, UIManager, etc. All of them declare a public static variable of their class type and call it "instance". Then all of them have this code in their Awake
void Awake
{
if (instance != null)
Destroy(gameObject);
instance = this;
DontDestroyOnLoad (gameObject);
}
Basically they're singletons so that I can reference them easier. When I'm trying to load or reload the level, I get this error: "The object of type 'GameObject' has been destroyed but you are still trying to access it."
All my managers are in DontDestroyOnLoad section of the scene, i.e. the gameobject and the scripts on them are preserved. I don't understand why the hell am I getting this error when I reload the scene and try to access these statics.
Can someone make sense of this?
EDIT: @hexagonius @jackishere @RobAnthem @ExtinctSpecie I think the problem here may be deeper since out of all those managers, only a specific one is throwing that error and i have problem debugging it. here's what's happening:
The loader is instantiating all the managers like so
void Awake ()
{
if (LvlGenerator.instance == null)
Instantiate(lvlGenerator);
if (GameManager.instance == null)
Instantiate(gameManager);
//etc.
}
then GameManager is calling this method upon being instantiated
void SetUpNewScene()
{
SceneManager.LoadScene("Scene1");
LvlGenerator.instance.GenerateLevel();
UIManager.instance.SetUpDeathScreen();
}
here if I omit "SceneManager.LoadScene("Scene1") then the entire thing works fine. It's the loading that screws it.
UIManager for example works fine, and LvlGenerator isn't null either. It goes through and calls GenerateLevel() method. Which looks like this
public void GenerateLevel()
{
transform.position = Vector3.zero; //moves LvlGenerator to 0,0,0 so that we start building from those coordinates
StartCoroutine(GenerateLevelCoroutine());
}
then it starts the coroutine which is quite some code, I'll cut out most part and leave the one that throws the error (which I don't understand).
IEnumerator GenerateLevelCoroutine()
{
int floorTilesRemaining = levelSize;
SpawnFloorTile ();
floorTilesRemaining--;
while(floorTilesRemaining > 0)
{
if (floorTilesList.Count > 0)
{
for (int i = 0; i < floorTilesList.Count; i++)
{
if (transform.position == floorTilesList [i].transform.position)
{
// some code
}
}
SpawnFloorTile ();
floorTilesRemaining--;
}
yield return null;
}
}
THIS line "if (transform.position == floorTilesList [i].transform.position)" is throwing an error mentioned above (The object of type 'GameObject' has been destroyed but you are still trying to access it.).
When I try to debug it, none of the variables there are null or anything. floorTilesList is declared in the same script as the error
public List<GameObject> floorTilesList = new List<GameObject>();
I still don't understand why this is happening : (
The line
Destroy(gameObject);
Destroys the gameObject.
The line
DontDestroyOnLoad (gameObject);
Is attempting to reference the already destroyed object.
I wish people wouldn't use Singletons so much, they are kind of crappy in a lot of ways.
I was sure that as soon as I Destroy the object the code wouldn't continue. As hexagonius pointed out though, I guess that's not the case. The only reason I use Singletons is to easily reference those managers.
Could you please explain why is using Singletons bad?
Because singletons are Unitys convoluted way to handle single-class references. The entire idea behind it bothers me lol. This is how I handle the same situation.
public static class Game$$anonymous$$anager
{
public static SceneHandler sceneHandler
{
get
{
if (_sceneHandler == null)
{
_sceneHandler = GameObject.FindObjectOfType<SceneHandler>();
}
return _sceneHandler;
}
set
{
_sceneHandler = value;
}
}
private static SceneHandler _sceneHandler;
}
I use this same foundation for all my important references, like the player object, saving and loading the actual player class, etc. Plus it packs all your important and constantly referenced classes in a single location. Depending on the game, I sometimes make a second class like this for GUI management, like an RPG where you have a lot of constantly referenced GUI elements. Basically because of this, there is almost NO FindObjectOfType calls in any of my scripts.
Also, if you want singleton to work, it should look like this.
if(instancel)
{
if (instance != this)
{
Destroy(instance);
instance = this;
}
}
else
{
instance = this;
}
DontDestroyOnLoad (gameObject);
Answer by Bigproblem01 · Mar 19, 2017 at 07:38 PM
I looked into this a bit more and there doesn't seem to be an easy explanation of why this is happening. I figure it's something in the coroutine that goes off while the scene is loading, or maybe something doesn't get preserved in the DontDestroyOnLoad. In any case, it doesn't make sense for me to get stuck on this any longer so I just removed all these singletons from DontDestroyOnLoad and when I load/reload a scene, everything gets wiped and it's working.
For educational purposes I'd still be curious to know why this was bugging out, so if anyone will figure it out, please do post here.
Answer by jackishere · Mar 18, 2017 at 11:46 PM
it's because you are destroying the gameobject then assigned the null to the instance
if (instance != null) { Destroy(gameObject); } else { instance = this; DontDestroyOnLoad (gameObject); }
Answer by hexagonius · Mar 18, 2017 at 11:23 PM
because the second time you destroy your reference from the first time but don't return. the next call is the try of assigning the destroyed reference to the variable, which fails. destruction does not stop code execution.
Destruction doesn't stop code execution? Are you sure? I thought I remembered more than one instance where I accidentally was destroying something mid code and the code wouldn't continue. I was sure it'd end right after "Destroy(gameObject)".
So then I don't quite understand what's happening. The object is being destroyed by Destroy(gameObject), and then instance equals what?
Sorry, I don't think I fully understand what's happening and It'd be awesome to grasp that so that I do better next time
$$anonymous$$y architecture is using a Loader which has this code:
public GameObject lvlGenerator;
public GameObject object$$anonymous$$anager;
public GameObject ui$$anonymous$$anager;
public GameObject game$$anonymous$$anager;
//etc.
void Awake ()
{
if (LvlGenerator.instance == null)
Instantiate(lvlGenerator);
if (Object$$anonymous$$anager.instance == null)
Instantiate(object$$anonymous$$anager);
if (UI$$anonymous$$anager.instance == null)
Instantiate(ui$$anonymous$$anager);
if (Game$$anonymous$$anager.instance == null)
Instantiate(game$$anonymous$$anager);
}
then when all those singletons instantiate, they're supposed to remain in the scene. So when I reload, if they happen to be reinstantiated, they should check if the singleton is already present and if it is destroy themselves. At least that's the plan. Is this the right approach in general?
it would be bad if anything besides a return could quit execution. destruction of gameobjects is just a call like any other method call is. one sometimes gets confused by unity and it's gameobject that give the impression you be something different then just classes.
and yes, that was the right way, but you didn't return, that's why it tried to assign itself even though it was already destroyed.
I'd be curious to hear your thoughts regarding the full problem though. I think the one you're talking about isn't the issue hear. If you could read my first post (edited), it shows where the error is exactly. As you'll see, all other singletons work, it's just that coroutine that's going south for some reason
Answer by ExtinctSpecie · Mar 19, 2017 at 12:27 AM
even if the variables are static when you destroy that script the variables get destroyed as well try creating a new script that saves the things you want to save
for example
public class SaveVolume
{
public static int volume { get;set;}
}
but to my understanding i'm not destroying anything. I even copied the code from Unity's tutorial about game manager singleton because I started being paranoid about the way I'm doing it. the code I'm using now is
if(instance == null)
instance = this;
else if(instance != this)
Destroy(gameObject);
DontDestroyOnLoad (gameObject);
and I'm still getting the same error
have you tried removing the Destroy(gameObject) part?
if (instance != null)
{
return;
}
instance = this;
I tried the code you wrote and i'm getting the same result unfortunately
Answer by Doker2030 · Mar 25 at 05:40 PM
I've been stuck for two days on a similar issue. Singletons for data persistance seems not to work in some cases. I used the tutorial at https://learn.unity.com/tutorial/implement-data-persistence-between-scenes# and built on it for my application, but eventually i got "MissingReferenceException: The object of type 'GameObject' 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."