ResourceSaver.save
2026/4/14大约 7 分钟
最后更新日期:2026-04-16
最后同步日期:2026-04-15 | Godot 官方原文 — ResourceSaver.save
ResourceSaver.save
定义
ResourceSaver.save 就像把你的游戏进度存到存档卡里——你手里有一个正在用的资源对象(比如一个配置、一个材质、一段数据),调用这个函数就能把它"打包"写入到硬盘上的文件中。下次需要的时候,再用 ResourceLoader.load 把它"拆包"读回来。
你可以把它想象成拍照保存:游戏中一个资源就像你面前的一个场景,ResourceSaver.save 就是按下快门,把当前状态保存成一张照片(文件)。之后你可以随时翻看这张照片(重新加载)来恢复当时的样子。
一句话总结
ResourceSaver.save 的作用是"把内存中的资源对象写入到磁盘文件",是实现存档系统、配置保存、资源编辑器等功能的基础。
函数签名
C#
public static Error Save(Resource resource, string path, uint flags = 0)GDScript
ResourceSaver.save(resource: Resource, path: String, flags: int = 0) -> int参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| resource | Resource | 是 | 要保存的资源对象。可以是任何继承自 Resource 的对象,如 Texture2D、Material、自定义数据类等 |
| path | string / String | 是 | 保存的目标文件路径,如 "res://saved_data.tres" 或 "user://save_game.tres"。文件扩展名决定了保存格式(见下方说明) |
| flags | uint / int | 否 | 保存标志位,控制保存行为(见下方说明) |
文件格式与扩展名
| 扩展名 | 格式 | 说明 |
|---|---|---|
.tres | 文本格式 | 人类可读的文本格式,类似 JSON/YAML,方便调试和版本控制 |
.res | 二进制格式 | 二进制格式,文件更小、加载更快,但不可人工阅读 |
.json | JSON 格式 | 仅适用于某些特定资源类型 |
保存标志(SaverFlags)
| 标志 | 值 | 说明 |
|---|---|---|
SaverFlags.None / FLAG_NONE | 0 | 默认,无特殊行为 |
SaverFlags.Relative / FLAG_RELATIVE_PATHS | 1 | 使用相对路径保存内部资源的引用 |
SaverFlags.BundleExternalResources / FLAG_BUNDLE_RESOURCES | 8 | 将外部引用的资源打包到一起 |
SaverFlags.ChangePath / FLAG_CHANGE_PATH | 32 | 保存时将资源的 ResourcePath 更新为目标路径 |
SaverFlags.OmitEditorProperties / FLAG_OMIT_EDITOR_PROPERTIES | 64 | 保存时省略编辑器专用的属性 |
SaverFlags.Merge / FLAG_REPLACE_SUBRESOURCE_PATHS | 128 | 保存时替换子资源的路径 |
返回值
| 类型 | 说明 |
|---|---|
| Error (C#) / int (GDScript) | 返回 Error.Ok(值为 0)表示保存成功;返回其他错误码表示失败(如路径无效、权限不足等) |
代码示例
基础用法
最简单的用法——创建一个自定义资源并保存到文件:
C#
using Godot;
public partial class SaveDemo : Node
{
public override void _Ready()
{
// 创建一个自定义资源
var material = new StandardMaterial3D();
material.AlbedoColor = new Color(1.0f, 0.0f, 0.0f); // 红色
material.Metallic = 0.8f;
// 保存到文本格式的 .tres 文件
Error result = ResourceSaver.Save(material, "res://saved_material.tres");
if (result == Error.Ok)
{
GD.Print("材质保存成功!");
// 运行结果: 材质保存成功!
}
else
{
GD.PrintErr("保存失败,错误码: " + result);
}
}
}GDScript
extends Node
func _ready() -> void:
# 创建一个自定义资源
var material = StandardMaterial3D.new()
material.albedo_color = Color(1.0, 0.0, 0.0) # 红色
material.metallic = 0.8
# 保存到文本格式的 .tres 文件
var result = ResourceSaver.save(material, "res://saved_material.tres")
if result == OK:
print("材质保存成功!")
# 运行结果: 材质保存成功!
else:
push_error("保存失败,错误码: %d" % result)实际场景
在实际游戏开发中,ResourceSaver.save 最常用于保存游戏配置或玩家数据。下面的例子展示了一个简单的游戏设置保存/加载系统:
C#
using Godot;
// 自定义资源类,用于保存游戏设置
[GlobalClass]
public partial class GameSettings : Resource
{
[Export] public float ExMasterVolume = 1.0f;
[Export] public float ExMusicVolume = 0.8f;
[Export] public float ExSfxVolume = 1.0f;
[Export] public bool ExFullscreen = false;
[Export] public int ExResolutionWidth = 1920;
[Export] public int ExResolutionHeight = 1080;
}
public partial class SettingsManager : Node
{
private const string SettingsPath = "user://game_settings.tres";
private GameSettings _settings;
public override void _Ready()
{
// 尝试加载已有设置,不存在则创建默认设置
if (ResourceLoader.Exists(SettingsPath))
{
_settings = ResourceLoader.Load<GameSettings>(SettingsPath);
GD.Print("已加载设置文件");
}
else
{
_settings = new GameSettings();
GD.Print("使用默认设置");
}
// 修改设置并保存
_settings.ExMasterVolume = 0.7f;
_settings.ExFullscreen = true;
SaveSettings();
ApplySettings();
}
public void SaveSettings()
{
Error result = ResourceSaver.Save(_settings, SettingsPath);
if (result == Error.Ok)
{
GD.Print("设置已保存到: " + SettingsPath);
// 运行结果: 设置已保存到: user://game_settings.tres
}
else
{
GD.PrintErr("设置保存失败: " + result);
}
}
private void ApplySettings()
{
GD.Print($"当前设置: 音量={_settings.ExMasterVolume}, 全屏={_settings.ExFullscreen}");
// 运行结果: 当前设置: 音量=0.7, 全屏=True
}
}GDScript
# 自定义资源类,用于保存游戏设置
class_name GameSettings
extends Resource
@export var ex_master_volume: float = 1.0
@export var ex_music_volume: float = 0.8
@export var ex_sfx_volume: float = 1.0
@export var ex_fullscreen: bool = false
@export var ex_resolution_width: int = 1920
@export var ex_resolution_height: int = 1080进阶用法
使用自定义 Resource 类保存复杂的游戏存档数据,包括背包物品、角色状态等:
C#
using Godot;
using System.Collections.Generic;
// 存档数据资源
[GlobalClass]
public partial class SaveData : Resource
{
[Export] public string ExPlayerName = "Player";
[Export] public int ExLevel = 1;
[Export] public float ExHealth = 100f;
[Export] public Godot.Collections.Array< string> ExInventory = new();
[Export] public Vector2 ExPlayerPosition = Vector2.Zero;
[Export] public string ExCurrentScene = "";
}
public partial class SaveSystem : Node
{
private const string SaveDir = "user://saves/";
private const string SaveFile = "save_slot_1.tres";
public override void _Ready()
{
// 创建一个新的存档
var saveData = new SaveData
{
ExPlayerName = "勇者小明",
ExLevel = 5,
ExHealth = 85.5f,
ExPlayerPosition = new Vector2(120.0f, 340.0f),
ExCurrentScene = "res://scenes/dungeon_level_3.tscn"
};
// 添加背包物品
saveData.ExInventory.Add("铁剑");
saveData.ExInventory.Add("治疗药水 x3");
saveData.ExInventory.Add("魔法卷轴");
// 保存存档
string fullPath = SaveDir + SaveFile;
Error result = ResourceSaver.Save(saveData, fullPath);
if (result == Error.Ok)
{
GD.Print("存档保存成功!");
GD.Print($" 角色名: {saveData.ExPlayerName}");
GD.Print($" 等级: {saveData.ExLevel}");
GD.Print($" 血量: {saveData.ExHealth}");
GD.Print($" 位置: {saveData.ExPlayerPosition}");
GD.Print($" 背包物品数: {saveData.ExInventory.Count}");
// 运行结果:
// 存档保存成功!
// 角色名: 勇者小明
// 等级: 5
// 血量: 85.5
// 位置: (120, 340)
// 背包物品数: 3
}
else
{
GD.PrintErr("存档保存失败: " + result);
}
// 验证:重新加载存档
if (ResourceLoader.Exists(fullPath))
{
var loaded = ResourceLoader.Load<SaveData>(fullPath);
GD.Print("存档验证 - 角色名: " + loaded.ExPlayerName);
// 运行结果: 存档验证 - 角色名: 勇者小明
}
}
}GDScript
# 存档数据资源
class_name SaveData
extends Resource
@export var ex_player_name: String = "Player"
@export var ex_level: int = 1
@export var ex_health: float = 100.0
@export var ex_inventory: Array[String] = []
@export var ex_player_position: Vector2 = Vector2.ZERO
@export var ex_current_scene: String = ""注意事项
- 只有
Resource的子类才能保存:你要保存的对象必须继承自Resource。普通的Node、Control等节点不能直接用ResourceSaver.save保存。如果需要保存节点状态,应该把数据提取到一个自定义Resource类中。 - 路径决定了保存格式:
.tres是文本格式(推荐调试时用),.res是二进制格式(推荐发布时用,更小更快)。 res://路径在导出后通常是只读的:保存玩家数据时,应该使用user://路径,因为res://在导出的游戏中通常是只读的(被打包进了.pck文件中)。- 自定义 Resource 类需要
[GlobalClass]:C# 中自定义的 Resource 子类需要加上[GlobalClass]特性,Godot 才能在保存和加载时正确识别类型。 - 保存前确保目录存在:如果保存路径中的目录不存在,保存会失败。建议在保存前用
DirAccess.MakeDirRecursiveAbsolute()创建必要的目录。 - 引用关系会自动保存:如果你的 Resource 引用了其他 Resource(比如材质引用了纹理),
ResourceSaver会自动处理这些引用关系,确保加载时能正确恢复。 - C# 差异:C# 中方法名用 PascalCase(
Save),GDScript 中用 snake_case(save)。C# 返回Error枚举,GDScript 返回int(用OK常量判断成功)。
