我们从新建一个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.unscaledDeltaTime);
}
}
以及在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就完成了,是不是很简单呢?接下来,就可以开始着手对各个功能模块进行编写了