【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解

简介: 【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解

前言

如何在 Unity 中正确制作一个保存和加载系统,该系统使用JSON 文件来处理保存配置文件,可以保存和加载任何类型对象!标题为什么叫小型游戏存储功能呢?因为该存储功能可能只适合存储数据比较单一的情况,它非常的方便快捷,且易于使用和理解。但是如果你的游戏要存储的内容有很多,比如很多怪物的状态,很多宝箱的状态,很多物品的状态,那么它可能就不适用了。但是不用担心,后续我还会针对大型游戏,出更加复杂和全面的存储系统,解决存储数据比较多的情况。

存储

新增SaveProfile保存配置文件的泛型类和SaveProfileData抽象基类

[System.Serializable]
// 保存配置文件的泛型类
public sealed class SaveProfile<T> where T : SaveProfileData
{
    // 保存配置文件的名称
    public string name;
    // 实际保存的数据
    public T saveData;

    // 私有的默认构造函数,防止无参数实例化
    private SaveProfile() { }

    // 公共构造函数,用于初始化名称和保存数据
    public SaveProfile(string name, T saveData)
    {
        this.name = name;
        this.saveData = saveData;
    }
}

// 抽象基类,用于保存数据
public abstract record SaveProfileData {}

新增SaveManager,定义读取和存储 删除存档文件方法

using System;
using System.IO;
using UnityEngine;
using Newtonsoft.Json;

public static class SaveManager
{
    // 文件保存的根目录路径
    private static readonly string saveFolder = Application.persistentDataPath + "/GameData";

    // 删除指定存档文件
    public static void Delete(string profileName)
    {
        if (!File.Exists($"{saveFolder}/{profileName}"))
            throw new Exception($"保存配置文件 {profileName} 未找到!");

        Debug.Log($"已成功删除 {saveFolder}/{profileName}");
        File.Delete($"{saveFolder}/{profileName}");
    }

    // 加载指定类型的存档文件
    public static SaveProfile<T> Load<T>(string profileName) where T : SaveProfileData
    {
        if (!File.Exists($"{saveFolder}/{profileName}"))
            throw new Exception($"保存配置文件 {profileName} 未找到!");

        // 读取文件内容为字符串
        var fileContents = File.ReadAllText($"{saveFolder}/{profileName}");
        // TODO:解密

        Debug.Log($"已成功加载 {saveFolder}/{profileName}");

        // 反序列化为指定类型的SaveProfile<T>对象并返回
        return JsonConvert.DeserializeObject<SaveProfile<T>>(fileContents);
    }

    // 保存指定类型的存档数据
    public static void Save<T>(SaveProfile<T> save) where T : SaveProfileData
    {
        if (File.Exists($"{saveFolder}/{save.name}")){
            // throw new Exception($"保存配置文件 {save.name} 未找到!");
            Delete(save.name);
        }

        // 将SaveProfile<T>对象序列化为JSON格式的字符串
        var jsonString = JsonConvert.SerializeObject(save, Formatting.Indented,
            new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
        // TODO:加密

        if (!Directory.Exists(saveFolder))
            Directory.CreateDirectory(saveFolder);

        // 将加密后的jsonString写入文件
        File.WriteAllText($"{saveFolder}/{save.name}", jsonString);
    }
}

使用

新增SaveData.cs,定义需要存储的数据,如果需要其他数据需要再添加

using UnityEngine;

// 玩家保存数据
public record PlayerSaveData : SaveProfileData
{
    // 玩家位置
    public Vector2 position;
    // 成就数组
    public int[] achievements;
}

// 世界保存数据
public record WorldSaveData : SaveProfileData
{
    // 方块二维数组
    public int[,] blocks;
}

新增Player ,保存测试数据和读取

public class Player : MonoBehaviour
{
    void Start()
    {
        Debug.Log(Application.persistentDataPath);

        // 保存玩家数据
        var playerSave = new PlayerSaveData
        {
            position = new Vector2(1f, 1.5f),
            achievements = new[] { 1, 2, 3, 4, 5 }
        };
        var saveProfile = new SaveProfile<PlayerSaveData>("playerSaveData", playerSave);
        SaveManager.Save(saveProfile);

        //保存世界数据
        var worldSave = new WorldSaveData
        {
            blocks =new[,] { {1,1}, {1,2}, {1,3}}        
        };
        var saveProfile2 = new SaveProfile<WorldSaveData>("WorldSaveData", worldSave);
        SaveManager.Save(saveProfile2);
    }

    void Update()
    {
        //读取数据
        if (Input.GetKeyDown(KeyCode.E))
        {
            Vector2 position = SaveManager.Load<PlayerSaveData>("playerSaveData").saveData.position;
            Debug.Log(position);
            transform.position = position;
        }
    }
}

运行之后,可以去查看保存的文件数据

运行按E成功加载数据

看到这里你应该就明白为什么叫小型游戏存储功能了吧!

目录
相关文章
|
2天前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
11 2
|
2天前
|
人工智能 定位技术 图形学
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
43 1
|
2天前
|
图形学
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(下)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
7 0
|
2天前
|
图形学 容器
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(上)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
5 0
|
2天前
|
图形学
【unity小技巧】Unity中实现一个战斗连击连招系统,可以动态添加减少连击连招段数功能
【unity小技巧】Unity中实现一个战斗连击连招系统,可以动态添加减少连击连招段数功能
5 0
|
2天前
|
图形学
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(上)
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)
10 2
|
2天前
|
图形学
【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版3(附带项目源码)
【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版3(附带项目源码)
13 2
|
2天前
|
图形学
【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版2(附带项目源码)
【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版2(附带项目源码)
8 1
|
2天前
|
图形学
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(下)
【制作100个unity游戏之29】使用unity复刻经典游戏《愤怒的小鸟》(完结,附带项目源码)(下)
8 0
|
2天前
|
存储 JSON 关系型数据库
【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版13(完结,附带项目源码)
【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版13(完结,附带项目源码)
9 0