In Unity3D having a singleton class is very useful, whether for “global” state or simply for the convenience of having a static accessor so you don’t have to have lots of: FindObjectOfType(typeof(Builder)) as Builder;
So you code up a C# singleton and then realize that you actually need it to be a MonoBehavior, not just a ScriptableObject – say you want the singleton to run coroutines, or have a transform, or any other MonoBehavior feature. But monobehaviors can’t be initialized with a constructor.
So what you want is a monobehavior pseudo singleton pattern. The unity community wiki has some good info
about the various options but all require boilerplate.
So I wrote a parametrized generic pseudo singleton monobehavior class. I attempted to compile all the best advice out there, so it is threadsafe, has some extra stuff for setting a parent, doesn’t implement an Awake, and initializes lazily.
The key was the C# where keyword, used to constrain the parameterizing type. So in this case both the class is a MonoBehavior and its parameterization type is a MonoBehavior.
usingUnityEngine;usingSystem.Collections;/// <summary>/// MONOBEHAVIOR PSEUDO SINGLETON ABSTRACT CLASS/// usage : best is to be attached to a gameobject but if not that is ok,/// : this will create one on first access/// example : '''public sealed class MyClass : Singleton<MyClass> {'''/// references : http://tinyurl.com/d498g8c/// : http://tinyurl.com/cc73a9h/// : http://unifycommunity.com/wiki/index.php?title=Singleton/// </summary>publicabstractclassSingleton<T>:MonoBehaviourwhereT:MonoBehaviour{privatestaticT_instance=null;/// <summary>/// gets the instance of this Singleton/// use this for all instance calls:/// MyClass.Instance.MyMethod();/// or make your public methods static/// and have them use Instance/// </summary>publicstaticTInstance{get{if(_instance==null){_instance=(T)FindObjectOfType(typeof(T));if(_instance==null){stringgoName=typeof(T).ToString();GameObjectgo=GameObject.Find(goName);if(go==null){go=newGameObject();go.name=goName;}_instance=go.AddComponent<T>();}}return_instance;}}/// <summary>/// for garbage collection/// </summary>publicvirtualvoidOnApplicationQuit(){// release reference on exit_instance=null;}// in your child class you can implement Awake()// and add any initialization code you want such as// DontDestroyOnLoad(go);// if you want this to persist across loads// or if you want to set a parent object with SetParent()/// <summary>/// parent this to another gameobject by string/// call from Awake if you so desire/// </summary>protectedvoidSetParent(stringparentGOName){if(parentGOName!=null){GameObjectparentGO=GameObject.Find(parentGOName);if(parentGO==null){parentGO=newGameObject();parentGO.name=parentGOName;}this.transform.parent=parentGO.transform;}}}