在实际开发中常常是策划配置好数据表在告诉客户端更新配置。往往公司策划一般使用Excel做数据。我记得在做coco的时候第二个项目就是用excel配置数据,每次更新都比较麻烦开始,忍不了就学几天Python写了一个导表工具,但是那时候已经有点晚了,策划的表之前没规划好,格式比较不统一,只能慢慢写几个不一样工具满足,比较麻烦。所以项目开始之前就必须想好数据的管理,和配置的数据格式和策划沟通,严格按照规定来。
肯定需要决定使用什么样的格式在程序里面:xml,json,csv,txt......又或者自己定制。我选择使用csv,好处就是比较小,读取也不难。
思路:Excel-----导出----->csv------>打包成---->AssetBundle----->客户端解析
问题:
1.遇到使用Excel导出Csv时候发现只能一个个导出,而且还出现什么修改。很不科学,我果断忍不了。自己使用unity写个解析自动生产.csv文件。
2.新版的AssetBundle只需要设置每个数据资源的名字直接打包,耶很麻烦。果断自己写个打包数据工具。
3.在程序中如果管理数据。第一:每次使用时候去读取CSV文件,这样做加大了IO操作,好处就是内存开始消耗不大。第二,数据持续化。好处就是减少IO操作,消耗部分内存但是消耗也不大如果数据少,一般手机游戏不是很大测试过,就算多耶可以自己写个DataManager进行管理,在什么时候加载那个数据,什么时候卸载。果断使用第二个。
4.使用第二种持续化数据问题来了。每个csv文件就对应一个数据结构,不可能手动去给每个csv写数据管理。呵呵,果断写工具自动生成,就好像之前写自动生成协议工具一样。
开始时候准备:在Excel文件夹下有个Excel文件,Excel格式如下
还没有文件:
使用工具在uniy菜单栏生成三个工具:
[MenuItem("GameTool/DataEditor/CreateCSV")]
[MenuItem("GameTool/DataEditor/Build_CSV")]
[MenuItem("GameTool/DataEditor/CreateDManager")]
对比上面生成文件:
已经生成没报错:DateManager里面解析是否成功。
OK结束。
代码太多分享下如果使用unity 生成csv文件:
[MenuItem("GameTool/DataEditor/CreateCSV")]
public static void createCSV()
{
FileStream stream = File.Open(excelPaht, FileMode.Open, FileAccess.Read);
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
DataSet result = excelReader.AsDataSet();
for (int k = 0 ,max = result.Tables.Count; k < max; k++)
{
int whitchSheel = k;
int columns = result.Tables[whitchSheel].Columns.Count;
int rows = result.Tables[whitchSheel].Rows.Count;
string savePath = saveCSADir + result.Tables[whitchSheel].TableName + ".csv";
if (File.Exists(savePath))
{
File.Delete(savePath);
}
StreamWriter streamWriter = new StreamWriter(savePath,true,Encoding.Default); //File.CreateText (savePath);
for(int i = 0; i< rows; i++)
{
string rowStr = "";
for(int j =0; j < columns; j++)
{
string nvalue = result.Tables[whitchSheel].Rows[i][j].ToString();
if (nvalue.Contains(","))
{
nvalue = "\"" + nvalue + "\"";
}
rowStr = rowStr +"," + nvalue;
}
rowStr = rowStr.Substring(1);
rowStr.Trim();
streamWriter.WriteLine(rowStr);
}
streamWriter.Flush();
streamWriter.Close ();
}
AssetDatabase.Refresh ();
}
这个工具暂时只支持:int,float,string,array,后面可以完善,但是现在暂时是够了。
注意:DatasManager.cs是个总得数据管理中心,一般就是初始化生成的持续化数据Manager例如ExpDManager,如果消耗果断就卸载部分,决定什么时候加载卸载工作。
自动生成的Manager格式如下,其实几就单例:
/*******************************************************************
* 注意:文件自动生成,不需要手动需改!
* 最后更新时间: 2015-11-25 15:42:51
* 名字: ExpDManager
* 简单解析: 数据类
*******************************************************************/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LumenWorks.Framework.IO.Csv;
//==============================数据结构=============================
public class ExpTConfig
{
public int Level; //等级
public float Exp; //经验
public string Name; //名字
public string[] Rands; //随机
public int[] TextInt; //测试int
public float[] TextFloat; //测试float
}
//==============================数据结构=============================
//==============================管理类===============================
public class ExpTManager: SingleClass<ExpTManager>
{
public Dictionary<int,ExpTConfig> _allDatas = new Dictionary<int,ExpTConfig>();
//=========初始化=========
public void InitCSVConfig(CsvReader csvRead)
{
int fieldCount = csvRead.FieldCount;
string[] headers = csvRead.GetFieldHeaders();
int jumpFlag = 0;
while (csvRead.ReadNextRecord())
{
if (jumpFlag < 2)
{
jumpFlag++;
continue;
}
int i = 0;
ExpTConfig config = new ExpTConfig();
config.Level = int.Parse(StaticUtils.enemy2Number(csvRead[i++]));
config.Exp = float.Parse(StaticUtils.enemy2Number(csvRead[i++]));
config.Name = StaticUtils.enemy2Number(csvRead[i++]);
string[] RandsArr = StaticUtils.enemy2Number(csvRead[i++]).Split(',');
if (config.Rands == null)
{
config.Rands = new string[RandsArr.Length];
}
for (int j = 0; j < RandsArr.Length; j++)
{
config.Rands[j] = StaticUtils.enemy2Number(RandsArr[j]);
}
string[] TextIntArr = StaticUtils.enemy2Number(csvRead[i++]).Split(',');
if (config.TextInt == null)
{
config.TextInt = new int[TextIntArr.Length];
}
for (int j = 0; j < TextIntArr.Length; j++)
{
config.TextInt[j] = int.Parse(StaticUtils.enemy2Number(TextIntArr[j]));
}
string[] TextFloatArr = StaticUtils.enemy2Number(csvRead[i++]).Split(',');
if (config.TextFloat == null)
{
config.TextFloat = new float[TextFloatArr.Length];
}
for (int j = 0; j < TextFloatArr.Length; j++)
{
config.TextFloat[j] = float.Parse(StaticUtils.enemy2Number(TextFloatArr[j]));
}
AddExpConfig( config);
}
}
//======增加一条数据====
public void AddExpConfig(ExpTConfig config)
{
if (_allDatas.ContainsKey(config.Level))
return;
_allDatas.Add(config.Level,config);
}
//======获得一条数据====
public ExpTConfig GetExpconfigByLevel(int Level)
{
if (_allDatas.ContainsKey(Level))
return _allDatas[Level];
return null;
}
}