最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

Unity 中的存档系统(本地存档)

来源:博客园

思想

在游戏过程中,玩家的背包、登录、人物系统都与数据息息相关,无论是一开始就设定好的默认数据,还是可以动态存取的数据,都需要开发人员去管理。游戏开发过程中,策划一般通过Excel表格配置一些内容来对游戏的一些行为经行数据的设定。表格有config默认数据,程序只需要读取即可;还可能建立model类数据需要在游戏中实例化对象来进行数据的增删改查.

MVC架构中Model的CRUD操作也包含在存档类中(本地存档):

方法

excel转换成config默认数据(json文件)并通过对应的类读取数据可以参考我之前发的文章


(资料图片)

https://www.cnblogs.com/ameC1earF/p/17270090.html

以下我对它进行了改良,涵盖了config默认数据以及类的转换以及model动态数据类文件的生成以及数据的存取。

使用

1.写俩个Excel测试(这里同一个Excel分成俩份,一个表示默认配置数据,一个表示model的结构不带数据也可以的):

需要注意:

Excel存放路径:

Config导出路径(Resources.Json)以及存档存储路径(编辑模式下在Assets/Records下,运行模式下在Application.persistentDataPath中)

2.通过编辑器导出对应的类型:

导出的文件:

导出类路径以及导出类:

测试

本地存档也修改了:

存档的优化:

在实际开发中,游戏存档一般不会在每一次数据修改就会改变,而是选择在一个特殊阶段(比如玩家退出游戏),或者是间隔时间存储,所以我们一般使用一个字典先记录模型和对应的数据,通过一个公共方法控制文件的存储。

完整代码

Json格式的数据类:

DataList
using System.Collections.Generic;using System;[Serializable]public class DataList{    public List datas = new List();}

导出类代码:

导出工具类
using UnityEngine;using UnityEditor;using System.IO;using OfficeOpenXml;using System.Collections.Generic;using System;using System.Text;/// /// 导出模式/// public enum ExporterMode{    ///     /// 表格数据,策划配置的默认数据    ///     Config,    ///     /// 模型数据,服务器或者本地可以修改的数据    ///     Model,}/// /// 使用EPPlus获取表格数据,同时导出对应的Json以及Class./// public class ExcelExporter{    ///     /// ExcelConfig路径    ///     private const string excelConfigPath = "../Assets/Excels/Configs";    ///     /// ExcelModel路径    ///     private const string excelModelPath = "../Assets/Excels/Models";    private const string configPath = "../Assets/Resources/Json";    private const string configClassPath = "../Assets/Scripts/Configs";    private const string modelPath = "../Assets/Records";    private const string modelClassPath = "../Assets/Scripts/Models";    ///     /// 属性行    ///     private const int propertyIndex = 2;    ///     /// 类型行    ///     private const int typeIndex = 3;    ///     /// 值行    ///     private const int valueIndex = 4;    [MenuItem("Tools/ExportExcelConfigs")]    private static void ExportConfigs()    {        try        {            string path = string.Format("{0}/{1}", Application.dataPath, excelConfigPath);            FileInfo[] files = FilesUtil.LoadFiles(path);            foreach (var file in files)            {                //过滤文件                if (file.Extension != ".xlsx") continue;                ExcelPackage excelPackage = new ExcelPackage(file);                ExcelWorksheets worksheets = excelPackage.Workbook.Worksheets;                //只导表1                ExcelWorksheet worksheet = worksheets[1];                ExportJson(worksheet, Path.GetFileNameWithoutExtension(file.FullName), ExporterMode.Config);                ExportClass(worksheet, Path.GetFileNameWithoutExtension(file.FullName), ExporterMode.Config);            }            AssetDatabase.Refresh();        }        catch (Exception e)        {            Debug.LogError(e.ToString());        }    }    [MenuItem("Tools/ExportExcelModels")]    private static void ExportModels()    {        try        {            string path = string.Format("{0}/{1}", Application.dataPath, excelModelPath);            FileInfo[] files = FilesUtil.LoadFiles(path);            foreach (var file in files)            {                //过滤文件                if (file.Extension != ".xlsx") continue;                ExcelPackage excelPackage = new ExcelPackage(file);                ExcelWorksheets worksheets = excelPackage.Workbook.Worksheets;                //只导表1                ExcelWorksheet worksheet = worksheets[1];                ExportJson(worksheet, Path.GetFileNameWithoutExtension(file.FullName), ExporterMode.Model);                ExportClass(worksheet, Path.GetFileNameWithoutExtension(file.FullName), ExporterMode.Model);            }            AssetDatabase.Refresh();        }        catch (Exception e)        {            Debug.LogError(e.ToString());        }    }    ///     /// 导出类    ///     private static void ExportClass(ExcelWorksheet worksheet, string fileName, ExporterMode mode)    {        string[] properties = GetProperties(worksheet);        StringBuilder sb = new StringBuilder();        sb.Append("using System;\t\n");        sb.Append("[Serializable]\t\n");        sb.Append($"public class {fileName}{mode.ToString()} ");//类名        if (mode == ExporterMode.Model)//模型类继承模型接口            sb.Append(": IModel");        sb.Append("\n");        sb.Append("{\n");        for (int col = 1; col <= properties.Length; col++)        {            string fieldType = GetType(worksheet, col);            string fieldName = properties[col - 1];            sb.Append($"\tpublic {fieldType} {fieldName};\n");        }        sb.Append("}\n\n");        FilesUtil.SaveFile(string.Format("{0}/{1}", Application.dataPath, mode == ExporterMode.Config ? configClassPath : modelClassPath),        string.Format("{0}{1}.cs", fileName, mode.ToString()), sb.ToString());    }    ///     /// 导出JSON    ///     private static void ExportJson(ExcelWorksheet worksheet, string fileName, ExporterMode mode)    {        string str = "";        int num = 0;        string[] properties = GetProperties(worksheet);        for (int col = 1; col <= properties.Length; col++)        {            string[] temp = GetValues(worksheet, col);            num = temp.Length;            foreach (var value in temp)            {                str += GetJsonK_VFromKeyAndValues(properties[col - 1],                    Convert(GetType(worksheet, col), value)) + ",";            }        }        //获取key:value的字符串        str = str.Substring(0, str.Length - 1);        str = GetJsonFromJsonK_V(str, num);        str = GetUnityJsonFromJson(str);        FilesUtil.SaveFile(string.Format("{0}/{1}", Application.dataPath, mode == ExporterMode.Config ? configPath : modelPath),        string.Format("{0}{1}.{2}", fileName, mode.ToString(), mode == ExporterMode.Config ? "json" : "record"),        str);    }    ///     /// 获取属性    ///     private static string[] GetProperties(ExcelWorksheet worksheet)    {        string[] properties = new string[worksheet.Dimension.End.Column];        for (int col = 1; col <= worksheet.Dimension.End.Column; col++)        {            if (worksheet.Cells[propertyIndex, col].Text == "")                throw new System.Exception(string.Format("第{0}行第{1}列为空", propertyIndex, col));            properties[col - 1] = worksheet.Cells[propertyIndex, col].Text;        }        return properties;    }    ///     /// 获取值    ///     private static string[] GetValues(ExcelWorksheet worksheet, int col)    {        //容量减去前三行        string[] values = new string[worksheet.Dimension.End.Row - 3];        for (int row = valueIndex; row <= worksheet.Dimension.End.Row; row++)        {            values[row - valueIndex] = worksheet.Cells[row, col].Text;        }        return values;    }    ///     /// 获取类型    ///     private static string GetType(ExcelWorksheet worksheet, int col)    {        return worksheet.Cells[typeIndex, col].Text;    }    ///     /// 通过类型返回对应值    ///     private static string Convert(string type, string value)    {        string res = "";        switch (type)        {            case "int": res = value; break;            case "int32": res = value; break;            case "int64": res = value; break;            case "long": res = value; break;            case "float": res = value; break;            case "double": res = value; break;            case "string": res = $"\"{value}\""; break;            default:                throw new Exception($"不支持此类型: {type}");        }        return res;    }    ///     /// 返回key:value    ///     private static string GetJsonK_VFromKeyAndValues(string key, string value)    {        return string.Format("\"{0}\":{1}", key, value);    }    ///     ///获取[key:value]转换为{key:value,key:value},再变成[{key:value,key:value},{key:value,key:value}]    ///     private static string GetJsonFromJsonK_V(string json, int valueNum)    {        string str = "";        string[] strs;        List listStr = new List();        strs = json.Split(",");        listStr.Clear();        for (int j = 0; j < valueNum; j++)        {            listStr.Add("{" + string.Format("{0},{1}", strs[j], strs[j + valueNum]) + "}");        }        str = "[";        foreach (var l in listStr)        {            str += l + ",";        }        str = str.Substring(0, str.Length - 1);        str += "]";        return str;    }    ///     /// 适应JsonUtility.FromJson函数的转换格式    ///     private static string GetUnityJsonFromJson(string json)    {        return "{" + "\"datas\":" + json + "}";    }}

存档类代码:

存档类
using UnityEngine;using System.IO;using System.Collections.Generic;using System;/// /// 本地模式存档类/// public class Recorder : Singleton{    ///     /// 不同模式下的存储路径    ///     private string RecordPath    {        get        {#if (UNITY_EDITOR || UNITY_STANDALONE)            return string.Format("{0}/Records", Application.dataPath);#else            return string.Format("{0}/Records", Application.persistentDataPath);#endif        }    }    ///     /// 用来临时存储存档的容器,便与定时存储而不是每一次修改都进行存储    ///Key是文件名,Value是内容    ///     private Dictionary _cache = new Dictionary();    public Recorder()    {        _cache.Clear();        FileInfo[] files = FilesUtil.LoadFiles(RecordPath);        foreach (var f in files)        {            string key = Path.GetFileNameWithoutExtension(f.FullName);            string value = File.ReadAllText(f.FullName);            _cache.Add(key, value);        }    }    ///     /// 通常不会修改一次数据就保存一次,间隔保存或者统一保存可以调用此方法    /// 强制手动保存    /// 将cache内容同步到本地文件    ///     public void ForceSave()    {        FileInfo[] files = FilesUtil.LoadFiles(RecordPath);        foreach (var f in files)        {            string name = Path.GetFileNameWithoutExtension(f.Name);            if (_cache.ContainsKey(name))            {                string path = string.Format("{0}/{1}.record", RecordPath, name);                if (File.Exists(path)) File.Delete(path);                //重新写入                File.WriteAllText(path, _cache[name]);            }        }    }    ///     /// 读取数据,dynamic表示你是从对象的cache中获取数据,还是读取静态存档的数据    ///     public DataList LoadData() where T : IModel    {        try        {            string fileContent = _cache[typeof(T).Name];            DataList dataList = JsonUtility.FromJson>(fileContent);            return dataList;        }        catch (Exception err)        {            throw new System.Exception(err.ToString());        }    }    ///     /// 存储数据,暂存在字典中或者持续存储到文件中    /// 不建议每次更改数据都存储到文件中    /// 非必要不使用save = true,建议使用ForceSave进行一次性的统一存储    ///     public void SaveData(DataList data, bool save = false) where T : IModel    {        string json = JsonUtility.ToJson(data);        try        {            _cache[typeof(T).Name] = json;            if (save)            {                string path = string.Format("{0}/{1}.record", RecordPath, typeof(T).Name);                if (File.Exists(path)) File.Delete(path);                //重新写入                File.WriteAllText(path, json);            }        }        catch (System.Exception)        {            throw;        }    }    #region  CURD    public void CreateData(T data, bool save = false) where T : IModel    {        DataList dataList = LoadData();        dataList.datas.Add(data);        SaveData(dataList, save);    }    public void UpdateData(int index, T data, bool save = false) where T : IModel    {        try        {            DataList dataList = LoadData();            dataList.datas[index] = data;            SaveData(dataList, save);        }        catch (Exception err)        {            throw new System.Exception(err.ToString());        }    }    public T ReadData(int index) where T : IModel    {        try        {            DataList dataList = LoadData();            return dataList.datas[index];        }        catch (Exception err)        {            throw new System.Exception(err.ToString());        }    }    public void DeleteData(T data, bool save = false) where T : IModel    {        DataList dataList = LoadData();        dataList.datas.Remove(data);        SaveData(dataList, save);    }    public void DeleteData(int index, bool save = false) where T : IModel    {        try        {            DataList dataList = LoadData();            dataList.datas.RemoveAt(index);            SaveData(dataList, save);        }        catch (System.Exception)        {            throw;        }    }    #endregion}

Config读取代码:

ConfigLoader
using UnityEngine;public class ConfigLoader : Singleton{    public DataList LoadConfig()    {        string json = Resources.Load("Json/" + typeof(T).Name).text;        DataList dataList = JsonUtility.FromJson>(json);        return dataList;    }}

关键词: