中EN
概念页

存档系统

SaveGame

更新于 2026-10-13 约 4 分钟UE5SaveGame存档序列化

UE 的存档围绕自定义的 USaveGame 子类进行:保存时把需要持久化的数据从游戏世界拷进 SaveGame 对象,再用 UGameplayStatics 写入某个存档槽(槽名 + 用户索引);读档时反过来。官方推荐用 AsyncSaveGameToSlot 异步保存,避免掉帧,也避免某些平台的认证问题。

流程

flowchart LR
  W["游戏世界<br/>Character / PlayerController / GameMode"] -->|"拷贝数据"| SG["UMySaveGame 对象"]
  SG -->|"SaveGameToSlot / AsyncSaveGameToSlot"| D[("存档槽<br/>SlotName + UserIndex")]
  D -->|LoadGameFromSlot| SG2["UMySaveGame 对象"]
  SG2 -->|"拷回"| W

保存时把世界里的数据拷进 SaveGame 对象再写盘,读档时把对象读回来、再拷回游戏对象。

  • 从 USaveGame 派生自己的类,里面放需要跨会话保存的所有信息;系统支持多个存档文件,也支持把不同的 SaveGame 类存到不同文件。保存与读取函数声明在 Kismet/GameplayStatics.h 中。(Saving and Loading Your Game in Unreal Engine)
  • 保存:先调用 CreateSaveGameObject 得到新对象,填入数据,然后调用 SaveGameToSlot 或 AsyncSaveGameToSlot。官方示例在构造函数里设置 SaveSlotName 和 UserIndex 作为默认值,否则只有一个会被反复覆盖的槽位。(Saving and Loading Your Game in Unreal Engine)
  • 读档时把数据从 SaveGame 对象拷回 Character、PlayerController、GameMode 等对象(见 Gameplay 框架)。

异步保存(推荐)

官方:AsyncSaveGameToSlot 是推荐的保存方式。异步运行可以避免突然掉帧,让玩家不易察觉,并避免某些平台上可能出现的认证问题。完成后会调用 FAsyncSaveGameToSlotDelegate 委托,参数是槽名、用户索引和表示成功与否的 bool。(Saving and Loading Your Game in Unreal Engine,委托见 委托与 Tick 机制)

实践与坑

  • 存档逻辑常放在 GameInstance 子系统里,使其跨关卡存在(见 子系统;这是工程上的常见做法,官方页没有规定)。
  • SaveGame 对象只保存你放进去的字段;Actor 引用之类的运行时指针不能直接持久化,应保存可重建的标识(这是经验归纳)。保存哪些属性取决于反射元数据,见 UObject 与反射系统。

GEA 的视角:存档与世界块的区别(卷 II 17.4.5)

GEA 第 17 章从引擎角度讨论存档,详见 游戏世界的加载与流送:

  • 存档不是世界块:世界块包含所有动态对象的初始状态和大量静态数据;存档只需当前状态,凡是能从世界块重新得到的信息(如静态几何)都不必存,对玩法无影响的对象可以完全省略,其余对象往往只需部分状态。标准是玩家分辨不出存读档前后的差别。
  • 检查点:只存最后到达的检查点名,再加上生命、命数、背包、武器弹药等少量玩家状态,有的游戏连这些都不存;代价是检查点稀疏时玩家会沮丧。
  • 随处存档:要保存所有影响玩法的对象的位置和内部状态,基本等于世界块减去静态部分;可以省略动画的精确时间、刚体的精确动量等细节,依赖玩家不完美的记忆只存近似状态。

与本页对照:USaveGame 只保存你放进去的字段,正好对应 GEA "只存必要状态"的原则;检查点还是随处存档由游戏设计决定,UE 文档没有规定(对比归纳)。

  1. Saving and Loading Your Game in Unreal Engine UE 5.8 文档
  2. Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
  3. Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 17 章 17.4.5 节

相关页面

游戏开发 · UE5子系统Subsystems子系统 (Subsystem) 是自动实例化、生命周期绑定在宿主对象上的类:Engine、Editor、GameInstance、World、LocalPlayer 五种。宿主创建时自动创建并 Initialize(),宿主关闭时 Deinitialize(),之后无引用即被 GC。它替代了「继承 GameInstance 塞管理器」的老做法,自带按类型的蓝图节点和 Python 访问,特别适合插件。官方编程页只列四种,World 子系统依据 5.8 Python API 补充。游戏开发 · UE5Gameplay 框架Gameplay FrameworkGameplay 框架 (Gameplay Framework) 是 UE 提供的一组相互配合的类,用来搭建游戏的基本结构:Actor 与组件 (Component) 构成场景中的一切;GameMode 在服务器上定规则并生成玩家;玩家由“控制器 (Controller) + 棋子 (Pawn)”组成;GameState 与 PlayerState 负责把全局与每个玩家的状态复制给所有客户端;GameInstance 跨关卡存活。游戏开发 · UE5委托与 Tick 机制Delegates & TickUE 有两种驱动游戏逻辑的方式:事件驱动——委托 (Delegate) 在某事发生时回调绑定的函数;轮询驱动——Tick 每帧(或按最小间隔)调用 Actor/组件的更新函数,并按 Tick 组 (Tick Group) 与物理模拟排序。官方建议能用定时器、委托就不用 Tick,必须 Tick 时用 Tick 组和 Tick 依赖保证顺序,避免“差一帧”问题。游戏开发 · UE5UObject 与反射系统UObject & Reflection System虚幻引擎 (Unreal Engine) 的对象基类是 UObject。在 C++ 类、属性、函数上加 UCLASS/UPROPERTY/UFUNCTION 等宏,再由构建前的预处理工具虚幻头文件工具 (Unreal Header Tool, UHT) 扫描头文件生成代码,引擎就能在运行时“看见”这些类型——这就是反射系统 (Reflection System)。垃圾回收、序列化、编辑器面板、蓝图、网络复制都建立在它之上。游戏开发引擎配置系统Engine Configuration游戏引擎总会积累大量可配置选项:有的通过选项菜单暴露给玩家(画质、音量、手柄设置),有的只供开发团队使用、发售前隐藏或去除(如玩家最大行走速度在开发期可调、发售前改成硬编码)。GEA 讨论选项的存取方式(文本文件、压缩二进制、注册表、命令行、环境变量、在线档案)、全局与每用户选项,以及 Quake cvar、OGRE、Naughty Dog 三个真实例子。游戏开发资源交叉引用与加载后初始化Resource Cross-References & Post-Load Initialization资源之间以任意方式相互引用(网格引用材质,材质引用纹理),整个资源数据库是一张有向依赖图。内存中的指针离开运行中的程序就失去意义,所以存盘时要把引用改写为 GUID 或文件内偏移,加载后再修正 (fix up) 回指针;含非 POD 的 C++ 对象还要用 placement new 调用构造函数;跨文件的外部引用要先加载全部相关文件。加载后通常还需要按资源类型做加载后初始化(以及释放前的拆除)。游戏开发游戏世界的加载与流送Loading & Streaming Game Worlds世界加载系统负责两件事:把世界块和所需资源从磁盘读进内存的文件 I/O,以及这些资源的内存分配与释放;另外还要管理游戏对象的生成与销毁。GEA 按演进顺序介绍:一次只载一个关卡的栈式加载(LSR 资源压栈底),用小块气闸 (air lock) 区域实现基本无缝的过渡,再到把所有资产切成等大块、用块池分配器按关卡加载区域流送的细粒度方案(Naughty Dog);对象生成的内存问题有"不许运行时分配"、按尺寸分池、小内存分配器和内存重定位四种对策;存档则分检查点和随处存档(GEA4 卷 II 17.4)。

被这些页面引用1 篇

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原