盘点Godot实现存档的7种常用方案

合集 · Godot技术分享 (6)

  1. 10:25
    [教程]Godot程序式音频生成
  2. 19:40
    [Godot with c++]从零使用Scons构建GDExtension
  3. 7:29
    [教程]反编译杀戮尖塔2可执行文件到可运行项目
  4. 4:09
    Godot导出资源分包解决方案 GodotAssetBundle
  5. 10:01
    盘点Godot实现存档的7种常用方案
  6. 30:06
    使用 Godot 实现 BongoCat 桌宠
Description
本期视频分享UP主总结的在Godot中实现存档的几种方案。
以下是UP个人的视频内容笔记:

文本存储:ConfigFile ; JSON ; CSV ; XML
二进制存储:FileAccess ; ResourceSaver ; SQLite

## ConfigFile
ConfigFile 是 Godot 提供的一种对于INI格式 (也可以叫做CFG文件,叫法不一)解析的类。Godot支持将ini解析为原生类型。
格式结构:扁平键值 + 分组,无嵌套
到底用在哪:本地化数据,游戏设置数据

## JSON
全名:JS对象简朴 JavaScript Object Notation
是一种广泛、通用,轻量级的数据保存格式,Godot原生支持 JSON 文件的读写,支持直接解析为原生类型
格式结构:对象和数组,键值对
到底用在哪:全能

## CSV
全名:逗号分隔值 Comma-Separated Values
专门用于保存表格数据,Godot仅在 FileAccess 中提供 get_csv_line 方法,保存数据需要手动序列化。
格式结构:二维的表结构
到底用在哪:二维数据,内部配置文件

## XML
全名:可扩展标记语言 Extensible Markup Language
格式严谨,可以用于部分Web数据交互(现代互联网已经被JSON替代),体积较大,不适合用于用户存档,在游戏内部配置中(例如道具物品信息)不及Resource。
到底用在哪:游戏内部的配置文件,不过被 Resource 全方面替代。

## FileAccess二进制流式
Godot原生支持将内置类型序列化为二进制表达,通过FIleAccess store_* / get_* 读写,优势是原生/效率快,缺点是不直观,版本迭代极易导致数据损坏。
到底用在哪:原生数据的网络数据序列化(p2p联机)

## ResourceSaver
Godot原生支持将 Resource 类序列化为文件,支持 res/tres ; scn/tscn 格式。优势是保存读取非常便捷,缺点是版本迭代极易导致数据损坏,不推荐作为外部数据持久化。
到底用在哪:适合游戏内部的配置文件

## SQLite
数据库格式,适合保存和查询海量数据,如大世界游戏的NPC对话字段,海量单位的详细信息,适合中/大型游戏或者有大量数据的情况。
到底用在哪:海量查询

Comments

飞翔正义 2026-05-29

其实本质就是三种,godot资源类,写文件,写数据库。感觉用个专门的存档类最方便。

♥ 19

lowp0wer 2026-05-29

我来补充一个,用FileAccess存储字典,既有类json的格式又可以方便的保存读取

♥ 9

BDGGame 2026-05-30

cfg和ini有个问题,这东西只会从头开始读。有多个section分开读会从头开始读会报错,你想只读player2数据必须把player1数据也读了。 如果player1数据在player2数据前只读player2数据会报错找不到player2的section,然后把player1的第一个数据给player2的第一个数据。 只适合同时需要保存和读取的数据

♥ 6 ↩ 8

泽马克 2026-05-29

[打call]

♥ 6 ↩ 1

拥抱美好的一天1 2026-05-30

我还在玩你的铁匠铺传奇呢,太上头了[笑哭]

♥ 5

老猫队长 2026-05-30

Resource不适用存档,只有一个原因就是太简单,容易被人破解

♥ 4 ↩ 5

一个男孩啊 2026-05-30

主包,你的gdscript代码为什么,语句后面可以像c语言一样加分号 ; ?

♥ 4 ↩ 8

Narycap 2026-05-30

做的很好哎! 但是手机端字幕有点被进度条挡住了[笑哭]

♥ 4 ↩ 2

也能摘下星辰 2026-05-29

太好了,可惜我没时间学习,只能先收藏了[大哭]

♥ 4

黑博艾狼 2026-06-12

很好奇像我的世界这种地图数据储存应该怎么实现,每个方块位置和类型都要记下来吗

♥ 2 ↩ 2

洛御灵 2026-05-29

朱波朱波,你的方案确实很强。但还有没有更简单更不吃操作的方案可以推荐一下[doge] BV1VXW3e6Ejn

♥ 2 ↩ 2

hardcore_肥肥 2026-05-29

前排占座[doge]

♥ 2

゚゙゙゚゚゙ 28d ago

存档可以拆成多个吗,就是一个游戏存档对应多个文件

♥ 1 ↩ 1

一年四季五谷丰登 2026-06-12

up的教程就是小而精还实用,好评[打call]

♥ 1

卧地而笑 2026-05-30

Resource不太适合做存档,它的逻辑和bytes_to_var等内置的序列化逻辑不太一样,默认值不覆盖,导致你保存时的状态和读取后的状态可能不一样

♥ 1 ↩ 2

琴匠辞林 2026-05-30

所有方法都试过,最后选定了用FileAccess存读PackedByteArray数据,虽然一开始造轮子麻烦但后面能实现完整的所有功能。 比如可以实现单个文件的分段读取,比如只读取存在里面的文件介绍而不读取后面的大量数据,也可以把一张图片的数据写在最前面让它能作为一张图片在电脑上打开。 首先要把数据序列化,方法是用 JSON.stringify(JSON.from_native(data, object_enable), indent, false).to_utf8_buffer() 后面把读取的数据反序列化用的是 JSON.to_native(JSON.parse_string(bytes.get_string_from_utf8()), object_enable) 然后用FileAccess的store_buffer()存进去,取出来就用get_buffer(),在那之前还可以把序列化的数据加密和压缩,可以用 func _get_compressed_buffer(buffer: PackedByteArray) -> PackedByteArray: var compressed_buffer: PackedByteArray compressed_buffer.resize(8) compressed_buffer.encode_u64(0, buffer.size()) compressed_buffer.append_array(buffer.compress(_compression_mode)) return compressed_buffer 以及 func _get_decompressed_buffer(buffer: PackedByteArray) -> PackedByteArray: var buffer_size: int = buffer.slice(0, 8).decode_u64(0) return buffer.slice(8).decompress(buffer_size, _compression_mode)

♥ 1 ↩ 5

白菜叶_ 2026-05-29

[打call][支持]

♥ 1

成狐狐 2026-05-29

[星绘·沐春灼华 应援装扮_复活]

♥ 1

北庭大侠 2026-06-08

[神操作][神操作]

♥ 1

BDGGame 2026-05-30

复现了一下我的报错,up帮我看看是哪里出了问题。存档文件里保存有数据,一读到section2就报错

♥ 1 ↩ 9