Wiki
978 words
5 minutes
Next
Updated 2025-11-27

使用前置声明的意义#

为了不编入头文件,加快编译速度

UPROPERTY#

存档相关字段如果需要被系统识别,通常会显式配上 SaveGame 说明符。

例如:

UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame)
int32 PlayerLevel = 1;

这能让数据边界更清晰,也方便后面排查“为什么这个字段没有被保存”。

USaveGame#

想要进行存档的话。需要创建一个新的类继承于该类。

Unity存档方式#

存档方式是使用PlayerPrefs,用KV值来进行存档

Unreal存档方式#

整个继承自 USaveGame 的类进行存档。

UGamePlayStatics#

调用SaveGame并选择槽位进行保存

常用入口主要是:

  • CreateSaveGameObject
  • SaveGameToSlot
  • LoadGameFromSlot
  • DoesSaveGameExist
  • DeleteGameInSlot

切换关卡#

UGameplayStatics::OpenLevel(this, FName("MapName"))

UUserWidget#

存档 UI 一般会交给 UUserWidget 处理,例如:

  • 存档列表
  • 覆盖存档确认框
  • 保存中提示
  • 读取失败提示

Next#

SubSystem

存档系统要解决什么问题#

真正的存档系统,不只是“把一个对象写进磁盘”,而是要明确:

  • 什么数据该存
  • 什么数据不该存
  • 什么时候存
  • 切关时数据怎么流转

如果这四件事不提前设计,后面就会变成哪里需要就往 SaveGame 里硬塞。

数据边界#

我更倾向于把数据分成三层:

  • 全局持久数据:玩家档案、设置、已解锁内容
  • 当前流程数据:当前关卡进度、任务状态、临时资源
  • 纯运行时数据:缓存、UI 状态、临时引用,不应该进存档

只有前两类才值得考虑写入 USaveGame

USaveGame 的职责#

USaveGame 适合充当“磁盘落地格式”,而不是整个存档系统的入口。

它负责:

  • 承载可序列化的数据
  • 作为 UGameplayStatics::SaveGameToSlot 的对象
  • 在加载时恢复成内存中的基础数据

建议把真正的“存档流程控制”交给更高一层的管理器,例如 GameInstanceSubsystemGameInstance

槽位设计#

槽位至少要想清楚三件事:

  • 存档名怎么命名
  • 一个用户是否允许多个档位
  • 是否区分自动存档和手动存档

常见做法:

  • Profile_01
  • Profile_01_Auto
  • Profile_01_Checkpoint

如果后期要做 UI 列表,还要同步保存:

  • 关卡名
  • 存档时间
  • 玩家等级或核心摘要信息

保存流程#

一个比较稳的保存流程通常是:

  1. 从各系统收集可持久化数据
  2. 写入自定义 USaveGame
  3. 调用 UGameplayStatics::SaveGameToSlot
  4. 成功后更新 UI 或存档元数据

如果项目里数据较多,建议用异步保存,避免在切关或战斗中卡顿。

异步保存#

异步保存的价值主要在于减少主线程卡顿,尤其是:

  • 存档体积变大时
  • 要保存大量状态时
  • 平台 IO 较慢时

设计时要注意:

  • 保存期间 UI 给出反馈
  • 不要让同一槽位被并发覆盖
  • 失败时要有重试或提示逻辑

跨关卡数据流#

切关时最容易混淆的,是“当前关卡状态”和“全局持久状态”的边界。

一个常见链路是:

  1. 关卡内系统把状态汇总到管理器
  2. 管理器写入 USaveGame
  3. 执行 OpenLevel
  4. 新关卡加载后,从存档或 GameInstance 恢复状态

所以 USaveGame 是磁盘层,GameInstance / Subsystem 更像运行时桥接层。

Blueprint 和 C++ 的分工#

比较合理的分工通常是:

  • C++:定义数据结构、存档读写入口、版本兼容处理
  • Blueprint:存档按钮、UI 反馈、简单展示逻辑

如果把整个存档系统都堆在蓝图里,后面做版本升级和字段迁移会很痛苦。

经验#

  • 不要直接把 Actor 引用原样存进去,通常要转成 ID、名称或结构化快照
  • 字段要明确哪些带 SaveGame
  • 存档对象是“数据镜像”,不是运行时世界本体
  • 越早定义边界,后面越不容易炸
Next
https://fuwari.vercel.app/wiki/unreal/存档系统/
Author
Qingswe
Published at
2025-11-27
License
CC BY-NC-SA 4.0