708 字
4 分钟
游戏设计模式01——单例模式
最直白最不绕弯子的理解
单例模式(Singleton)保证某个类在程序运行时只有一个实例,并且任何地方都能方便地访问到它。
为什么游戏开发里很常用
游戏里有一些系统天然就应该只有一个:
- GameManager:管理游戏状态(开始、暂停、结束)
- AudioManager:统一播放音乐和音效
- UIManager:打开和关闭界面
- SaveManager:存档和读档
- InputManager:统一处理输入
以上管理器的共同特点:
- 全局唯一:如果有两个 AudioManager,背景音乐可能会同时播两遍。
- 到处要用:玩家、敌人、UI 都可能要播放音效。
- 生命周期长:通常从游戏启动一直存在到退出。
单例解决的就是“唯一”和“方便访问”这两件事,不用到处拖拽引用,也不用反复调用 FindObjectOfType 去找。
三个核心思想
- 唯一实例:类自己保存“我那唯一的一个实例”。
- 全局访问点:对外提供一个统一入口,通常叫
Instance。 - 防止重复:如果出现第二个实例,要阻止或销毁它。
最简单例写法
using UnityEngine;
public class GameManager : MonoBehaviour{ public static GameManager Instance;
void Awake() { Instance = this; }}使用前提
- 场景里只放一个挂了这个脚本的物体。
- 在其他脚本的
Start里访问,不要在Awake里访问。
未解决的点
- 不防止重复实例:如果有两个,后执行
Awake的那个会覆盖前一个。 - 不跨场景:切换场景后,这个实例会和场景一起被销毁。
Instance是公开字段,其他脚本可以改它。
这种写法只适合单个场景里用的小管理器,或是小型项目使用。
懒汉单例
第一次访问 Instance 时才去寻找或创建实例。
using UnityEngine;
public class GameManager : MonoBehaviour{ private static GameManager _instance;
public static GameManager Instance { get { if (_instance == null) { // 1. 先在场景里找有没有现成的 _instance = FindObjectOfType<GameManager>();
// 2. 场景里没有,就自己创建一个 if (_instance == null) { GameObject go = new GameObject("GameManager"); _instance = go.AddComponent<GameManager>(); } } return _instance; } }
private void Awake() { // 防止场景里出现重复实例 if (_instance != null && _instance != this) { Destroy(gameObject); return; }
_instance = this; DontDestroyOnLoad(gameObject); // 跨场景保留 }
// 测试用方法 public void Hello() { Debug.Log("GameManager 单例被调用"); }}饿汉单例
using UnityEngine;
public class GameManager : MonoBehaviour{ // 全局访问点:外部只能读,不能改 public static GameManager Instance { get; private set; }
private void Awake() { // 已经有实例了,并且不是自己 → 销毁多余的 if (Instance != null && Instance != this) { Destroy(gameObject); return; }
Instance = this; // 场景加载时就登记自己 DontDestroyOnLoad(gameObject); // 跨场景保留(不需要可以删掉) }
// 测试用方法 public void Hello() { Debug.Log("GameManager 单例被调用"); }}