![見出し画像](https://assets.st-note.com/production/uploads/images/130576086/rectangle_large_type_2_5dd85e381bbda72bc2ebd6d15c8ea072.png?width=1200)
【Unity】簡単で使いやすいSingletonクラス
はじめに
今回は私がいつもUnityで使ってるSingletonクラスの作り方を紹介します。関数名などは自由に変更していただいても構いませんが、他の関数名と名前の衝突(重複)を起こしてしまう場合があるのでご注意ください。そして、今回紹介するSingletonクラスはあくまで我流なので、もっと簡単で使いやすい方法があったら申し訳ありません。
Singletonクラス
早速コードを載せておきます。
using System;
using UnityEngine;
[DisallowMultipleComponent]
public abstract class Singleton<T> : MonoBehaviour
where T : Singleton<T>
{
private static T s_instance = default;
protected virtual void Awake()
{
if (s_instance)
{
Destroy(this);
Debug.LogWarning($"{typeof(T)}のインスタンスは既に生成されています");
return;
}
s_instance = this as T;
}
protected virtual void OnDestroy()
{
if (ReferenceEquals(this, s_instance))
s_instance = null;
}
public static void InvokeIfInstanceIsNotNull(Action<T> act)
{
if (s_instance)
act?.Invoke(s_instance);
}
public static TResult InvokeIfInstanceIsNotNull<TResult>(Func<T, TResult> func)
{
if (!s_instance || func is null)
return default;
return func.Invoke(s_instance);
}
}
注意点
今回紹介したSingletonクラスを使う上で注意することが何点かあります。
まず一つ目、Singletonクラスを継承したクラスA、これは1つのオブジェクトにしかアタッチしてはなりません。シングルトンですから、クラスAが複数あっては困るわけです。複数あってもエラーが出ないよう実装はしていますが、警告はでるようにしてます。
二つ目、SingletonクラスにはDisallowMultipleComponentという属性が付いています。この属性が付いたコンポーネントは1つのオブジェクトに同じコンポーネントをアタッチすることが出来なくなってます。シングルトンは1つだけしかあってはならないので、事前策として属性をつけてます。
三つ目、Singletonクラスをアタッチすることはできません。abstractが付いたクラスはそのままインスタンス化できません。なので必ず継承してから継承したコンポーネントをアタッチしなければなりません。
四つ目、継承先でAwake関数またはOnDestroy関数を実装する際、親クラスのAwake関数またはOnDestroy関数は必ず呼び出すこと。これに関しては下のサンプルのTestクラスをご参照ください。
使い方(サンプル)
今回はサンプル用に2つのクラスを用意しました。
1つはSingletonクラスを継承したTestクラス。
もう1つはTestクラスを使うTest2クラスです。
using UnityEngine;
public class Test : Singleton<Test>
{
private int m_int;
protected override void Awake()
{
base.Awake();
/* === SingletonのAwakeを先に呼び出す === */
}
protected override void OnDestroy()
{
/* === SingletonのOnDestroyを後に呼び出す === */
base.OnDestroy();
}
public int GetInt()
{
return m_int;
}
}
using UnityEngine;
public class Test2 : MonoBehaviour
{
private void Start()
{
var test = Test.InvokeIfInstanceIsNotNull(t => t);
var integer = Test.InvokeIfInstanceIsNotNull(t => t.GetInt());
Test.InvokeIfInstanceIsNotNull(t =>
{
/* === なんか処理 === */
});
}
}