Project AS Developer Doc Help

第5章 游戏状态管理与存档机制(State & Save)

游戏状态管理系统负责在运行期维护玩家当前的世界状态,并提供完整的保存与加载机制,以支撑断点恢复、多存档、成就统计与分支记忆功能。本项目采用多 Binary 文件组合的文件夹式结构进行存档管理,增强数据安全性、模块独立性与防篡改能力。

5.1 游戏状态模型

运行期游戏状态由 GameState 对象统一管理,涵盖以下核心模块:

[Serializable] public class GameState { public int currentDay; public Dictionary<ResourceType, int> resourceAmount; public List<FacilityInstanceData> facilities; public List<ResidentData> residents; public List<QuestState> questStates; public List<string> completedTechIds; public Dictionary<FactionType, float> factionRatios; public string currentResearchTechId; public string currentMainlineQuestId; public NarrativeState narrativeState; public GameEndingState endingState; }

各子系统应在状态更新时将相关信息同步至 GameState 中,由 GameSaveManager 定时保存或响应玩家存档请求。

5.2 存档结构定义与存取方式(Binary 文件夹式结构)

存档格式设计原则:

  • 模块解耦存储:每类数据单独存入一个二进制文件

  • 文件夹结构:每个存档为一个文件夹,包含多个 .bin 文件和可选 meta 文件

  • 写入分步骤:支持增量保存、分模块读取

  • 支持加密压缩:防止玩家恶意修改存档内容

示例存档结构:

/Saves/Save_001/ meta.json // 存档元信息(时间戳、版本、备注等) core.bin // 当前天数、结局状态、主任务ID等 resources.bin // 所有资源状态(类型与数值) residents.bin // 居民列表与状态 facilities.bin // 已建成/建造中设施状态 quests.bin // 所有任务进度与完成状态 techs.bin // 已解锁科技节点列表 narrative.bin // 剧情执行记录与选项结果

5.3 存档数据序列化方案(写入与还原流程)

项目推荐使用 Unity 自带的 BinaryFormatter (或安全性更高的 MessagePackOdinSerializer )进行分文件存储。

写入逻辑(示例):

public static void SaveToBinary<T>(string path, T data) { using (FileStream fs = new FileStream(path, FileMode.Create)) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(fs, data); } } public static void SaveGame(string saveFolderPath) { Directory.CreateDirectory(saveFolderPath); SaveToBinary(Path.Combine(saveFolderPath, "core.bin"), coreState); SaveToBinary(Path.Combine(saveFolderPath, "resources.bin"), GameState.resourceAmount); SaveToBinary(Path.Combine(saveFolderPath, "residents.bin"), GameState.residents); ... }

读取逻辑(示例):

public static T LoadFromBinary<T>(string path) { using (FileStream fs = new FileStream(path, FileMode.Open)) { BinaryFormatter formatter = new BinaryFormatter(); return (T)formatter.Deserialize(fs); } } public static void LoadGame(string saveFolderPath) { GameState.resourceAmount = LoadFromBinary<Dictionary<ResourceType, int>>(Path.Combine(saveFolderPath, "resources.bin")); GameState.residents = LoadFromBinary<List<ResidentData>>(Path.Combine(saveFolderPath, "residents.bin")); ... }

5.4 与配置数据(ScriptableObject)的解耦

为保持版本兼容与数据稳定性,存档仅保存配置项的 唯一 ID ,运行时通过 DataManager 引用实际数据:

// 存档中保存: facilityConfigId = "FAC_RESEARCH_02"; // 运行时加载: var config = DataManager.Instance.GetFacilityConfig(facilityConfigId);

避免在存档中直接序列化 ScriptableObject 或其字段引用。

下一章将进入《模块交互机制》,介绍事件系统与数据传递结构的统一通信策略。

15 七月 2025