[Unity]Generic Based Singleton for MonoBehaviours完全版(?)

シーン内でいろいろ共有したい!(たとえばアイコンとかのリソース)
シーンを跨いで処理させたい!(たとえばBGMの再生とか)

そんなときに役立つデザインパターンにSingletonというものがあります。
staticメンバーにインスタンスを保持しておいて使いまわそうっていうアレで。
Unityで実装できるSingletonは、
http://wiki.unity3d.com/index.php?title=Singleton
こちらにまとまっていたりします。
Unify Community Wiki便利!

そこで、私が使おうと思ったのが
Generic Based Singleton for MonoBehaviours
にあるMonoSingleton<T>なのですが、動作を検証してみるといろいろ癖があって思わぬバグを招きそうでした。

ってことで、シーンにあらかじめ置いておこうと、間違って複数置いておこうと、
MonoSingleton<T>を継承したスクリプトをScript Execution Orderで呼び出し順を敢えて遅らせようと、
しっかり初期化が呼ばれるようにしてみました
ついでに終了時の呼び出しにも対応!

using UnityEngine;

public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
	static T m_Instance = null;

	public static T instance
	{
		get
		{
			if( m_Instance != null )
			{
				return m_Instance;
			}

			System.Type type = typeof(T);

			T instance = GameObject.FindObjectOfType(type) as T;

			if( instance == null )
			{
				string typeName = type.ToString();

				GameObject gameObject = new GameObject( typeName, type );
				instance = gameObject.GetComponent<T>();

				if( instance == null )
				{
					Debug.LogError("Problem during the creation of " + typeName,gameObject );
				}
			}
			else
			{
				Initialize(instance);
			}
			return m_Instance;
		}
	}

	static void Initialize(T instance)
	{
		if( m_Instance == null )
		{
			m_Instance = instance;

			m_Instance.OnInitialize();
		}
		else if( m_Instance != instance )
		{
			DestroyImmediate( instance.gameObject );
		}
	}

	static void Destroyed(T instance)
	{
		if( m_Instance == instance )
		{
			m_Instance.OnFinalize();

			m_Instance = null;
		}
	}

	public virtual void OnInitialize() {}
	public virtual void OnFinalize() {}

	void Awake()
	{
		Initialize( this as T );
	}

	void OnDestroy()
	{
		Destroyed( this as T );
	}

	void OnApplicationQuit()
	{
		Destroyed( this as T );
	}
}

使い方は

using UnityEngine;
using System.Collections;

public class TestSingleton : MonoSingleton<TestSingleton>
{
	public override void OnInitialize()
	{
		Debug.Log ( "TestSingleton#OnInitialize" );
	}

	public override void OnFinalize()
	{
		Debug.Log ( "TestSingleton#OnFinalize" );
	}
}

こんなん作って、使いたいときにTestSingleton.instanceで取得するだけ。

初期時に呼び出されたOnInitialize()内でDontDestroyOnLoad()を設定しておけばシーン跨ぎにもなります。

Unityのアセット販売中!

ステートマシンの状態遷移やパラメータはエディタで編集でき、
ゲームロジックに依存するステートの挙動はスクリプトで記述可能なエディタ拡張。

詳細はこちら

RPGツクールVXやWOLF RPGエディターのオートタイルに準拠したエディタ拡張。

詳細はこちら

オススメ!