单例模式是一种设计模式,它确保一个类在整个应用程序中只有一个实例存在,并提供一个全局的访问点来获取这个唯一的实例。
using UnityEngine;
public class GameManager : MonoBehaviour
{
// 1. 提供一个静态的、全局唯一的实例
public static GameManager Instance { get; private set; }
// 2. 在 Awake 中处理实例化的逻辑
private void Awake()
{
// 检查是否已经有实例存在
if (Instance != null && Instance != this)
{
// 如果有,说明这是个重复的实例,销毁自己
Destroy(this.gameObject);
}
else
{
// 如果没有,将自己赋值给这个静态实例
Instance = this;
}
}
// ... 其他游戏管理逻辑 ...
public void StartGame()
{
Debug.Log("游戏开始!");
}
}
泛型(在 C# 中用 <T> 表示)允许你编写一个可以与任何数据类型一起工作的类或方法,就像一个“类型模板”。
using UnityEngine;
/// <summary>
/// 一个支持懒加载(自动创建)的泛型 MonoBehaviour 单例基类。
/// 它会优先寻找场景中已存在的实例,如果找不到,则会自动创建一个。
/// </summary>
/// <typeparam name="T">必须是一个 MonoBehaviour 组件</typeparam>
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
// 使用 lock 对象来处理多线程情况(虽然在 Unity 主线程中不常见,但这是个好习惯)
private static readonly object _lock = new object();
private static T _instance;
public static T Instance
{
get
{
// 在访问实例时加锁,防止多线程问题
lock (_lock)
{
// 如果实例已经存在,直接返回
if (_instance != null)
return _instance;
// 1. 首先,尝试在场景中查找已经存在的实例
// 这可以处理“先访问Instance后执行Awake”的竞争问题
_instance = FindObjectOfType<T>();
// 2. 如果场景中仍然没有找到
if (_instance == null)
{
// 3. 动态创建一个新的 GameObject 并挂载组件
GameObject singletonObject = new GameObject();
_instance = singletonObject.AddComponent<T>();
singletonObject.name = $"{typeof(T).Name} (Singleton)";
// 可选:如果你希望这个单例跨场景存在
// DontDestroyOnLoad(singletonObject);
}
return _instance;
}
}
}
protected virtual void Awake()
{
// 处理场景中已经放置了该单例的情况
if (_instance == null)
{
// 如果静态实例为空,将自己赋值给它
_instance = this as T;
// 可选:如果你希望这个单例跨场景存在
// DontDestroyOnLoad(this.gameObject);
}
else if (_instance != this)
{
// 如果静态实例已存在且不是自己,说明自己是重复的,销毁自己
Debug.LogWarning($"场景中存在重复的单例: {typeof(T).Name},已销毁后来的。");
Destroy(gameObject);
}
}
protected virtual void OnDestroy()
{
if (_instance == this)
{
_instance = null;
}
}
}
评论(0)
暂无评论