- 游戏开发
【免费下载链接】GameFramework
This is literally a game framework, based on Unity game engine. It encapsulates commonly used game modules during development, and, to a large degree, standardises the process, enhances the development speed and ensures the product quality.
本篇技术指南以 Game Framework 官方简介与模块清单为核心,结合仓库源码逐一剖析其 19 个内置模块的职责边界、关键接口与实现原理。读完本文,你将理解每个模块在游戏开发中的典型应用场景、如何通过统一的模块机制获取与轮询模块、以及事件、对象池、任务池、资源异步加载等底层设施是如何支撑起这套框架的。
Game Framework 是什么
Game Framework 是一个基于 Unity 引擎的游戏框架,主要对游戏开发过程中常用模块进行了封装,很大程度地规范开发过程、加快开发速度并保证产品质量。框架不依赖具体业务逻辑,而是以"模块 + 辅助器(Helper)"的开放架构,让开发者针对自己的项目实现各模块的辅助器来适配引擎细节。
在当前仓库中,框架本体全部代码位于 GameFramework 目录下,是一个编译为类库(Library)的 C# 工程(见 GameFramework.csproj,目标框架为 .NET 3.5,AllowUnsafeBlocks已开启以支持序列化等底层操作)。README.md(即本文所依据的官方简介文档)声明当前版本内置19 个模块,下文将逐一展开。
框架的运行底座:模块注册、获取与轮询
在逐个认识 19 个模块之前,先理解框架整体的"模块化"运转方式,这有助于后续快速上手任何模块。
所有模块都继承自内部抽象类 GameFrameworkModule,它定义了三个要素:
- Priority(优先级):优先级较高的模块会优先轮询,关闭操作会后进行;
- Update(elapseSeconds, realElapseSeconds):每帧由框架入口统一驱动轮询;
- Shutdown():关闭并清理模块资源。
框架入口 GameFrameworkEntry 使用一个GameFrameworkLinkedList<GameFrameworkModule>按优先级维护全部模块实例,并提供三个静态入口:
Update(elapseSeconds, realElapseSeconds):逐模块调用Update,完成每帧逻辑驱动;Shutdown():逆序关闭所有模块、清空引用池、释放缓存的非托管内存并重置日志辅助器;GetModule<T>():按接口类型获取模块。其内部通过命名约定把接口IFooManager映射为具体实现类FooManager,若模块不存在则Activator.CreateInstance自动创建并按优先级插入链表。注意它要求传入的必须是GameFramework.命名空间下的接口,否则抛出GameFrameworkException。
因此实际开发中,获取任意模块的惯用法是:
IEventManager eventManager = GameFrameworkEntry.GetModule<IEventManager>();框架还提供一批与模块解耦的通用基础设施,包括 事件池 EventPool、引用池 ReferencePool、任务池 TaskPool、多字典与链表容器、通用变量 Variable 以及 实用函数集 Utility(涵盖程序集、压缩、转换、加密、JSON、Marshal、路径、随机、文本、CRC32 校验等工具方法),这些设施会被下文多个模块复用。
19 个内置模块逐一解析
1. 全局配置(Config)
用于存储一些全局的只读游戏配置,如玩家初始速度、游戏初始音量等。实际实现 ConfigManager 内部以Dictionary<string, ConfigData>保存配置项,并借助基座层的DataProvider<IConfigManager>统一完成数据的异步读取,因此暴露了ReadDataSuccess、ReadDataFailure、ReadDataUpdate、ReadDataDependencyAsset四个读取事件。框架本身不实现具体文件格式的解析,解析逻辑由实现 IConfigHelper 的辅助器决定——这也是 Game Framework 各模块统一的"管理器管流程、辅助器管平台细节"设计。
2. 数据结点(Data Node)
将任意类型的数据以树状结构保存,用于管理游戏运行时的各种数据。DataNodeManager 维护一棵根结点(<Root>),路径支持.、/、\三种分隔符(见PathSplitSeparator)。典型用法:
IDataNodeManager dataNodeManager = GameFrameworkEntry.GetModule<IDataNodeManager>(); // 设置/获取数据(数据以 Variable 泛型包装) dataNodeManager.SetData<VarInt>("Player.Level", 10); VarInt level = dataNodeManager.GetData<VarInt>("Player.Level");数据结点本身也实现引用池回收(Shutdown时通过ReferencePool.Release释放根结点),体现了框架"所有可复用对象尽量进引用池"的取向。
3. 数据表(Data Table)
可以将游戏数据以表格(如 Microsoft Excel)的形式进行配置后使用,数据表的格式可以自定义。DataTableManager 通过IDataTableHelper将自定义格式的文本/二进制解析为强类型的数据行(行对象实现 IDataRow),并同样借助DataProvider<DataTableBase>异步加载。开发者需要做的事情是:为每张表定义一个实现IDataRow的行类型,并提供解析该表格式的IDataTableHelper。与 Config 类似,数据表也提供成功/失败/更新/依赖资源四类读取事件。
4. 调试器(Debugger)
当游戏在 Unity 编辑器中运行或者以 Development 方式发布运行时,将出现调试器窗口,便于查看运行时日志、调试信息等。DebuggerManager 通过ActiveWindow控制窗口显隐,以DebuggerWindowGroup树(见 DebuggerManager.DebuggerWindowGroup.cs)组织各调试窗口,开发者可以通过实现 IDebuggerWindow 把自己的调试面板注册进窗口树中。
5. 下载(Download)
提供下载文件的功能,支持断点续传,并可指定允许几个下载器进行同时下载;更新资源时会主动调用此模块。DownloadManager 基于任务池TaskPool<DownloadTask>调度下载任务,其关键参数与默认值(源码可见)包括:
| 参数 | 含义 | 默认值 |
|---|---|---|
FlushSize | 将缓冲区写入磁盘的临界大小 | 1 MB |
Timeout | 下载超时时长(秒) | 30 秒 |
Paused | 是否暂停全部下载 | false |
| 任务优先级 | 下载任务默认优先级 | 0(见 Download/Constant.cs) |
通过TotalAgentCount、FreeAgentCount、WorkingAgentCount、WaitingTaskCount可以实时观察下载队列状态。模块优先级为 5(见源码Priority重写),保证在资源更新流程中获得合理的轮询次序。
6. 实体(Entity)
将游戏场景中动态创建的一切物体定义为实体。此模块提供管理实体和实体组的功能,如显示隐藏实体、挂接实体(如挂接武器、坐骑,或者抓起另一个实体)等;实体使用结束后可以不立刻销毁,从而等待下一次重新使用。EntityManager 通过EntityInfo记录实体状态,用对象池(IObjectPoolManager)缓存实体实例对象,加载实体资源统一走LoadAssetCallbacks异步回调。实体逻辑类实现 IEntity,平台实例化等细节由 IEntityHelper 提供。同时暴露ShowEntitySuccess/Failure/Update/DependencyAsset与HideEntityComplete五个事件。
7. 事件(Event)
游戏逻辑监听、抛出事件的机制。Game Framework 中的很多模块在完成操作后都会抛出内置事件,监听这些事件将大大解除游戏逻辑之间的耦合;用户也可以定义自己的游戏逻辑事件。EventManager 直接建立在EventPool之上,构造时采用AllowNoHandler | AllowMultiHandler模式(允许无处理器、允许多处理器)。其接口(见 IEventManager)提供:
Subscribe(id, handler)/Unsubscribe(id, handler):订阅与取消订阅,事件 id 由事件类类型生成;Fire(sender, e):抛出事件(线程安全,非主线程抛出也会保证在主线程下一帧分发);FireNow(sender, e):立即分发事件(非线程安全,立刻回调)。
自定义事件的推荐做法是派生 GameEventArgs(它继承自BaseEventArgs并实现引用池接口),在事件类中实现Clear()与Id属性。
8. 文件系统(File System)
虚拟文件系统使用类似磁盘的概念对零散文件进行集中管理,优化资源加载时产生的内存分配,甚至可以对资源进行局部片段加载,极大提升资源加载性能。FileSystemManager 负责文件系统的创建、加载与销毁;具体读写由 FileSystem 实现,它包含头部数据(HeaderData)、块数据(BlockData)与字符串数据(StringData)三类内部结构,底层通过 FileSystemStream(及其通用实现 CommonFileSystemStream)访问物理文件,访问模式由 FileSystemAccess 枚举控制(Read/Write/ReadWrite)。
9. 有限状态机(FSM)
提供创建、使用和销毁有限状态机的功能,适用于状态机机制的游戏逻辑。FsmManager 以Dictionary<TypeNamePair, FsmBase>维护所有状态机,轮询时先拷贝到临时列表再逐个Update,规避遍历中销毁状态机的问题。状态机本身为 Fsm,状态基类为 FsmState,其中定义了进入(OnEnter)、轮询(OnUpdate)、离开(OnLeave)与销毁(OnDestroy)四个钩子。FSM 模块优先级为 1,是流程模块(见第 13 节)的直接依赖。
10. 本地化(Localization)
提供本地化功能,即多语言支持。Game Framework 的本地化不但支持文本,还支持任意资源的本地化——例如烟花特效可以做成多语言版本,中文版显示"新年好",英文版显示"Happy New Year"。LocalizationManager 内部维护Dictionary<string, string>字典,通过Language属性设置当前语言(枚举见 Language,初始为Unspecified,设为该值会抛异常),SystemLanguage则交给 ILocalizationHelper 获取系统语言。文本表的加载同样基于DataProvider<ILocalizationManager>,并暴露成功/失败/更新/依赖资源事件。
11. 网络(Network)
提供使用 Socket 长连接的功能,当前支持 TCP 协议,同时兼容 IPv4 和 IPv6。NetworkManager 通过Dictionary<string, NetworkChannelBase>维护多个网络频道,可同时建立多个连接与多个服务器通信(例如同时连接游戏服务器与语音服务器)。关键类型:
- ServiceType:
Tcp与TcpWithSyncReceive(同步接收的 TCP)两种频道实现分别见 NetworkManager.TcpNetworkChannel.cs 与 NetworkManager.TcpWithSyncReceiveNetworkChannel.cs; - AddressFamily:
Unknown/IPv4/IPv6; - Packet:消息包基类,如果接入 ProtoBuf 之类的协议库,只要派生自 Packet 类并实现自己的消息包类即可使用;消息包的编解码与注册由 IPacketHeader 与 IPacketHandler 定义。
频道提供NetworkConnected、NetworkClosed、NetworkMissHeartBeat(心跳丢失)、NetworkError、NetworkCustomError五类事件。
12. 对象池(Object Pool)
提供对象缓存池的功能,避免频繁地创建和销毁各种游戏对象,提高游戏性能。Game Framework 自身大量使用对象池,用户也可以很方便地创建和管理自己的对象池。ObjectPoolManager 以Dictionary<TypeNamePair, ObjectPoolBase>管理全部对象池,默认参数见源码常量:
| 参数 | 默认值 |
|---|---|
容量Capacity | int.MaxValue |
过期时间ExpireTime | float.MaxValue(不过期) |
优先级Priority | 0 |
对象池中每个对象继承 ObjectBase,释放策略可自定义(ReleaseObjectFilterCallback)。对象池模块优先级为 6,每帧负责驱动所有池的自动释放与过期处理。
13. 流程(Procedure)
流程是贯穿游戏运行时整个生命周期的有限状态机。通过流程将不同的游戏状态解耦:对于网络游戏,可能需要检查资源流程、更新资源流程、检查服务器列表流程、选择服务器流程、登录服务器流程、创建角色流程等;对于单机游戏,则需要在游戏选择菜单流程和实际玩法流程之间切换。ProcedureManager 本质上是对 FSM 的封装——Initialize(IFsmManager, params ProcedureBase[])将流程数组创建为一个状态机,StartProcedure<T>()切换当前流程,CurrentProcedure与CurrentProcedureTime分别取得当前流程与其持续时间。增加流程只需派生 ProcedureBase 并实现自己的流程类,例如:
public sealed class ProcedureMenu : ProcedureBase { protected override void OnEnter(IFsm<IProcedureManager> procedureOwner) { base.OnEnter(procedureOwner); // 进入主菜单:加载主菜单界面、播放背景音乐等 } protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds) { base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); // 处理菜单逻辑,需要时切换到其他流程 } }流程模块优先级为 -2,是所有模块中最早轮询的一批,确保游戏状态机先于其他业务运转。
14. 资源(Resource)
为保证玩家体验,框架不推荐使用同步方式加载资源,由于自身使用了一套完整的异步加载资源体系,因此只提供异步加载资源的接口。不论简单的数据表、本地化字典,还是复杂的实体、场景、界面,都使用异步加载。同时提供默认的内存管理策略(也可以自定义),多数情况下使用 GameObject 时甚至不需要自行调用Instantiate或Destroy。IResourceManager 定义了完整的能力面:
- 资源分区:
ReadOnlyPath(只读区,通常为包内资源)、ReadWritePath(读写区,通常为可更新目录)、CurrentVariant(当前变体); - 资源模式 ResourceMode:
Package(单机模式)、Updatable(预下载的可更新模式)、UpdatableWhilePlaying(使用时下载的可更新模式); - 版本信息:
ApplicableGameVersion(适用游戏版本号)、InternalResourceVersion(内部资源版本号)、AssetCount、ResourceCount; - 序列化器:
PackageVersionListSerializer、UpdatableVersionListSerializer、ReadOnlyVersionListSerializer、ReadWriteVersionListSerializer、ResourcePackVersionListSerializer,分别对应单机/可更新/本地/资源包场景下的版本资源列表解析; - 加载能力:资源加载、二进制加载、场景加载均以回调组(如
LoadAssetCallbacks、LoadSceneCallbacks、LoadBinaryCallbacks)异步返回结果。
从源码结构看,资源模块内部被拆分为资源检查(ResourceChecker)、初始化(ResourceIniter)、更新(ResourceUpdater)、校验(ResourceVerifier)、加载(ResourceLoader)以及版本列表处理(VersionListProcessor)等若干子组件,并复用下载模块完成热更新文件的拉取。这是整个框架中最庞大、最核心的模块。
15. 场景(Scene)
提供场景管理功能,可以同时加载多个场景,也可以随时卸载任何一个场景,从而很容易实现场景的分部加载。SceneManager 内部维护三个列表分别记录已加载、加载中、卸载中的场景资源名,加载与卸载全部经由资源模块的异步回调完成,并暴露LoadSceneSuccess/Failure/Update/DependencyAsset与UnloadSceneSuccess/Failure事件。
16. 配置(Setting)
以键值对形式存储玩家数据,对UnityEngine.PlayerPrefs进行封装,也可以将这些数据直接存储在磁盘上。SettingManager 本身不实现存储细节,而是把读写委托给 ISettingHelper(SetSettingHelper注入),因此在 Unity 平台可选用 PlayerPrefs 辅助器,在需要落盘的项目中可换用基于磁盘文件的辅助器。Shutdown()时框架会自动调用Save()持久化数据,此外还提供Load()、Save()、DeleteSetting以及按类型读写键值的一组方法。
17. 声音(Sound)
提供管理声音和声音组的功能,用户可以自定义一个声音的音量、是 2D 还是 3D 声音,甚至是直接绑定到某个实体上跟随实体移动。SoundManager 以Dictionary<string, SoundGroup>管理声音组,播放参数封装在 PlaySoundParams 中(包括音量、是否为 2D/3D、是否绑定实体等);声音资源同样经资源模块异步加载,暴露PlaySoundSuccess/Failure/Update/DependencyAsset事件。声音播放的平台细节由 ISoundHelper 与 ISoundAgentHelper 实现。
18. 界面(UI)
提供管理界面和界面组的功能,如显示隐藏界面、激活界面、改变界面层级等。不论是 Unity 内置的 uGUI 还是其它类型的 UI 插件(如 NGUI),只要派生自 UIFormLogic 类并实现自己的界面类即可使用;界面使用结束后可以不立刻销毁,从而等待下一次重新使用。UIManager 通过UIGroup组织界面层级,界面实例复用依托IObjectPool<UIFormInstanceObject>实例池(对应InstanceAutoReleaseInterval、InstanceCapacity、InstanceExpireTime、InstancePriority一组池参数),加载走LoadAssetCallbacks异步回调,并暴露OpenUIFormSuccess/Failure/Update/DependencyAsset与CloseUIFormComplete事件。
19. Web 请求(Web Request)
提供使用短连接的功能,可以用 GET 或 POST 方法向服务器发送请求并获取响应数据,可指定允许几个 Web 请求器同时请求。WebRequestManager 基于TaskPool<WebRequestTask>调度请求,默认超时 30 秒,默认任务优先级 0(见 WebRequest/Constant.cs),通过AddWebRequest系列方法发起请求,并暴露WebRequestStart/Success/Failure事件。与下载模块不同,它面向短连接场景(如登录验证、公告拉取、排行榜上报等),两者共享任务池调度模式但职责分明。
模块间的协作与典型启动流程
从源码的优先级设置(ProcedureManager = -2、DebuggerManager = -1、FsmManager = 1、SceneManager = 2、FileSystemManager = 4、DownloadManager = 5、ObjectPoolManager = 6、EventManager = 7,其余模块为默认 0)可以推断出框架每帧的轮询次序与关闭次序的设计意图:流程与调试器先行驱动全局状态,对象池与事件系统紧跟其后保证复用与消息分发,下载与文件系统等重 IO 模块居中;关闭时则逆序进行,事件系统最先收尾,避免关闭过程中产生孤立事件。
一个典型的网络游戏启动链路通常是:
- 通过
GameFrameworkEntry.GetModule<T>()获取各管理器接口(自动创建模块); ProcedureManager.Initialize(fsmManager, procedures...)注册全部流程,StartProcedure<ProcedureLaunch>()启动首个流程;- 启动流程中借助
IResourceManager(ResourceMode.Updatable)检查并更新资源,更新时IDownloadManager被主动调用; - 资源就绪后通过
ISceneManager.LoadScene异步加载场景,通过IUIManager.OpenUIForm弹出登录界面; - 游戏过程中的业务数据经
IDataNodeManager管理、事件经IEventManager广播、频繁创建的对象经IObjectPoolManager复用。
如何获取与上手
当前仓库以源码形式提供框架本体,包含 GameFramework.sln 解决方案与 GameFramework.csproj 工程文件。上手方式:
- 阅读源码:按 GameFramework 目录下的模块划分逐目录阅读,每个模块均由"管理器(内部实现)+ 接口 + 事件参数 + 辅助器接口"四类文件组成,结构非常规整;
- 编译工程:用支持 .NET 3.5 的 MSBuild 工具链构建
GameFramework.csproj得到GameFramework.dll与对应的 XML 文档文件(工程已开启DocumentationFile与TreatWarningsAsErrors); - 集成到 Unity:将程序集放入 Unity 项目,再为需要使用的模块编写对应辅助器实现(如
IResourceHelper、IUIManager配套的 UI 逻辑基类等),并通过SetXxxHelper注入; - 进阶指引:README 中同时提供了中英文简介(English 部分官方标注 Coming soon),社区交流可参考其中提到的 QQ 讨论群 216332935;更完整的官方文档站为 gameframework.cn,可按需查阅。
小结
Game Framework 的价值在于把游戏开发中最高频的横切能力——配置、数据、调试、下载、实体、事件、文件系统、状态机、本地化、网络、对象池、流程、资源、场景、存档、声音、界面与网络请求——统一收敛为 19 个职责清晰、可插拔的模块,并在底层用引用池、事件池、任务池与异步资源加载体系把这些模块高效地串起来。理解每个模块的接口面与辅助器扩展点,是把它用进自己项目的关键一步;而源码中每个模块"接口 + 实现 + 事件参数 + 辅助器接口"的四件套结构,也为二次开发或替换平台实现提供了清晰的模板。
- 游戏开发
【免费下载链接】GameFramework
This is literally a game framework, based on Unity game engine. It encapsulates commonly used game modules during development, and, to a large degree, standardises the process, enhances the development speed and ensures the product quality.
相关推荐
基于 DAMON 的主动式内存回收(DAMON_RECLAIM)内核模块完全指南
基于 DAMON 的主动式内存回收(DAMON_RECLAIM)内核模块完全指南 DAMON based Reclamation(DAMON_RECLAIM)是
操作系统内核驱动驱动开发虚拟化嵌入式网络存储OpenCore Legacy Patcher 实操指南:把 2013 年的 MacBook Pro 升级到 Sonoma
OpenCore Legacy Patcher 实操指南:把 2013 年的 MacBook Pro 升级到 Sonoma 上周我帮朋友翻出一台 2013 年的
操作系统固件驱动开发MicroPython 核心模块实现指南:基于 py/ 目录从零编写内置模块
MicroPython 核心模块实现指南:基于 py/ 目录从零编写内置模块 本指南以 MicroPython 官方开发文档 docs/develop/libr
嵌入式语言运行时编程语言解释器编译器物联网系统编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考