unity实现存档系统

如今,几乎所有游戏都具备存档功能,这成为了游戏中不可或缺的重要特性。然而,存档功能的实现并不神秘,它是通过将游戏中的数据保存到硬盘上的文件中,以便在下次进入游戏时能够读取这些数据,从而实现玩家能够继续游戏的功能。

在游戏开发中,通常会选择一种数据格式(如JSON、XML或二进制)将数据写入文件中。本文将以JSON格式作为存储数据的示例,因为它易于阅读和编辑。

由于存档内容通常不会单一,而且可能存在多个存档文件,因此我们需要一种通用的方法来管理存档。通过接口,我们可以实现多态性,使得不同的类能够以统一的方式进行存档操作。

接下来,我们将介绍如何通过接口来实现存档功能。通过接口调用函数的形式,不同的类可以实现不同的存档逻辑。

public interface IArchive
{
    void Save();
    void Load();
}

然后通过存档管理器来统一管理

	public class ArchiveSystem
    {
        protected static Dictionary<string, List<IArchive>> saves = new();
        protected static Dictionary<IArchive, List<string>> saveIndex = new();
        /// <summary>
        /// 存档
        /// </summary>
        /// <param name="key">存档任务的索引</param>
        /// <param name="name">发出存档指令的物体</param> 
        public static void SaveData(string key, string name = "")
        {
            if (!saves.ContainsKey(key))
            {
                Debug.LogWarning($"存档任务<{name}>使用错误索引<{key}>");
                return;
            }
            foreach (var item in saves[key])
            {
                try
                {
                    item.Save();
                }
                catch(System.Exception e)
                {
                    Debug.LogError($"存档任务<{name}>存档失败:{e.Message}");
                }
            }
        }
        /// <summary>
        /// 读档
        /// </summary>
        /// <param name="key">读档任务的索引</param>
        /// <param name="name">发出读档任务的物体</param>
        public static void LoadData(string key, string name = "")
        {
            if (!saves.ContainsKey(key))
            {
                Debug.LogWarning($"读档任务<{name}>使用错误索<{key}>");
                return;
            }
            foreach (var item in saves[key])
            {
                try
                {
                    item.Load();
                }
                catch (System.Exception e)
                {
                    Debug.LogError($"读档任务<{name}>读档失败:{e.Message}");
                }
            }
        }
        /// <summary>
        /// 增加任务
        /// </summary>
        /// <param name="key">任务索引</param>
        /// <param name="archive">存档接口</param>
        /// <param name="name">发出任务的物体</param>
        /// <param name="isAllowRepeat">是否允许重复在不同任务添加</param>
        /// <param name="isCheck">是否检查在同一任务重复添加</param>
        public static void AddTask(string key, IArchive archive, string name = "", bool isAllowRepeat = false, bool isCheck = false)
        {
            if (!isAllowRepeat && saveIndex.ContainsKey(archive) && saveIndex[archive].Count > 1)
            {
                string message = string.Join(",", saveIndex[archive]);
                Debug.LogError($"对于<{name}>存档接口<{archive}>已存在于任务<{message}>中");
                return;
            }
            if (isCheck && saveIndex[archive].Find(value =>
            {
                return value == key;
            }) != null)
            {
                Debug.LogError($"对于<{name}>存档接口<{archive}>已存在于任务<{key}>中");
                return;
            }
            if (!saves.ContainsKey(key))
            {
                saves.Add(key, new List<IArchive>());
            }
            saves[key].Add(archive);

            if (!saveIndex.ContainsKey(archive))
            {
                saveIndex.Add(archive, new List<string>());
            }
            saveIndex[archive].Add(key);

            string sd = string.Join(",", saveIndex[archive]);
            if (isAllowRepeat)
            {
                Debug.LogWarning($"存档接口<{archive}>已添加到任务<{key}>中,当前任务列表为<{sd}>");
            }
        }
        /// <summary>
        /// 对所有任务进行存档
        /// </summary>
        public static void SaveAll(string name)
        {
            Debug.LogWarning($"<{name}>发起全部存档命令");
            foreach (var item in saves)
            {
                SaveData(item.Key);
            }
        }
        /// <summary>
        /// 加载所有读档任务
        /// </summary>
        public static void LoadAll(string name)
        {
            Debug.LogWarning($"<{name}>发起全部读档命令");
            foreach (var item in saves)
            {
                LoadData(item.Key);
            }
        }
        public static void ClearAll(string name)
        {
            Debug.LogWarning($"<{name}>发起全部清除存档命令");
            saves.Clear();
        }
        public static void RemoveTask(string key, IArchive archive, string name)
        {
            Debug.LogWarning($"<{name}>发出从任务<{key}>中移除存档接口<{archive}>的命令");
            if (saves.ContainsKey(key))
            {
                saves[key].Remove(archive);
            }
        }
    }

然后实现两个测试类

public class Test1: MonoBehaviour,IArchive
{
    private void Start()
    {
        ArchiveSystem.AddTask("测试", this);
    }
    public void Save()
    {
        Debug.Log("存档1");
    }

    public void Load()
    {
        Debug.Log("读档1");
    }
}
public class Test2 : MonoBehaviour,IArchive
{
    private void Start()
    {
        ArchiveSystem.AddTask("测试", this);
    }
    public void Save()
    {
        Debug.Log("存档2");
    }

    public void Load()
    {
        Debug.Log("读档2");
    }
}

将Test1与Test2分别挂载到Objet1与Object2物体,然后新建GameTest脚本

public class GameTest : MonoBehaviour
{
    [ContextMenu("测试存档功能")]
    public void SaveTest()
    {
        ArchiveSystem.SaveData("测试");
        
    }
    [ContextMenu("测试读档功能")]
    public void LoadTest()
    {
        ArchiveSystem.LoadData("测试");
    }
}

挂载到Test物体,点击按钮,结果如图

改写Test1脚本,如下

public class Test1 : MonoBehaviour, IArchive
{
    private void Start()
    {
        ArchiveSystem.AddTask("测试", this);
    }
    public void Save()
    {
        string data = JsonUtility.ToJson(transform.position);
        File.WriteAllText("./test.json", data);
        Debug.Log("存档1" + data);
    }

    public void Load()
    {
        string data = File.ReadAllText("./test.json");

        transform.position = JsonUtility.FromJson<Vector3>(data); ;
        Debug.Log("读档1" + data);
    }
}

运行,效果如下

可以看到,存档系统正常工作。另外需要特别提示的一点是,存档系统相对较为消耗性能。因此,务必避免将存档相关的函数调用写入到游戏的Update方法中,最好是在必要时进行调用,而且尽量保证一个关键操作只调用一次。这样可以有效地降低存档操作对游戏性能的影响,确保游戏的流畅运行。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值