单例系统完善生命周期、支持Dispose

This commit is contained in:
ALEXTANG
2024-05-13 14:09:32 +08:00
parent 682a0bd786
commit f9f9122027
7 changed files with 297 additions and 9 deletions

View File

@@ -1,14 +1,14 @@
using TEngine;
using System.Diagnostics;
namespace GameBase
{
/// <summary>
/// 通用单例
/// 全局对象必须继承于此
/// </summary>
/// <typeparam name="T">泛型T。</typeparam>
public class Singleton<T> where T : new()
/// <typeparam name="T">子类类型。</typeparam>
public abstract class Singleton<T> : ISingleton where T : Singleton<T>, new()
{
private static T _instance;
protected static T _instance = default(T);
public static T Instance
{
@@ -17,11 +17,43 @@ namespace GameBase
if (null == _instance)
{
_instance = new T();
Log.Assert(_instance != null);
_instance.Init();
SingletonSystem.Retain(_instance);
}
return _instance;
}
}
public static bool IsValid => _instance != null;
protected Singleton()
{
#if UNITY_EDITOR
string st = new StackTrace().ToString();
// using const string to compare simply
if (!st.Contains("GameBase.Singleton`1[T].get_Instance"))
{
UnityEngine.Debug.LogError($"请必须通过Instance方法来实例化{typeof(T).FullName}类");
}
#endif
}
protected virtual void Init()
{
}
public virtual void Active()
{
}
public virtual void Release()
{
if (_instance != null)
{
SingletonSystem.Release(_instance);
_instance = null;
}
}
}
}

View File

@@ -0,0 +1,108 @@
using TEngine;
using UnityEngine;
namespace GameBase
{
/// <summary>
/// 全局MonoBehavior必须继承于此
/// </summary>
/// <typeparam name="T">子类类型</typeparam>
public class SingletonBehaviour<T> : MonoBehaviour where T : SingletonBehaviour<T>
{
private static T _instance;
private void Awake()
{
if (CheckInstance())
{
OnLoad();
}
}
private bool CheckInstance()
{
if (this == Instance)
{
return true;
}
Object.Destroy(gameObject);
return false;
}
protected virtual void OnLoad()
{
}
protected virtual void OnDestroy()
{
Release();
}
/// <summary>
/// 判断对象是否有效
/// </summary>
public static bool IsValid
{
get
{
return _instance != null;
}
}
public static T Active()
{
return Instance;
}
public static void Release()
{
if (_instance != null)
{
SingletonSystem.Release(_instance.gameObject);
_instance = null;
}
}
/// <summary>
/// 实例
/// </summary>
public static T Instance
{
get
{
if (_instance == null)
{
System.Type thisType = typeof(T);
string instName = thisType.Name;
GameObject go = SingletonSystem.GetGameObject(instName);
if (go == null)
{
go = GameObject.Find($"/{instName}");
if (go == null)
{
go = new GameObject(instName);
go.transform.position = Vector3.zero;
}
SingletonSystem.Retain(go);
}
if (go != null)
{
_instance = go.GetComponent<T>();
if (_instance == null)
{
_instance = go.AddComponent<T>();
}
}
if(_instance == null)
{
Log.Error($"Can't create SingletonBehaviour<{typeof(T)}>");
}
}
return _instance;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bc365e281d234e61891bf9f922a0897a
timeCreated: 1715574965

View File

@@ -0,0 +1,141 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace GameBase
{
public interface ISingleton
{
/// <summary>
/// 激活接口,通常用于在某个时机手动实例化
/// </summary>
void Active();
/// <summary>
/// 释放接口
/// </summary>
void Release();
}
/// <summary>
/// 框架中的全局对象与Unity场景依赖相关的DontDestroyOnLoad需要统一管理方便重启游戏时清除工作
/// </summary>
public static class SingletonSystem
{
private static List<ISingleton> _singletons;
private static Dictionary<string, GameObject> _gameObjects;
public static void Retain(ISingleton go)
{
if (_singletons == null)
{
_singletons = new List<ISingleton>();
}
_singletons.Add(go);
}
public static void Retain(GameObject go)
{
if (_gameObjects == null)
{
_gameObjects = new Dictionary<string, GameObject>();
}
if (_gameObjects.TryAdd(go.name, go))
{
if (Application.isPlaying)
{
Object.DontDestroyOnLoad(go);
}
}
}
public static void Release(GameObject go)
{
if (_gameObjects != null && _gameObjects.ContainsKey(go.name))
{
_gameObjects.Remove(go.name);
Object.Destroy(go);
}
}
public static void Release(ISingleton go)
{
if (_singletons != null && _singletons.Contains(go))
{
_singletons.Remove(go);
}
}
public static void Release()
{
if (_gameObjects != null)
{
foreach (var item in _gameObjects)
{
Object.Destroy(item.Value);
}
_gameObjects.Clear();
}
if (_singletons != null)
{
for (int i = 0; i < _singletons.Count; ++i)
{
_singletons[i].Release();
}
_singletons.Clear();
}
Resources.UnloadUnusedAssets();
}
public static GameObject GetGameObject(string name)
{
GameObject go = null;
if (_gameObjects != null)
{
_gameObjects.TryGetValue(name, out go);
}
return go;
}
internal static bool ContainsKey(string name)
{
if (_gameObjects != null)
{
return _gameObjects.ContainsKey(name);
}
return false;
}
public static void Restart()
{
if (Camera.main != null)
{
Camera.main.gameObject.SetActive(false);
}
Release();
SceneManager.LoadScene(0);
}
internal static ISingleton GetSingleton(string name)
{
for (int i = 0; i < _singletons.Count; ++i)
{
if (_singletons[i].ToString() == name)
{
return _singletons[i];
}
}
return null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4ad00b596d0743a4b04591fe52087d0f
timeCreated: 1715574577

View File

@@ -19,7 +19,7 @@ public partial class GameApp:Singleton<GameApp>
_hotfixAssembly = (List<Assembly>)objects[0];
Log.Warning("======= 看到此条日志代表你成功运行了热更新代码 =======");
Log.Warning("======= Entrance GameApp =======");
Instance.Init();
Instance.Active();
Instance.Start();
Utility.Unity.AddUpdateListener(Instance.Update);
Utility.Unity.AddFixedUpdateListener(Instance.FixedUpdate);
@@ -60,8 +60,9 @@ public partial class GameApp:Singleton<GameApp>
Utility.Unity.RemoveDestroyListener(Instance.OnDestroy);
Utility.Unity.RemoveOnDrawGizmosListener(Instance.OnDrawGizmos);
Utility.Unity.RemoveOnApplicationPauseListener(Instance.OnApplicationPause);
return;
}
SingletonSystem.Release();
}
private void Start()

View File

@@ -7,7 +7,7 @@ public partial class GameApp
{
private List<ILogicSys> _listLogicMgr;
private void Init()
public override void Active()
{
CodeTypes.Instance.Init(_hotfixAssembly.ToArray());
EventInterfaceHelper.Init();