In my code I need to reference the Player gameObject in many scripts. I am attaching the Player prefab via editor to those many scripts. But I’m thinking, since only 1 Player instance is necessary (and valid) in the scene, that I should make the Player gameObject a singleton or sharedInstance so I can reference it from all of those scripts easily.
I don’t have enough experience with singletons or sharedInstances to be confident that this is a good solution, and can’t think of problems that might arise. It looks like it should work fine. So I’m wondering, if anyone has considerations about this idea - making the Player a singleton or sharedInstance (any difference?) - I would appreciate the help.
Seems totally reasonable. Sometimes I get lazy with things that the entire game needs (like a wind controller or something) and give it some static instance type accessor.
Keep in mind lifetimes, and also know that just because you keep a reference to something, that does NOT prevent Unity from destroying it.
Some possible lifetimes for MonoBehaviours in Unity:
standard : change scenes, objects deleted, lifetime ends
game : marked DontDestroyOnLoad(), but intentionally destroyed at the end of the game (GameManagers)
true singleton: marked DontDestroyOnLoad(), never again recreated (like an advertising interface)
For simplicity, if you really want longer lifetimes, I prefer this style, which means you DO NOT drop random crap into the scenes, you just access it and it comes into being when needed. Far cleaner.
Some super-simple Singleton examples to take and modify:
Simple Unity3D Singleton (no predefined data):
Unity3D Singleton with Prefab used for predefined data:
These are pure-code solutions, do not put anything into any scene, just access it via .Instance!
If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:
public void DestroyThyself()
{
Destroy(gameObject);
Instance = null; // because destroy doesn't happen until end of frame
}
Thank you so much for the comprehensive answer @Kurt-Dekker ! That more than answers my doubts. Thanks for pointing out the important considerations and its correspondent solutions, as well. I feel like I’m much better informed and confident about taking this approach now. Thanks again!
Thank you for the response @SparrowsNest ! Good to know I’m not being unreasonable with this idea. I have started using scriptable objects recently as well, so that video comes in handy. I have a lot to learn on game architecture for sure, and on scriptable objects. Will definitely check it out. Thanks!
The main thing to consider: Is there any chance at all that your game will ever have either a second player or an AI that is similar to the player character?
If not, then there’s basically no reason to avoid a singleton.
If there’s a chance it might, you can still use a singleton, but I’d advise getting access to your player object through other/more relevant ways when they are available. For example, in a collision, get the player object through collision.GetComponent() rather than Player.Instance. That way, when/if you add other players, there will be less code that needs to be changed to accommodate the extra objects.
Thanks for the reply @StarManta ! That is a fair point. There is the possibility of multiplayer but I’m not going for it at first, so I’m keeping the project single player. Multiplayer would be more complex, I’m focused on completing it.
But this got me thinking. If I had a co-op mode, couldn’t I just create a CoopPlayer class, extending Player, and have a singleton instance of CoopPlayer and singleton instance of Player? Would it conflict? I am definitely not experienced enough with singletons, static classes, or object-oriented programming and patterns for that matter, to answer this off the top of my head.
Close - more likely, you’d have the two classes each derive from a common base class, and then each one could have a singleton.
If doing that, I’d probably also have:
public static List<PlayerBase> allPlayers;
and each one adds itself in OnEnable to this list, and removes itself in OnDisable. There are any number of situations where I’d want to iterate through all the Players, and this would facilitate that.
Mind blown. I honestly never even considered this as a simple way to go from single-player where you used singleton players to couch coop… I can immediately see some drawbacks with other duped code, but it might be a cheap and cheerful solution.
Great, I can see that this is a better solution than I suggested already. Will definitely refer back to this idea if I eventually get to work on coop. Thanks @StarManta !