整体架构

GF层

  • 包含框架中各个模块的具体实现,不依赖于引擎
  • 各个模块若有需要引擎传递的参数,可通过UGF层的Component在初始化时传入
  • 若需要调用依赖于引擎实现的接口,可定义对应的IHelper接口,并在UGF层实现接口,GF层只调用,不关心具体实现

UGF层

  • 实现框架中需要依赖Unity的逻辑,把框架与引擎解耦
  • 作为Game层与GF层之间的桥梁
  • 实例化并初始化框架各个模块
  • 借助Unity的Editor扩展,实现各个模块参数的可视化配置

上图UGF与GF的关系其实简化了,实际上每个模块的XXXManager都会实现了对应的IXXXManager接口,UGF只会直接引用接口,不会直接引用Manager

Game层

游戏逻辑,只与UGF层直接接触

启动流程

Unity要启动游戏,至少要有一个自定义的Monobehaviour脚本挂在场景中的GameObject上,来作为我们游戏的逻辑入口,那么任何框架要在Unity中启动也不例外,需要依赖Monobehaviour的生命周期方法启动。

  1. GF中每个模块都有一个对应的Component(继承自Monobehaviour),并挂在各自对应的GameObject上,放在启动场景中,当运行游戏时,Unity便会调用各个Component的Awake方法。
  2. 在GameFrameworkComponent(UGF中所有Component的基类)的Awake方法中,会调用GameEntry.RegisterComponent把Component注册到GameEntry中,以方便在其他地方通过GameEntry来访问任意Component。
  3. 因为Component是继承自Monobehaviour并被直接挂在场景中的GameObject上,引擎会执行Component的实例化,而GF层中的各个模块(Module)是普通C#类,需要我们自己去实例化,GF便是在Component的Awake中去实例化各个模块类。(Resource模块比较特殊,在Start实例化)。
  4. 各个Component的Start方法被调用,考虑到模块可能需要依赖其他模块,所以在Awake过后,各个Component注册到GameEntry中后(这样才能获取到其他模块的引用),再在Start阶段初始化各个模块。
  5. 根据Inspector面板配置和Unity API的参数,初始化各个模块,并实例化Component所需要的GameObject。
  6. 实例化模块所需要的Helper,并以接口形式传递给对应模块。
  7. Procedure是框架中管理整个游戏流程的模块,Procedure的Component中的Start方法以协程方式启动,协程等待了一帧,这一帧猜测是等待步骤5中实例化出来的GameObject对象完成初始化,避免游戏启动逻辑与这些GameObject的初始化有依赖时产生时序问题。
  8. 游戏启动第二帧,Procedure模块启动我们指定的入口流程,在此例中,入口为ProcedureLaunch。
  9. 执行ProcedureLaunch流程的OnEnter方法,游戏的第一句具体逻辑,在这正式被调用。

GameFrameworkModule的实例化

GameFrameworkModule(GF层中各个模块的基类)采用惰性实例化,UGF的Component通过调用GameFrameworkModule.GetModule来获取模块对象,在GetModule时,GameFrameworkEntry会先检测内部有没有这个模块对象,没有时再调用内部的CreateModule来实例化该模块。

可以看到GetModule是传入模块的接口的,而不是模块类本身,GetModule内部会通过反射获得传入接口名字的字符串,并裁掉第一个字符,如传入IXXXManager,会取得“XXXManager”字符串,这个字符串对应了模块类名,然后通过反射来创建该模块实例。

Tick

因为各个Monobehaviour之间不能很好地控制顺序问题,GF通过指定的一个Monobehaviour中的Update方法去驱动所有模块的Update,各自模块的Update顺序由各自模块定义的优先级决定,这样只要在框架管理下的模块,都能做到执行顺序可控。

  1. 引擎调用所有Monobehaviour的Update方法
  2. BaseComponent中的Update方法被调用
  3. BaseComponent中的Update方法调用GameFrameworkEntry的Update方法
  4. GameFrameworkEntry内部以链表的方式,把已经创建好的模块对象按优先级顺序(降序)组织好,GameFrameworkEntry的Update中会以链表顺序遍历各个模块,并调用Update方法

Shutdown

  1. 业务层调用GameEntry的Shutdown方法(会传入枚举值ShutdownType)
  2. GameEntry的Shutdown方法调用BaseComponent的Shutdown方法
  3. BaseComponent是个Monobehaviour类,在Shutdown中调用Monobehaviour的Destroy销毁自身
  4. 根据最初传入的ShutdownType来执行LoadScene(重新启动游戏)或Quit(退出游戏)。
  5. BaseComponent的OnDestroy被调用
  6. BaseComponent的OnDestroy里调用GameFrameworkEntry的Shutdown方法
  7. 与Update相反,GameFrameworkEntry的Shutdown中会以链表逆序遍历各个模块,并调用Shutdown方法

最后

GameFramework解析 系列目录:GameFramework解析:开篇

个人原创,未经授权,谢绝转载!