☰
Unity2018打开GameFramework遇到的问题GameFramework解读
2026/10/23 2:58:47 网站建设 项目流程

首先是GameFramework的Editor程序集找不到GameFramework命名空间,需要在它的asmdef文件添加对GameFramework和UnityGameFramework.Runtime程序集的引用。

UnityGameFramework.Runtime程序集也要引用GameFramework程序集。

然后UnityWebRequest在2018没有PostWWWForm函数,先改成Post。然后发现没有自动重新编译。发现PackageManager里没有Visual Studio的插件,Unity Registry里也没有。

查资料知道Visual Studio的插件在2019才出现。2018 不靠 Registry 装 VS 支持,是外部 IDE 模式 + VSTU(Visual Studio Tools for Unity)。

让我在Unity Hub安装Microsoft Visual Studio Community 2017。我有Visual Studio2022,不想装2017,于是换Unity2022。

最根的非Behavior类:GameFrameworkModule

是不继承MonoBehavior的管理器的基类。很多XXManager都是继承它和一个同名接口。

有抽象方法Update,由所有模块的管理器GameFrameworkEntry调用。

最根的Behavior类:GameFrameworkComponent

我们发现GameFrameworkComponent继承MonoBehavior,一大堆XXComponent继承它。那么很明显GameFrameworkComponent就是MonoBehavior型管理器的基类。

XXComponent-XXManager架构

关于GameFramework:UI

我追踪一个UI面板的关闭方法,调用了UIComponent.CloseUIForm,里面调用了UIManager.CloseUIForm,UIComponent持有IUIManager成员。点进它的方法,进入的是接口的声明,定义要去同名实现里。

IUIManager接口,只有一个实现,UIManager,由5个脚本写成。里面使用异步加载,有正在加载的UI集合,有加载完就要销毁的UI集合。

有一个UIGroup,它下面有IUIForm。

我想看释放UI资源的具体实现,一直找到这里。这里让类型参数必须是一个接口。但是后面是用Activator.CreateInstance反射创建对象。接口怎么创建对象?

注意这里获得moduleName,从第一个字符(也就是从1数第2个)截取,其实是把接口的I去掉得到类型名。

public static T GetModule<T>() where T : class { Type interfaceType = typeof(T); if (!interfaceType.IsInterface) { throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", interfaceType.FullName)); } if (!interfaceType.FullName.StartsWith("GameFramework.", StringComparison.Ordinal)) { throw new GameFrameworkException(Utility.Text.Format("You must get a Game Framework module, but '{0}' is not.", interfaceType.FullName)); } string moduleName = Utility.Text.Format("{0}.{1}", interfaceType.Namespace, interfaceType.Name.Substring(1)); Type moduleType = Type.GetType(moduleName); if (moduleType == null) { throw new GameFrameworkException(Utility.Text.Format("Can not find Game Framework module type '{0}'.", moduleName)); } return GetModule(moduleType) as T; }

这个框架有大量的接口,唯一的实现就是去掉I的同名类。包括UIManager、ObjectPoolManager都继承GameFrameworkModule和同名接口。接口定义必须实现的函数、属性。GameFrameworkModule方便上层统一调用。

ObjectPoolManager是生成各种对象池的管理器。

UIManager销毁UI是把它放进一个回收队列,在Update里处理。Update里调用了ObjectPool.Unspawn(这里写的是接口IObjectPool,要去实现类里找方法实现)。里面调用了GF封装的Object.Unspawn。

对象的封装

被管理的对象都继承ObjectBase,而ObjectPool缓存的是Object<T>,Object<T>里面有具体被管理对象。

资源的编辑器异步加载:EditorResourceComponent

我想到,我们想看资源加载的调用链,直接用VS代码搜索相关的API如AssetDatabase.LoadAssetAtPath,加打印,那么它就会把调用栈全打印出来。而不用从上层跳转十八层去找底层API。于是找到了EditorResourceComponent。但是打印并没有很长的调用链。

在EditorResourceComponent里看到,它是在Update里取出链表,加载,加载后执行加载成功回调。那么请求资源方就是往链表里加节点,并且把使用的函数加入回调。

往链表里加节点是LoadAsset做的,查找它的引用,发现它被7个重载引用。

真正被框架调用的只有最后一个重载。调用它的有UI、实体、Item、声音、数据模块。

然后我们看UI模块对资源模块的调用,在UIManager.OpenUIForm,同样一个干活的函数被7个重载调用,还被UIComponent调用。

所以加载一个UI的调用链是:

UIComponent.OpenUIForm>UIManager.OpenUIForm>EditorResourceComponent.LoadAsset放入链表,Update里处理。

那么就在LoadAsset里打印,能看见完整调用栈

拿到加载资源的完整调用栈了,接下来怎么读?从上往下还是从下往上?

资源的编辑器异步加载:ResourceManager

IResourceManager接口有两个实现,一个是编辑器资源加载,另一个是ResourceManager。ResourceManager由27个partial脚本组成。

框架Update调用链

BaseComponent.Update>GameFrameworkEntry.Update遍历GameFrameworkModule链表,调用Update>

其他Component未实现Update函数。GameEntry也不参与。

把GameFrameworkModule加入GameFrameworkEntry:

XComponent持有XManager,在Awake里为自己持有的管理器注册加入GameFrameworkEntry的链表。

状态机系统

Procedure系统

在检查器显示了一堆流程,还有一个入口流程选项。这些应该是CustomEditor写的,于是代码搜索CustomEditor。找到了在\Assets\GameFramework\Scripts\Editor\Inspector

这些流程的名字是获取ProcedureBase的所有子类得到的。有多少子类这里就显示多少名字。

这个检查器不会显示默认显示的字段,因为它继承GameFrameworkInspector,这个检查器就没有执行绘制默认检查器。所以它完全按OnInspectorGUI里的代码绘制。

这里用SerializedProperty包裹流程列表和入口流程。

初始时通过名字找到要包裹的属性。

SerializedProperty有一系列API得到它包裹的任何类型的值,包括字符串值、数组长度、数组任意元素。

private void ReadAvailableProcedureTypeNames() { m_CurrentAvailableProcedureTypeNames = new List<string>(); int count = m_AvailableProcedureTypeNames.arraySize; for (int i = 0; i < count; i++) { m_CurrentAvailableProcedureTypeNames.Add(m_AvailableProcedureTypeNames.GetArrayElementAtIndex(i).stringValue); } }

再梳理关键类:GameFrameworkModule、GameFrameworkComponent、ObjectBase、Object<T>、ObjectPool<T>、ObjectPoolBase、GameFrameworkEntry、GameEntry

那么到此我们知道这个框架:

所有非Behavior管理器都叫XManager,继承GameFrameworkModule和同名接口;

所有Behavior管理器都叫XComponent,继承GameFrameworkComponent;

XComponent持有XManager;

XManager通过自定义的SetYManager持有对其他管理器的引用,一个管理器可以有多个方法和引用。

GameFrameworkEntry缓存和管理所有GameFrameworkModule,调用它们的Update;

GameEntry缓存和管理所有GameFrameworkComponent;

这就是所谓的专业框架,随便一个调用,调用链有18层函数,一个函数,五六个参数,不同参数组合要写出七八种重载。

我总结出一点读重载的技巧。一堆重载里面有一个是真正干活的,其他的只是调用那个。真正干活的就是参数最多的那个。

这个作者似乎很喜欢用重载,喜欢把一堆参数,有的没有的排列组合。似乎认为这是成熟代码的标志?

不能把参数打包成一个结构体,不想传的参数就不赋值?

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询