最新要闻
- 突破10GB/s!影驰首款PCIe 5.0 SSD开卖:2TB售价2499元
- 热门:2.1s破百!100万的新款特斯拉 快得我差点吐了
- 世界今亮点!苹果WWDC大会定档6月6日:iOS 17无悬念、MR头显最受期待
- 达墨国产PCIe 5.0 硬盘2TB 1899元 官方坦诚提醒:谁买谁冤种
- 当前速看:飞艇事件的背后
- 世界热文:搞笑动漫日和在线观看(搞笑动漫日和)
- 苹果推出的美国版花呗:被严重低估了
- 全球聚焦:为什么洗澡时总想“尿尿”?这怀习惯可不好!
- 环球信息:新一代高贵“亮机卡”!RTX 4050被曝6月发布:弱得不像话
- 【世界报资讯】 “大号MINI”!五菱缤果正式上市:5.98万元起
- 国产特有 魔改RTX 3060显卡999元:AMD也做不到的性价比
- 天天通讯!报告:电信业采购供应链发展呈现四大趋势
- 当前速看:《生化危机4:重制版》阿什莉服装Mod公布 看了把持不住
- 天天亮点!CPU占用暴降 SSD提速百倍:《暗黑4》将支持微软DX游戏神技
- 今日热讯:关于大国竞争,“修昔底德陷阱”提出者谈到了“澶渊之盟”
- 合资轿车雪上加霜!上汽名爵最帅轿跑MG7上市:11.98万起
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
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
Config读取代码:
ConfigLoader
using UnityEngine;public class ConfigLoader : Singleton{ public DataList LoadConfig() { string json = Resources.Load("Json/" + typeof(T).Name).text; DataList dataList = JsonUtility.FromJson
关键词:
-
【Visual Leak Detector】配置项 SkipHeapFreeLeaks
使用VLD内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍VLD配置文件中配置项SkipHeapFreeLeaks的使用方法。
来源: -
最新消息:IDEA2023.1破解 永久激活 最新版IDEA激活 亲测可用!
当前IDEA的版本,已经更新到2023 1,本文为大家带来最新版IDEA2023 1专用激活破解方式。此激活方式,...
来源: 【Visual Leak Detector】配置项 SkipHeapFreeLeaks
Unity 中的存档系统(本地存档)
最新消息:IDEA2023.1破解 永久激活 最新版IDEA激活 亲测可用!
突破10GB/s!影驰首款PCIe 5.0 SSD开卖:2TB售价2499元
热门:2.1s破百!100万的新款特斯拉 快得我差点吐了
世界今亮点!苹果WWDC大会定档6月6日:iOS 17无悬念、MR头显最受期待
达墨国产PCIe 5.0 硬盘2TB 1899元 官方坦诚提醒:谁买谁冤种
当前速看:飞艇事件的背后
世界热文:搞笑动漫日和在线观看(搞笑动漫日和)
天天新资讯:Ubuntu18.04系统安装nginx
天天速递!手撕HashMap(二)
【Visual Leak Detector】配置项 TraceInternalFrames
苹果推出的美国版花呗:被严重低估了
全球聚焦:为什么洗澡时总想“尿尿”?这怀习惯可不好!
环球信息:新一代高贵“亮机卡”!RTX 4050被曝6月发布:弱得不像话
【世界报资讯】 “大号MINI”!五菱缤果正式上市:5.98万元起
国产特有 魔改RTX 3060显卡999元:AMD也做不到的性价比
天天通讯!报告:电信业采购供应链发展呈现四大趋势
【独家】【Visual Leak Detector】配置项 StartDisabled
78.类型转换
环球快报:2023年找工作的心酸历程
全球热议:ASP.NET Core MVC+Quartz实现定时任务可视化管理页面
世界即时看!SSM框架笔记 庆祝学习SSM框架结束!!!
世界速读:【财经分析】债市短期表现向好 机构操作犹存分歧
当前速看:《生化危机4:重制版》阿什莉服装Mod公布 看了把持不住
天天亮点!CPU占用暴降 SSD提速百倍:《暗黑4》将支持微软DX游戏神技
具体如何编写信号与槽
今日热讯:关于大国竞争,“修昔底德陷阱”提出者谈到了“澶渊之盟”
合资轿车雪上加霜!上汽名爵最帅轿跑MG7上市:11.98万起
新动态:ROG游戏手机7跑分首曝:二代骁龙8 134.6万冠绝全球
规模或超90%!流媒体巨头Hulu国内被曝大裁员
JOLED破产 日本OLED面板技术押错宝:弯道超车失败
当前动态:骁龙8cx Gen 4处理器跑分曝光:12核性能大跌眼镜 仅苹果M2 Max 1/3
【世界速看料】76.算术运算符
世界动态:PfSense pfBlockerNG 未授权RCE漏洞(CVE-2022-31814)
热点!Unity中基于EPPLUS的Excel转换以及Json数据读取
全球速讯:c# 对序列化类XMLSerializer 二次封装泛型化方便了一些使用的步骤
新华社权威快报|首次纳入肝素类药品 第八批药品集采平均降价56%
焦点!一排小草怎么画简单好看_一排小草怎么画简笔画
当前快讯:Win12正全力开发!微软重构操作系统底层:模块化设计
【新视野】宣称能跑100公里!男子网购电动车续航打折:法院判退一赔三
全球快资讯:“雪糕刺客”的仁慈!钟薛高用文心一言打造雪糕 仅售3.5元
即时看!口腔溃疡总不好 可能是大病预警!“偏方”都没用!
今日讯!比5G强10倍!工信部:中国已成立6G工作组推动关键技术研究
pthread库实现简单并行程序:Hello
全球焦点!日本央行官员暗示调整YCC政策 日债收益率周三全线回落
全球快资讯:净利润同比增长超62% 中国石油2022年业绩创历史最好水平
全球视点!韩瑟冻干粉怎么样_韩瑟化妆品怎么样
果然来了!电商偷跑索尼PS5 Slim游戏机:新外观 更轻薄
全球热头条丨SSD性能狂飙 追赶DDR5内存 PCIe 6.0硬盘预计2026年问世
听到吧唧嘴就抓狂:一男子已4年不理家人
头条:德国掀桌 欧盟让步 “2035禁燃令”为何不再禁燃油车?
男子测智商竟被推荐花98元包月:付了钱也没看到结果
【独家焦点】郑氏点银:黄金有望震荡冲1980,原油背离逼空反弹待回落
【天天快播报】记录--开局一张图,构建神奇的 CSS 效果
java泛型和通配符
环球微资讯!玩家期待已久!任天堂限定版Switch来了
全球今日报丨不拍蒜也断?张小泉斩骨刀斩骨时断裂 客服:与使用力度、角度有关
车被撞废人完好无损!比亚迪汉DM-i车主转头定了一台海豹
环球快资讯丨为何Redmi敢首发高通第二代骁龙7+?员工解释原因
男子驾车途中昏迷撞走公司大门 罪魁祸首竟是一只马蜂
全球看热讯:惠州治皮肤过敏较好的医院
全球微头条丨用 Go 剑指 Offer 07. 重建二叉树
快资讯:IDEA使用技巧和注册教程
全网最详细中英文ChatGPT-GPT-4示例文档-最强JS助手聊天机器人应用从0到1快速入门——官网推荐的48种最佳应用场景(附python/node.js/
全球快看点丨下载安装MyAQL数据库8.0.30
NX二次开发:Checkmate例子根据dfa文件检查模型数据
天天即时看!广东佛山发生3.4级地震 广州有震感!你感受到没
环球微动态丨火狐良心!至少支持Win7/8.1到2024年第3季度
天天快看点丨质量堪忧 多批次行车记录仪抽检不合格 纽曼上黑榜
天天通讯!360版ChatGPT要来了!周鸿祎:大家给起个名字
焦点简讯:男子回应合成迪丽热巴视频来龙去脉:不想跟其他博主同质化
即时:钟薛高推出3.5元雪糕上市时间
MySQL的安装
世界资讯:python中函数的返回值详解
环球速读:关于Web的欢迎页面的开发设置
焦点热讯:Whats's New In Seata 1.6.x
环球短讯!Powerpoint教程_编程入门自学教程_菜鸟教程-免费教程分享
热点评!首批两只新能源领域REITs上市首日均收涨
头条:前搜狗CEO王小川成立人工智能公司:中国需要自己的OpenAI
观速讯丨美团回应限制大龄外卖骑手:入职年龄并未调整 能干到57岁
环球快报:经济学家林毅夫:AI可让人们享受生活 未来每周只工作一天
历史上首次!佳能将推可自动对焦的移轴镜头
全球热点!关注!有答复了,《关于加快发展文化创意产业,培育福鼎经济新亮点的建议》。
lmxcms代码审计学习
【天天播资讯】0功耗电子纸数字海报问世:不换画面不耗电
今日视点:30年大品牌 金邦2TB SSD到手549元:长寿TLC+PCIe 4.0性能
中国高铁首次出海!雅万高铁全线轨道铺通:最高时速350公里
每日报道:比亚迪汽车毛利率25.9%!李想夸赞:比特斯拉强太多
全球速递!俄亥俄河一载1400吨有毒物质驳船沉没:尚不清楚是否发生泄漏
世界报道:太极股份:截止2023年3月20日,公司的股东户数为36798户
Go语言:编写一个 WebsiteRacer 的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL。如果两个 URL 在 10 秒内都未返回结果
全球实时:一文带你搞懂如何优化慢SQL
焦点快报!Dijkstar-And-Astar算法
用上ChatGPT的这几个功能,你的开发效率不高都难
联想y400什么时候上市的?联想y400笔记本配置
地下城与勇士龙年套装哪个好?地下城与勇士龙年套装有几个宝珠?
HTCG28什么时候上市的?HTCG28手机参数
华为C8813Q如何装sim卡?华为C8813Q手机参数
gprs套餐费是什么意思?怎么关闭GPRS套餐?