- Home /
Need suggestion to handle references in Singleton.
Hope to be clear on this question. I have several managers as singleton on my game that for the most part manage generic functions like playback of audio or save settings, but I have also one component that control player nad Ui functions for easy access. This is how the main functions to get the player references looks like:
GameObject playerGo;
[HideInInspector]
public PlayerStatus Status;
[HideInInspector]
public PlayerController Controller;
[HideInInspector]
public PlayerWeapons Weapons;
[HideInInspector]
public UIPlayerManager UI;
//Player Status values
public int playerHealth;
public int playerArmor;
//Player Weapons values
public int currentWeapon;
public int[] currentAmmo; //0 is Fists, keep it at 1
public bool[] weaponLock;
//Setup Player
void Awake (){InitManager();}
//Failsafe
void Start (){InitManager();}
//Failsafe to load components
void OnLevelWasLoaded(int level) {InitManager();}
//Setup components
void InitManager () {
if(GameObject.FindWithTag("Player")) {
playerGo = GameObject.FindWithTag("Player");
Status = playerGo.GetComponent();
Controller = playerGo.GetComponent();
Weapons = playerGo.GetComponent();
}
if(GameObject.FindWithTag("UITag")) {
UI = GameObject.FindWithTag("UITag").GetComponent();;
}
}
As you can see the manager get the player references on awake, then it tries also OnLevelWasLoaded as failsafe and on Start too. I did put another failsafe to be sure everything is loaded, autosetting the components to the manager on Start with the following functions:
//Set PlayerStatus to this instance
public void SetStatus (PlayerStatus status) { if(Status == null) Status = status;}
//Set PlayerWeapons to this instance
public void SetWeapons (PlayerWeapons weapons) { if(Weapons == null) Weapons = weapons;}
//Set PlayerController to this instance
public void SetController (PlayerController controller) { if(Controller == null) Controller = controller;}
//Set UIPlayerManager to this instance
public void SetUI (UIPlayerManager ui) { if(UI == null) UI = ui;}
I did all this mess because I had problems changing from one scene to another having the references still in the manager, because the Player beign not a DontDestroyOnLoad would make the manager loose all the references. But now I'm having doubts this is the worst method to use for such things, I would still be able to access the player references this way, because is easy and fast once is all loaded, but on more complex scenes may mess up the priority of loading. I know I can set script loading priority but I would like to hear for alternatives before messing with it.
Answer by whydoidoit · Jun 15, 2013 at 10:36 AM
Well I'd do it in Awake only and make sure that the script execution order for your singleton is very early in the process or make sure that nothing accesses the values until their own Start function. An even better way is to avoid all that GameObject.Find stuff and just assign them in the inspector - always seems much more flexible to me, but that's horses for courses.
The benefit of that is that you can create an Instance property that removes the issues of Awake on other scripts needing access to the singleton's properties (you can also do this by forcibly calling the initialization function to be fair).
static SomeSingleton _instance;
public static SomeSingleton instance
{
get
{
if(_instance == null)
_instance = GameObject.Find("SingletonWellKnownName").GetComponent<SomeSingleton>();
return _instance;
}
}
void Awake()
{
_instance = this;
}
In the end I opted to make sure nothing about the singleton get executed until is everything setted up, so I set up each component from the components themself and then did a check like you suggested, is fast and less insanity inducing, so thank you for the suggestion.