我们从新建一个Unity项目开始,名字叫SimpleGameFramework(下文简称SGF)
建立好框架与其脚本的目录
然后就可以开始框架Entry部分的搭建了
在GF的设计中,框架被分为了两部分,一部分独立Unity引擎,另一部分则依赖于Unity引擎:
自然而然的,GF里Entry也被分为了两部分,既然我们要搭建的是简易版的GF,那在设计上就不采用一部分与Unity分离的形式,而是全部依赖于Unity
首先新建一个Base文件夹,用来存放构成框架基础的类文件,GF在总体设计上是Manager of Managers式的,我们就在Base下面新建一个名为ManagerBase的模块管理器基类
/// <summary> /// 模块管理器基类 /// </summary> public abstract class ManagerBase { /// <summary> /// 模块优先级,优先级高的模块会先被轮询,并且后关闭 /// </summary> public virtual int Priority { get { return 0; } } /// <summary> /// 初始化模块 /// </summary> public abstract void Init(); /// <summary> /// 轮询模块 /// </summary> /// <param name="elapseSeconds">逻辑流逝秒</param> /// <param name="realElapseSeconds">真实流逝秒</param> public abstract void Update(float elapseSeconds, float realElapseSeconds); /// <summary> /// 停止并清理模块 /// </summary> public abstract void Shutdown(); }
在SGF的设计中,各Manager并不继承 MonoBehaviour,那么里面的Update是在哪里被调用呢?答案是在Managers里,只有Managers需要去继承MonoBehaviour,因此在建立Managers之前,我们需要先建立一个用于MonoBehaviour的单例模板
/// <summary> /// 脚本的单例模板基类 /// </summary> public abstract class ScriptSingleton<T> : MonoBehaviour where T : ScriptSingleton<T> { protected static T _instance; public static T Instance { get { if (_instance == null) { //从场景中找T脚本的对象 _instance = FindObjectOfType<T>(); if (FindObjectsOfType<T>().Length > 1) { Debug.LogError("场景中的单例脚本数量 > 1:" + _instance.GetType().ToString()); return _instance; } //场景中找不到的情况 if (_instance == null) { string instanceName = typeof(T).Name; GameObject instanceGO = GameObject.Find(instanceName); if (instanceGO == null) { instanceGO = new GameObject(instanceName); DontDestroyOnLoad(instanceGO); _instance = instanceGO.AddComponent<T>(); DontDestroyOnLoad(_instance); } else { //场景中已存在同名游戏物体时就打印提示 Debug.LogError("场景中已存在单例脚本所挂载的游戏物体:" + instanceGO.name); } } } return _instance; } } void OnDestroy() { _instance = null; } }
然后就可以开始建立作为框架入口的Managers了
新建一个FrameworkEntry类,并继承我们刚才写的ScriptSingleton
/// <summary> /// 框架入口,维护所有模块管理器 /// </summary> public class FrameworkEntry : ScriptSingleton<FrameworkEntry> { }
在其中定义一个链表,用于维护所有的Manager
/// <summary> /// 所有模块管理器的链表 /// </summary> private LinkedList<ManagerBase> m_Managers = new LinkedList<ManagerBase>();
然后在Update方法里轮询所有Manager,调用它们的Update方法
void Update() { //轮询所有管理器 foreach (ManagerBase manager in m_Managers) { manager.Update(Time.deltaTime, Time.realtimeSinceStartup); } }以及在OnDestroy方法里清理所有Manager
void OnDestroy() { //关闭并清理所有管理器 for (LinkedListNode<ManagerBase> current = m_Managers.Last; current != null; current = current.Previous) { current.Value.Shutdown(); } m_Managers.Clear(); }
接着开始编写对外提供的,获取链表里指定类型的Manger对象的方法
/// <summary> /// 获取指定管理器 /// </summary> public T GetManager<T>() where T : ManagerBase { Type managerType = typeof(T); foreach (ManagerBase manager in m_Managers) { if (manager.GetType() == managerType) { return manager as T; } } //没找到就创建 return CreateManager(managerType) as T; }
我们还需要一个供内部使用的创建Manager的方法
/// <summary> /// 创建模块管理器 /// </summary> private ManagerBase CreateManager(Type managerType) { ManagerBase manager = (ManagerBase)Activator.CreateInstance(managerType); if (manager == null) { Debug.LogError("模块管理器创建失败:" + manager.GetType().FullName); } //根据模块优先级决定它在链表里的位置 LinkedListNode<ManagerBase> current = m_Managers.First; while (current != null) { if (manager.Priority > current.Value.Priority) { break; } current = current.Next; } if (current != null) { m_Managers.AddBefore(current, manager); } else { m_Managers.AddLast(manager); } //初始化模块管理器 manager.Init(); return manager; }到这里,我们的Managers就完成了,是不是很简单呢?接下来,就可以开始着手对各个功能模块进行编写了