123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- /*************************************************************
- * Unity Singleton Class (c) by ClockStone 2011 *
- *
- * Allows to use a script components like a singleton
- *
- * Usage:
- *
- * Derive your script class MyScriptClass from
- * SingletonMonoBehaviour<MyScriptClass>
- *
- * Access the script component using the static function
- * MyScriptClass.Instance
- *
- * use the static function SetSingletonAutoCreate( GameObject )
- * to specify a GameObject - containing the MyScriptClass component -
- * that should be instantiated in case an instance is requested and
- * and no objects exists with the MyScriptClass component.
- *
- * ***********************************************************/
- using System;
- using UnityEngine;
- #pragma warning disable 1591 // undocumented XML code warning
- public class UnitySingleton<T>
- //where T : SingletonMonoBehaviour<T>
- where T : MonoBehaviour
- {
- #if UNITY_FLASH
- static UnityEngine.Object _instance;
- #else
- static T _instance;
-
- #endif
- static internal Type _myType = typeof( T ); // not working for Flash builds. Requires SetSingletonType() for correct Flash support
- static internal GameObject _autoCreatePrefab;
- static private int _GlobalInstanceCount = 0;
- static private bool _awakeSingletonCalled = false;
- static public T GetSingleton( bool throwErrorIfNotFound, bool autoCreate )
- {
- if ( !_instance ) // Unity operator to check if object was destroyed,
- {
- UnityEngine.Object component = null;
- #if UNITY_FLASH
- if( _myType == null )
- {
- Debug.LogError( "Flash builds require SetSingletonType() to be called!" );
- return null;
- }
- #endif
- var components = GameObject.FindObjectsOfType( _myType );
- foreach ( var c in components )
- {
- //var cpt = ( (Component)c ).GetComponent( _myType );
- var singletonCpt = (ISingletonMonoBehaviour)( c );
- if ( singletonCpt.isSingletonObject )
- {
- component = (UnityEngine.Object)singletonCpt;
- break;
- }
- }
- if ( !component )
- {
- if ( autoCreate && _autoCreatePrefab != null )
- {
- GameObject go = (GameObject)GameObject.Instantiate( _autoCreatePrefab );
- go.name = _autoCreatePrefab.name; // removes "(clone)"
- var newComponent = GameObject.FindObjectOfType( _myType );
- if ( !newComponent )
- {
- Debug.LogError( "Auto created object does not have component " + _myType.Name );
- return null;
- }
- }
- else
- {
- if ( throwErrorIfNotFound )
- {
- Debug.LogError( "No singleton component " + _myType.Name + " found in the scene." );
- }
- return null;
- }
- }
- else
- {
- _AwakeSingleton( component as T );
- }
- #if UNITY_FLASH
- _instance = component;
- #else
- _instance = (T) component;
- #endif
- }
- return (T)_instance;
- }
- private UnitySingleton( )
- { }
- #if UNITY_FLASH
- static internal void _Awake( UnityEngine.Object instance )
- #else
- static internal void _Awake( T instance )
- #endif
- {
- _GlobalInstanceCount++;
- if ( _GlobalInstanceCount > 1 )
- {
- Debug.LogError( "More than one instance of SingletonMonoBehaviour " + typeof( T ).Name );
- } else
- _instance = instance;
- _AwakeSingleton( instance as T);
- }
- static internal void _Destroy()
- {
- if ( _GlobalInstanceCount > 0 )
- {
- _GlobalInstanceCount--;
- if ( _GlobalInstanceCount == 0 )
- {
- _awakeSingletonCalled = false;
- _instance = null;
- }
- }
- else
- {
- // can happen if an exception occurred that prevented correct instance counting
- // Debug.LogWarning( "_GlobalInstanceCount < 0" );
- }
- }
- static private void _AwakeSingleton( T instance )
- {
- if ( !_awakeSingletonCalled )
- {
- _awakeSingletonCalled = true;
- instance.SendMessage( "AwakeSingleton", SendMessageOptions.DontRequireReceiver );
- }
- }
- }
- interface ISingletonMonoBehaviour
- {
- bool isSingletonObject { get; }
- }
- /// <summary>
- /// Provides singleton-like access to a unique instance of a MonoBehaviour. <para/>
- /// </summary>
- /// <example>
- /// Derive your own class from SingletonMonoBehaviour. <para/>
- /// <code>
- /// public class MyScriptClass : SingletonMonoBehaviour<MyScriptClass>
- /// {
- /// public MyScriptClass()
- /// {
- /// MyScriptClass.SetSingletonType( typeof( MyScriptClass ) ); // workaround for Flash
- /// }
- /// public void MyFunction() { }
- /// protected override void Awake()
- /// {
- /// base.Awake();
- /// }
- /// void AwakeSingleton()
- /// {
- /// // all initialisation code here. Will get called from Awake() by singleton.
- /// // Can get called before Awake() if an instance is accessed in an Awake() function which
- /// // was called earlier
- /// }
- /// }
- /// </code>
- /// <para/>
- /// access the instance by writing
- /// <code>
- /// MyScriptClass.Instance.MyFunction();
- /// </code>
- /// </example>
- /// <typeparam name="T">Your singleton MonoBehaviour</typeparam>
- /// <remarks>
- /// Makes sure that an instance is available from other Awake() calls even before the singleton's Awake()
- /// was called. ( Requires AwakeSingleton() !)
- /// </remarks>
- public abstract class SingletonMonoBehaviour<T> : MonoBehaviour, ISingletonMonoBehaviour
- //where T : SingletonMonoBehaviour<T>
- where T : MonoBehaviour
- {
- /// <summary>
- /// Gets the singleton instance.
- /// </summary>
- /// <returns>
- /// A reference to the instance if it exists, otherwise <c>null</c>
- /// </returns>
- /// <remarks>
- /// Outputs an error to the debug log if no instance was found.
- /// </remarks>
- static public T Instance
- { get { return UnitySingleton<T>.GetSingleton( true, true ); } }
- /// <summary>
- /// Checks if an instance of this MonoBehaviour exists.
- /// </summary>
- /// <returns>
- /// A reference to the instance if it exists, otherwise <c>null</c>
- /// </returns>
- static public T DoesInstanceExist( )
- {
- return UnitySingleton<T>.GetSingleton( false, false );
- }
- /// <summary>
- /// Activates the singleton instance.
- /// </summary>
- /// <remarks>
- /// Call this function if you set an singleton object inactive before ever accessing the <c>Instance</c>. This is
- /// required because Unity does not (yet) offer a way to find inactive game objects.
- /// </remarks>
- static public void ActivateSingletonInstance() //
- {
- UnitySingleton<T>.GetSingleton( true, true );
- }
- /// <summary>
- /// Sets the object to be instantiated automatically if no instance of the singleton is found.
- /// </summary>
- /// <param name="autoCreatePrefab">The prefab to be instantiated automatically.</param>
- /// <remarks>
- /// Either the game object itself or one of its child objects must contain the singleton component
- /// </remarks>
- static public void SetSingletonAutoCreate( GameObject autoCreatePrefab )
- {
- UnitySingleton<T>._autoCreatePrefab = autoCreatePrefab;
- }
- /// <summary>
- /// Only required for Flash builds. If this function is not called by the class deriving from
- /// SingletonMonoBehaviour in the constructor the singleton can not be found by GetSingleton(...)
- /// </summary>
- /// <param name="type"></param>
- static public void SetSingletonType( Type type )
- {
- UnitySingleton<T>._myType = type;
- }
- protected virtual void Awake() // should be called in derived class
- {
- if ( isSingletonObject )
- {
- #if UNITY_FLASH
- UnitySingleton<T>._Awake( this );
- #else
- UnitySingleton<T>._Awake( this as T );
- #endif
- //Debug.Log( "Awake: " + this.GetType().Name );
- }
- }
- protected virtual void OnDestroy() // should be called in derived class
- {
- if ( isSingletonObject )
- {
- UnitySingleton<T>._Destroy();
- }
- }
- /// <summary>
- /// must return true if this instance of the object is the singleton. Can be used to allow multiple objects of this type
- /// that are "add-ons" to the singleton.
- /// </summary>
- public virtual bool isSingletonObject
- {
- get
- {
- return true;
- }
- }
- }
|