経緯
Unity上でシングルトンなクラスはあまり多く作ると管理がいろいろ面倒になったりする
シーンに依存するマネージャ( そのシーンでだけ利用するマネージャ )にシングルトンを利用するのも若干非効率なためランタイムに生成し、該当シーンが終了したら削除されるようなマネージャがあると勝手が良いかも???
あくまで一つの案として...
スクリプト
まずはゲームマネージャが管理できるランタイムマネージャのベースクラスの作成
using UnityEngine;
namespace sample
{
/// <summary>
/// シングルトンではない通常のマネージャクラスを作成するためのベースクラス.
/// シーンに依存するマネージャやほかのシーンでは使う場面が全くないものなどに使う.
/// Awakeで必ずGameManagerに登録すること.
/// </summary>
public class RuntimeManagerBase : MonoBehaviour
{
public override string ToString()
{
return GetType().ToString();
}
}
}
GameManagerクラスではDictionaryで管理するためキー値用のstringを取得するためのToString()メソッドをオーバーライドする
続いてGameManagerクラス
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace sample
{
/// <summary>
/// ゲームマネージャ.
/// </summary>
public class GameManager : SingletonMonoBehaviour<GameManager>
{
Dictionary<string, RuntimeManagerBase> managerDic;
protected override void Awake()
{
base.Awake();
managerDic = new Dictionary<string, RuntimeManagerBase>();
DontDestroyOnLoad(this);
SceneManager.activeSceneChanged += ActiveSceneChangeListener;
SceneManager.sceneUnloaded += SceneUnLoadedListener;
}
/// <summary>
/// 登録済みのランタイムマネージャを取得.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetRuntimeManager<T>() where T : class
{
if (!Instance.managerDic.ContainsKey(typeof(T).ToString())) return null;
return Instance.managerDic[typeof(T).ToString()] as T;
}
/// <summary>
/// ランタイムマネージャを登録.
/// </summary>
/// <param name="manager"></param>
public static void RegisterRuntimeManager(
RuntimeManagerBase manager)
{
string typeString = manager.ToString();
if (Instance.managerDic.ContainsKey(typeString)) return;
Instance.managerDic.Add(typeString, manager);
}
// シーンが破棄された故タイミングのリスナ.
static void SceneUnLoadedListener(
Scene scene)
{
// ランタイムマネージャはこのタイミングで破棄.
Instance.managerDic?.Clear();
}
// シーン変更検知,Unityの仕様上beforeには何も入っていない,afterにロードされたシーンがある.
static void ActiveSceneChangeListener(
Scene before,
Scene after)
{
}
}
}
↑スクリプト中にある SingletonMonoBehaviour に関しては UnityでMonoBehaviourのシングルトンを参考に作成しています
今回の実装では簡単にランタイムマネージャの登録処理,ランタイムマネージャの取得処理,シーンの変更時にランタイムマネージャの破棄処理を行っている
ランタイムマネージャの破棄用メソッドを用意していないのはどのみちシーン遷移時に破棄されるため
後はお好みでゲームに必要な処理を追加していけばよいと思う
難点としてはGameManagerに依存しがちになってしまうのでGameManagerが神クラス化してしまわないかなど...
あるいはManagerProviderという名前にしてGameManagerとは別のクラスでやればGameManagerがやるべき仕事と分離できるかも?