尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Godot 多存档槽存档系统:4 个动作 + 自动备份的完整实现

Godot 多存档槽存档系统:4 个动作 + 自动备份的完整实现 Godot 多存档槽存档系统:4 个动作 自动备份的完整实现【免费下载链接】godotGodot Engine – Multi-platform 2D and 3D game engine项目地址: https://gitcode.com/GitHub_Trending/go/godot进程在第 10 小时崩溃,唯一的存档写了一半,进度归零——这是单槽存档最真实的损失。本文基于 Godot Engine 实现一套多存档槽存档系统:5 个槽位独立读写,覆盖前自动生成时间戳备份。读完你能在自己的工程里跑通存档、读取、擦除、恢复四个动作。先见全貌:一个目录树,四个动作布局约定只有一条:每个槽位是一个独立目录,主数据、元数据、备份全部放在槽位内部,工程里不存在全局索引文件。user://saves/ ├── slot_0/ │ ├── data.json # 游戏状态,唯一事实来源 │ ├── meta.json # 槽位元数据:修改时间、游玩时长 │ └── backup/ │ └── data_1756351200.json # 覆盖前的时间戳快照 └── slot_1/ … slot_4/存档、读取、擦除、备份四个动作都发生在slot_N目录内:写入前把旧档快照进backup/,读取以data.json为准、损坏时回退快照,擦除直接移除整个目录。元数据跟着槽位走,就不存在索引与槽位对不上的问题。写入与读取:Godot 多存档实现的两个核心动作写入存档:先备份,后覆盖要解决的问题:直接覆盖data.json,断电或崩溃会在槽位里留下半截 JSON,旧档又已被覆盖,没有回头路。 做法:固定备份旧档 → 写新档 → 更新元数据三步,顺序不可调换。管理器写成普通类SaveStore(继承RefCounted),由游戏自己持有实例,不引入单例;序列化交给 JSON,文件句柄交给 FileAccess。class_name SaveStore extends RefCounted const SAVE_ROOT : user://saves func save_to_slot(slot: int, state: Dictionary) - bool: var dir : %s/slot_%d % [SAVE_ROOT, slot] DirAccess.make_dir_recursive_absolute(dir) var data_path : dir.path_join(data.json) snapshot_before_write(data_path) # 旧档先归档到 backup/ var file : FileAccess.open(data_path, FileAccess.WRITE) if file null: return false file.store_string(JSON.stringify(state, \t)) file.close() write_meta(dir, state) return truestringify第二参数给\t缩进,坏档落盘后能肉眼定位断点。读取存档:先验证,后取值要解决的问题:半截 JSON 或缺字段的旧版本存档,直接取值必然出错。JSON.parse_string对非法输入返回 null,这是现成的第一道闸。 做法:存在性检查 → 类型检查 → 版本迁移,三步缺一不可;主档损坏时自动取backup/中时间戳最大的一份,玩家无感知。func load_slot(slot: int) - Dictionary: var dir : %s/slot_%d % [SAVE_ROOT, slot] if not DirAccess.dir_exists_absolute(dir): return {} var parsed JSON.parse_string(_read_file(dir.path_join(data.json))) if not (parsed is Dictionary) or parsed.is_empty(): parsed restore_latest_backup(dir) # 主档损坏,回退最新快照 if parsed is Dictionary: return migrate(parsed) # 老版本存档就地升级 return {}migrate按version字段逐级升级,不要在加载函数里散落 if 判断。擦除与备份:让槽位可删、可悔擦除槽位:连元数据一起删要解决的问题:只删data.json,目录还在,存档界面会把空槽渲染成可用,元数据与实际内容脱节。 做法:擦除的单位是目录而不是文件,meta.json和backup/随目录一起消失,无需同步任何外部索引。func wipe_slot(slot: int) - bool: var dir : %s/slot_%d % [SAVE_ROOT, slot] if not DirAccess.dir_exists_absolute(dir): return true # 空槽位视为已删除 var err : DirAccess.remove_recursive_absolute(dir) if err ! OK: push_warning(slot_%d 删除失败,错误码 %d % [slot, err]) return false return true目录操作走 DirAccess 的静态方法,不需要先 open 再逐个遍历。时间戳自动备份:8 行代码留下恢复机会要解决的问题:玩家在槽位上反复试错,或某次写入本身有 bug,覆盖一旦发生,旧状态永久消失。 做法:每次覆盖前,把当前data.json复制成backup/data_时间戳.json;每槽只保留最近 8 份,超出的按时间戳从旧到新删除,目录不膨胀。func snapshot_before_write(data_path: String) - void: if not FileAccess.file_exists(data_path): return var backup_dir : data_path.get_base_dir().path_join(backup) DirAccess.make_dir_recursive_absolute(backup_dir) var dest : backup_dir.path_join(data_%d.json % OS.get_unix_time()) FileAccess.copy(data_path, dest) prune_backups(backup_dir, 8) # 只保留最近 8 份快照陷阱与边界:坏档、迁移、路径、权限⚠️ 数据损坏:parse_string的结果取值前先过is Dictionary检查;主档损坏时回退backup/最新快照,并告知玩家发生过回退。版本迁移:data.json固定带version字段,加载时按版本号逐级升级;不要靠缺哪个字段猜版本。跨平台路径:统一user://前缀,路径拼接一律用path_join,不手写绝对路径和反斜杠。移动端权限:Android、iOS 限制沙盒外写入;user://目录由引擎代管,无需额外申请运行时权限。时钟篡改:OS.get_unix_time()读的是系统时间,玩家回拨时钟会让备份文件名冲突;用进程内自增序号拼接时间戳保唯一。进阶优化:异步、压缩、加密、同步异步保存:FileAccess写盘是同步阻塞,大存档会卡帧;stringify留主线程,写入丢给Thread,线程内只碰字符串与文件,不碰场景树。数据压缩:大库存、大地图存档先用 ZSTD 压成二进制再落盘,读取端解压后再交JSON.parse_string,体积通常降到 1/3。 加密保护:落盘前用 Crypto 做对称加密,防玩家手改数值;密钥不要硬编码在脚本里。云同步:起步阶段用 HTTP 客户端把data.json上传服务器即可;冲突按最新时间戳胜出 本地备份可回滚处理,别一上来做复杂合并。存档系统是否可靠,只看一条路径:坏档能不能被恢复。回到工程里先跑通一次存档→杀掉进程→重新读取,以backup/中出现第一份快照作为验收标准。【免费下载链接】godotGodot Engine – Multi-platform 2D and 3D game engine项目地址: https://gitcode.com/GitHub_Trending/go/godot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表