一、IGameModule
框架不建议使用继承Singleton的单例,当你需要新增一个模块或者叫管理器的时候,建议继承IGameModule并在Game脚本中添加静态引用。
/// <summary>
/// 模块接口
/// </summary>
public interface IGameModule
{
/// <summary>
/// 模块优先级
/// </summary>
/// <remarks>优先级较高的模块会优先轮询</remarks>
int Priority{ get; }
/// <summary>
/// 游戏框架模块轮询
/// </summary>
/// <param name="elapseSeconds">逻辑运行时间,以秒为单位</param>
/// <param name="realElapseSeconds">真实运行时间,以秒为单位</param>
void Update(float elapseSeconds, float realElapseSeconds);
/// <summary>
/// 关闭模块
/// </summary>
void Shutdown();
}
二、入口
1.GameEntry
这是一个静态类,在框架层面对所有的模块进行管理,在游戏运行时每帧都会遍历当前已开启的模块,虽然类名叫游戏入口,但其不继承Mono,还不是真正的游戏入口
/// <summary>
/// 每帧运行
/// </summary>
/// <param name="elapseSeconds">逻辑运行时间</param>
/// <param name="realElapseSeconds">真实运行时间</param>
public static void ModuleUpdate(float elapseSeconds, float realElapseSeconds)
/// <summary>
/// 获取一个模块
/// </summary>
/// <typeparam name="T">模块类型</typeparam>
/// <returns>模块</returns>
public static T GetModule<T>() where T : class, IGameModule
/// <summary>
/// 开启一个模块
/// </summary>
/// <typeparam name="T">模块类型</typeparam>
/// <param name="args">对应模块构造函数需要用到的参数</param>
/// <returns>模块</returns>
public static T AddModule<T>(params object[] args) where T : IGameModule
/// <summary>
/// 关闭一个模块
/// </summary>
/// <typeparam name="T">模块类型</typeparam>
public static void ShutdownModule<T>() where T : IGameModule
/// <summary>
/// 卸载当前已加载的所有模块
/// </summary>
public static void CleraAllModule()
2.Game
这个脚本需要挂游戏的初始场景中的一个空物体上,在切换场景时不会被销毁,在程序开始运行的时候,这个脚本会初始化一些必要的模块,除非你明确的知道自己要干什么,否则不要卸载这些模块,其余模块在合适的地方自行加载和卸载。之后在Update中会调用GameEntry的ModuleUpdate。Game中还保存了对所有模块的引用,程序中要使用某个模块的方法统一使用
Game.xxxModule.xxxFunction。
public static EntityManager EntityModule { get; private set; }
public static FsmManager FsmModule { get; private set; }
public static GraphicsManager GraphicsModule { get; private set; }
public static MessageManager MessengerModule { get; private set; }
public static DataSubjectManager ObserverModule { get; private set; }
public static ProcedureManager ProcedureModule { get; private set; }
public static TaskManager TaskModule { get; private set; }
public static ObjectPoolManager ObjectPool { get; private set; }
public static ResourceManager ResModule { get; private set; }
在运行游戏之前,要选择进入游戏的初始流程,脚本会遍历所有继承了ProcedureBase的类放在Inspector面板上供选择。所以在面板上选择的初始流程的Init()和OnEnter函数是真正的游戏入口。模块的卸载和加载也需要在流程的进入和退出中处理。
ProcedureBase的概念会在后面具体介绍,进入一个流程应该尽量不依赖于它之前的流程,这样的话我们在的测试的时候可以从任何一个关键点进入游戏。
为了开发方便,使用者可以在所有的场景中都挂载一个Game脚本,Game类在Awake中做了判断,如果已经有一个Game了,会销毁自身。