游戏开发分享

[Godot] C# 使用Resource类实现保存功能

2025-03-11
1 分钟200 字

创建场景

我创建了一个简单的场景,有一个文本,和两个按钮

我给他绑定了一个脚本,以显示金钱数量,和金钱增加按钮,点一下增加一块钱

scene.cs

using Godot;
using System;
 
public partial class scene : Node2D
{
    private int Money;
    private Label T_Money;
 
    public override void _Ready()
    {
        T_Money = GetNode<Label>("./money");
    }
 
    public override void _Process(double delta)
    {
        T_Money.Text = $"Money:{Money}";
    }
 
    public void AddMoney()
    {
        Money++;
    }
}

实现效果


创建保存脚本

要实现保存的功能,有一个简单的办法,就是用Resource类,我们新建一个脚本,继承自Resource

在这个脚本里面写出来要保存的数据,例如我这个场景的金钱

using Godot;
using System;
 
public partial class SaveDate : Resource
{
    [Export] public int money = new int();
}

在scene脚本中,我们新建一个string字符串变量,作为存档位置

private string SavePath = "user://save.tres";

注意,这个路径是用户路径,位置在

C:\Users\用户名\AppData\Roaming\Godot\app_userdata\项目名

你也可以设置为 res:// 来保存在项目资源位置,但是只能在项目开发时使用,打包发布后就不能保存了

这里我们保存的后缀名是.tres,为了方便查看,也可以保存成.res文件,就加密了,或者你也可以保存为其他格式,如json等

保存函数

void SaveGame()
    {
        SaveDate saveDate;
        if (!FileAccess.FileExists(SavePath))
        {
            GD.Print("角色文件不存在,正在创建");
            saveDate = new SaveDate();
        }
        else
        {
            saveDate = ResourceLoader.Load<SaveDate>(SavePath);
        }
        saveDate.money = Money;
        ResourceSaver.Save(saveDate, SavePath);
    }

大家看代码就能明白,我们先声明了存档类的对象,然后判断存档文件是否存在,没有的话就建个新的,有的话就加载,之后就对这个对象赋上值,最后再保存即可

我们在Ready函数内调用一下SaveGame函数,然后运行一下场景,去路径上的文件夹找找看

我们找到了这个保存的文件,里面确实有了一个money变量


加载函数

至于加载存档,我们可以再写个LoadGame函数

bool LoadGame()
    {
        if (!FileAccess.FileExists(SavePath))
        {
            GD.Print("存档文件不存在,无法加载。");
            return false;
        }
 
        var saveDate = ResourceLoader.Load<SaveDate>(SavePath);
 
        if (saveDate == null)
        {
            GD.Print("加载存档失败");
            return false;
        }
 
        Money = saveDate.money;
 
        return true;
    }

之后我们可以在Ready函数里面写一下初始化调用的代码

if (LoadGame())
{
    GD.Print("人物加载成功");
}
else
{
    SaveGame();
}

现在我们运行场景,可以正确的保存和加载数据了


注意

频繁进行保存和读取操作会出问题,报错,尽量避免频繁读取,而且保存代码可以优化一下,可以设置为空闲时调用保存操作(CallDeferred方法)

void SaveGame()
    {
        SaveDate saveDate;
        if (!FileAccess.FileExists(SavePath))
        {
            GD.Print("角色文件不存在,正在创建");
            saveDate = new SaveDate();
        }
        else
        {
            saveDate = ResourceLoader.Load<SaveDate>(SavePath);
        }
        saveDate.money = Money;
        CallDeferred(nameof(SaveToFile),saveDate);
    }
void SaveToFile(SaveDate data)
    {
        ResourceSaver.Save(data, SavePath);
        GD.Print("保存完成");
    }

其他

如果我们想保存更复杂的数据,像自定义类字典或者数组什么的,可以按照下面的来做

比如我们要实现物品列表的话,自定义一个物品类,键就作为物品ID,里面写比如数量、描述等变量,在存档数据脚本内可以这么写

[Export] public Godot.Collections.Dictionary<int,类名> items = new Godot.Collections.Dictionary<int,类名>();

之后调用的时候就可以很方便的调用和修改了

许可协议: CC BY-SA 4.0 。转载请注明出处,允许商用;改编/转载须以相同许可(CC BY-SA 4.0)发布。如有问题请联系我。