Unity3D RPG Core | 19 泛型单例模式

这节内容编写泛型单例类。使用泛型的原因是后续我们还会再创建一些单例类,为了方便我们为单例抽象出一个模板。

1. 编写泛型单例类

我们创建一个新的 C# 脚本,命名为 Singleton。如代码清单 1 所示,我们同样申请静态的 m_instance 以及访问单例的 GetInstance() 函数。

同时此处单例类上下文依托于 Unity 生命周期,所以将相关维护操作放置在 Awake()OnDestroy() 中。进一步感受生命周期对于单例的维护,可以在相关函数上打断点跟踪一下。

要使运行时断点生效,需要在 VS 中选择 “附加到 Unity 并播放”。

第 5 行声明中的 where 关键字是对类型参数的约束,它代表类型 T 必须是继承于 Singleton<T> 的类型。

代码清单 1 泛型单例类
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class Singleton<T> : MonoBehaviour where T : Singleton<T>
  6. {
  7.     static T m_instance = null;
  8.  
  9.     static public T GetInstance()
  10.     {
  11.         return m_instance;
  12.     }
  13.  
  14.     protected virtual void Awake()
  15.     {
  16.         if (m_instance != null)
  17.             Destroy(gameObject);
  18.         else
  19.             m_instance = (T)this;
  20.     }
  21.  
  22.     protected virtual void OnDestroy()
  23.     {
  24.         if (m_instance == this)
  25.         {
  26.             m_instance = null;
  27.         }
  28.     }
  29. }

1.1 改写 MouseManager 类

之前编写的 MouseManager 类是一个单例类,我们对其进行改造。只需使其继承于上述编写的 Singleton 类:

  • public class MouseManager : Singleton<MouseManager>

接着再删除 MouseManager 中之前已经定义的和 Singleton 类中逻辑重复的地方即可(m_instance、GetInstance、Awake)。

2. GameManager 开个头

之前我们还遗留一些问题:比如角色人物死亡后,需要执行特定的逻辑。这些游戏整体的逻辑我们放在 GameManager 类中进行控制,同样它也需要是一个单例类。

如代码清单 3 所示,我们同样使 GameManager 继承于 Singleton 类。在 GameManager 中我们需要获取到角色人物的状态信息,通过 RegisterPlayerData() 函数外部指定角色信息变量。

代码清单 2 GameManager 类
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4.  
  5. public class GameManager : Singleton<GameManager>
  6. {
  7.     public CharacterData m_playerData;
  8.  
  9.     public void RegisterPlayerData(CharacterData playerData)
  10.     {
  11.         m_playerData = playerData;
  12.         Debug.Log("RegisterPlayerData Done.");
  13.     }
  14. }

如代码清单 3 所示,RegisterPlayerData() 调用的时机,我们放在 PlayerController 类的 Start() 函数中。

代码清单 3 指定人物角色信息
  1. public class PlayerController : MonoBehaviour
  2. {
  3.     // Start is called before the first frame update
  4.     void Start()
  5.     {
  6.         MouseManager.GetInstance().OnMoveMouseClick   += DoMoveAction;
  7.         MouseManager.GetInstance().OnAttackMouseClick += DoAttackAction;
  8.  
  9.         GameManager.GetInstance().RegisterPlayerData(m_characterData);
  10.     }
  11. }

最后,要让 GameManager 运行起来。和 MouseManager 一样,如图 1 所示,我们在 Hierarchy 窗体中创建一个空的对象,并将 GameManager 脚本附加在上面。

图1 附加 MouseManager 脚本