What’s the best way (you know, fastest and with least memory hugs) to keep the GameObject reference after it is destroyed, without copying it? So when it gets recreated (by returning to the scene), the reference is still there (instead of null).
I know if I manually set the reference in the inspector, that’s exactly what happens. But that’s “static”. How could we do something similar, using scripts?
GetInstanceID() does not work. It obviously brings a different ID every time.
DontDestroyOnLoad is not what I’m looking for. I want the objects to be destroyed (and free the memory).
GameObject.namedoes work, but later requires using some kind of hungry GameObject.Find and unique name convention, which are both non-performatic and heavy (using strings).
Keeping a reference to a destroyed object is impossible; it doesn’t exist anymore, after all.
What you can do is store the state of the object before it has been destroyed and then recreate that object on demand. This is called the Memento pattern. You will need a static (with the keyword or GO with DontDestroyOnLoad) object that persists between scenes and a non-MonoBehaviour class that contains all necessary state of the menu so it can be recreated.
I don’t know how you’ve done your menu logic, but in my example it’s handled with an enumeration.
It is also relatively easy to serialize the Memento-object to disk, and then retrieve that on next run. If such behavior is needed.
public enum MenuStates{
Main,
Options
}
//static classes are never unloaded during runtime
public static class MenuMemory{
private Memento previousState = new Memento(/*default values here*/);
public MenuStates RecallMenuState(){
return previousState.menuState;
}
//getters for all data
//alternatively, break data encapsulation and give access to the Memento-object itself
//a sufficient amount of overloads to cater to every need
public void Save(MenuStates currentState){
previousState = new Memento(currentState);
}
//only the memory should know of the Memento
private class Memento{
public MenuStates menuState;
public int menuOption; //0 is the topmost menu choice
public float musicPosition;
//all other kinds of important data
//all the required constructors
}
}
/*****************************/
/*Within the menu logic class*/
/*which extends MonoBehaviour*/
/*****************************/
MenuStates currentState;
void Awake(){
currentState = MenuMemory.RecallMenuState();
//any other data that needs recalling
}
public void EnterGame(){
MenuMemory.Save(currentState);
Application.LoadLevel(1);
}
You can’t keep a reference to an object after it’s destroyed, because the object simply no longer exists. When you recreate it, it will be a new object, not the same one, so the old reference won’t hold.
What you’re describing in the inspector, is different, since whenever the scene is loaded, unity automatically creates all the objects in the scene, and also automatically populates all the references according to what you dragged in the inspector. Behind the scenes, unity creates an object and then sets a reference, it’s not automatic. This behavior is only possible if you have persistent data (data that remains between loading scenes), and use that data to do the creation and population of references. In unity’s case, this persistent data is the .scene file.
The way I’d suggest to do it manually, is a slightly different take on your idea to use GameObject.name. Instead of using GameObject.Find() every time you want to access the object, use a lazy loading reference. Sample code:
public class SomeClass : MonoBehaviour {
private GameObject _obj = null;
private string _objName;
public GameObject Obj {
get {
if (_obj == null) {
_obj = GameObject.Find(_objName);
}
return _obj;
}
set {
_obj = value;
_objName = value.name;
}
}
}
This code will store the name whenever you assign the Obj value programatically, but when you try to access it, it will return the GameObject _obj immediately without using the messy GameObject.Find(). But if at some point the game object you reference is destroyed, _obj will become null, but the name will remain since it’s a string. Now, after you re-create the object, and you try to access Obj, it will see that _obj is null, so it will use GameObject.Find() only once to fetch the reference of the newly created object. From there on, every time you try to access it, it will use _obj and not resort to GameObject.Find(), up until the next time that you destroy the referenced object.