应用场景
做了个RPG游戏,但是道具表如果建在脚本里,不方便调整,需要Excel表来统一调整记录
但是我又已经在脚本里面写了很多道具了,这样我如果重新建excel表,还得重填一遍,于是就做个自动保存excel表的方法
保存成Excel文件
public void ItemSaveToExcle(string i)
{
Debug.Log("保存道具个数:" + ItemManager.instance.AllItems.Count);
// 创建一个Excel文件
using (var package = new ExcelPackage())
{
Debug.Log("保存excle");
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("道具表");
// 将List<Item>中的数据写入Excel表中
worksheet.Cells[1, 1].Value = "物品编号";
worksheet.Cells[1, 2].Value = "物品名称";
worksheet.Cells[1, 3].Value = "品质";
//.......这里就一行行填命名,方便理解的,写啥都行
int row = 2;
foreach (Item item in ItemManager.instance.AllItems)
{
Debug.Log("保存:" + item.Iname);
worksheet.Cells[row, 1].Value = item.ItemID;
worksheet.Cells[row, 2].Value = item.Iname;
//....这里就一格格记录一个属性
row++;
}
// 保存Excel文件
string filePath = Path.Combine(Application.streamingAssetsPath, i+".xlsx");
FileInfo file = new FileInfo(filePath);
package.SaveAs(file);
}
}
读取Excel文件(需要有EEPL)
//读取excel表
public void ItemLoadFormExcle()
{
bool isAndor = true;
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
isAndor = false;
break;
case RuntimePlatform.Android:
isAndor = true;
break;
}
string filePath;
//如果是安卓,这里区分安卓的原因,是挣扎了一下手机读取excle,发现确实读不了
if (isAndor)
{
filePath = Path.Combine(Application.persistentDataPath, "Item.xlsx");
}
else
{
filePath = Path.Combine(Application.streamingAssetsPath, "Item.xlsx");
}
Debug.Log(filePath);
FileInfo file = new FileInfo(filePath);
using (ExcelPackage package = new ExcelPackage(file))
{
//读取第一张表
ExcelWorksheet worksheet = package.Workbook.Worksheets["item"];
int rowCount = worksheet.Dimension.Rows;
List<Item> items = new List<Item>();
for (int row = 2; row <= rowCount; row++)
{
//Debug.Log("读取:" + row + "这行");
if (worksheet.Cells[row, 1].Value == null)
{
continue;
}
else
{
Item item = new Item();
item.ItemID = worksheet.Cells[row, 1].GetValue<int>();
item.Iname = worksheet.Cells[row, 2].Value.ToString();
//...把属性一行行地赋给新物品
//新物品加入道具表
items.Add(item);
}
}
//把我们原有的道具表清空,赋值新道具表即可
ItemManager.instance.AllItems.Clear();
ItemManager.instance.AllItems = items;
}
}
保存为Json文件
//保存
public void Save()
{
物品整型数据 = new List<int>();
物品字符数据 = new List<string>();
foreach (Item i in AllItems)
{
// 物品整型数据
物品整型数据.Add(i.ItemID);
物品整型数据.Add(i.品质);
物品整型数据.Add(i.抗药性);
物品整型数据.Add(i.可以使用 ? 1 : 0);
物品整型数据.Add(i.使用等级);
物品整型数据.Add(i.技艺要求数值);
物品整型数据.Add(i.精力消耗);
物品整型数据.Add(i.奖励帝具id);
物品整型数据.Add(i.奖励物品id);
物品整型数据.Add(i.普通物品id);
物品整型数据.Add(i.技能id);
物品整型数据.Add(i.可以售卖 ? 1 : 0);
物品整型数据.Add(i.是否用钻 ? 1 : 0);
物品整型数据.Add(i.售价);
物品整型数据.Add(i.已经卖出 ? 1 : 0);
物品整型数据.Add(i.星级);
物品整型数据.Add((int)(i.属性要求1数值*100));
物品整型数据.Add((int)(i.属性要求2数值 * 100));
物品整型数据.Add((int)(i.属性惩罚数值 * 100));
物品整型数据.Add((int)(i.属性惩罚百分比 * 100));
物品整型数据.Add((int)(i.属性奖励数值 * 100));
物品整型数据.Add((int)(i.属性奖励百分比 * 100));
物品整型数据.Add((int)(i.资源奖励数值 * 100));
物品整型数据.Add((int)(i.资源奖励百分比 * 100));
物品整型数据.Add((int)(i.资源惩罚数值 * 100));
物品整型数据.Add((int)(i.资源惩罚百分比 * 100));
物品整型数据.Add((int)(i.赌狗概率 * 100));
物品整型数据.Add((int)(i.临时属性惩罚数值 * 100));
物品整型数据.Add((int)(i.临时属性惩罚百分比 * 100));
物品整型数据.Add((int)(i.临时属性奖励数值 * 100));
物品整型数据.Add((int)(i.临时属性奖励百分比 * 100));
物品整型数据.Add((int)(i.吸血率 * 100));
物品整型数据.Add((int)(i.反伤率 * 100));
物品整型数据.Add((int)(i.回复率 * 100));
物品整型数据.Add((int)(i.爆宝率 * 100));
物品整型数据.Add((int)(i.免伤率 * 100));
// 物品字符数据
物品字符数据.Add(i.属性要求1.ToString());
物品字符数据.Add(i.属性要求2.ToString());
物品字符数据.Add(i.技艺要求.ToString());
物品字符数据.Add(i.属性惩罚.ToString());
物品字符数据.Add(i.属性奖励.ToString());
物品字符数据.Add(i.资源奖励.ToString());
物品字符数据.Add(i.资源惩罚.ToString());
物品字符数据.Add(i.道具类型.ToString());
物品字符数据.Add(i.资源属性.ToString());
物品字符数据.Add(i.Iname);
物品字符数据.Add(i.物品描述);
物品字符数据.Add(i.使用效果);
}
//保存方法
GameManager.instance.Save(物品整型数据, "/AllitemInt.json");
GameManager.instance.Save(物品字符数据, "/AllitemString.json");
}
using System.Collections.Generic;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using LitJson;
using System.IO;
using System;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
public void Save<T> (T t,string path)
{
bool isAndor = true;
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
isAndor = false;
break;
case RuntimePlatform.Android:
isAndor = true;
break;
}
if(isAndor)
{
string filePath = Application.persistentDataPath + path;//persistentDataPath
//把剧本转成json字符串
string saveJsonstr = JsonMapper.ToJson(t);
//新建一个StreamWiter文件,路径按照上面路径固定住
StreamWriter sw = new StreamWriter(filePath);
//写入json字符串
sw.Write(saveJsonstr);
//关闭
sw.Close();
}
else
{
string filePath = Application.streamingAssetsPath + path;//persistentDataPath
//把剧本转成json字符串
string saveJsonstr = JsonMapper.ToJson(t);
//新建一个StreamWiter文件,路径按照上面路径固定住
StreamWriter sw = new StreamWriter(filePath);
//写入json字符串
sw.Write(saveJsonstr);
//关闭
sw.Close();
}
}
这个方法就是典型的因为用了float导致我一个个保存,中间还得数自己漏了哪几个,还要转换类型等等,非常麻烦,一个东西就写了一晚上,我的Skill设计是只有int和string的,保存起来非常舒服
加载Json文件
public void Load()
{
AllItems.Clear();
物品整型数据 = GameManager.instance.Load(物品整型数据, "/AllitemInt.json");
//Debug.Log("整型数目:"+物品整型数据.Count);
物品字符数据 = GameManager.instance.Load(物品字符数据, "/AllitemString.json");
//Debug.Log("字符数目:" + 物品字符数据.Count);
for (int i = 0; i < 物品整型数据.Count/36; i++)
{
Item item = new Item();
item.ItemID = 物品整型数据[i*36 + 0];
item.品质 = 物品整型数据[1 + i*36];
item.抗药性 = 物品整型数据[2 + i*36];
item.可以使用 = 物品整型数据[3 + i*36] == 1;
item.使用等级 = 物品整型数据[4 + i*36];
item.技艺要求数值 = 物品整型数据[5 + i*36];
item.精力消耗 = 物品整型数据[6 + i*36];
item.奖励帝具id = 物品整型数据[7 + i*36];
item.奖励物品id = 物品整型数据[8 + i*36];
item.普通物品id = 物品整型数据[9 + i*36];
item.技能id = 物品整型数据[10 + i*36];
item.可以售卖 = 物品整型数据[11 + i*36] == 1;
item.是否用钻 = 物品整型数据[12 + i*36] == 1;
item.售价 = 物品整型数据[13 + i*36];
item.已经卖出 = 物品整型数据[14 + i*36] == 1;
item.星级 = 物品整型数据[15 + i*36];
item.属性要求1数值 = 物品整型数据[16 + i*36] / 100f;
item.属性要求2数值 = 物品整型数据[17 + i*36] / 100f;
item.属性惩罚数值 = 物品整型数据[18 + i*36] / 100f;
item.属性惩罚百分比 = 物品整型数据[19 + i*36] / 100f;
item.属性奖励数值 = 物品整型数据[20 + i*36] / 100f;
item.属性奖励百分比 = 物品整型数据[21 + i*36] / 100f;
item.资源奖励数值 = 物品整型数据[22 + i*36] / 100f;
item.资源奖励百分比 = 物品整型数据[23 + i*36] / 100f;
item.资源惩罚数值 = 物品整型数据[24 + i*36] / 100f;
item.资源惩罚百分比 = 物品整型数据[25 + i*36] / 100f;
item.赌狗概率 = 物品整型数据[26 + i*36] / 100f;
item.临时属性惩罚数值 = 物品整型数据[27 + i*36];
item.临时属性惩罚百分比 = 物品整型数据[28 + i*36];
item.临时属性奖励数值 = 物品整型数据[29 + i*36];
item.临时属性奖励百分比 = 物品整型数据[30 + i*36];
item.吸血率 = 物品整型数据[31 + i*36];
item.反伤率 = 物品整型数据[32 + i*36];
item.回复率 = 物品整型数据[33+i*36];
item.免伤率= 物品整型数据[34 + i*36];
item.爆宝率= 物品整型数据[35 + i*36];
//Debug.Log("读取道具:" + 物品字符数据[9 + i * 12]);
item.属性要求1 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[0+i * 12]);
item.属性要求2 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[1+ i * 12]);
item.技艺要求 = (GameNumeber)System.Enum.Parse(typeof(GameNumeber), 物品字符数据[2+ i * 12]);
item.属性惩罚 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[3+ i * 12]);
item.属性奖励 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[4+ i * 12]);
item.资源奖励 = (GameNumeber)System.Enum.Parse(typeof(GameNumeber), 物品字符数据[5+ i * 12]);
item.资源惩罚 = (GameNumeber)System.Enum.Parse(typeof(GameNumeber), 物品字符数据[6+ i * 12]);
item.道具类型 = (Items)System.Enum.Parse(typeof(Items), 物品字符数据[7+ i * 12]);
item.资源属性 = (ItemType)System.Enum.Parse(typeof(ItemType), 物品字符数据[8+ i * 12]);
item.Iname = 物品字符数据[9+ i * 12];
item.物品描述 = 物品字符数据[10+ i * 12];
item.使用效果 = 物品字符数据[11+ i * 12];
AllItems.Add(item);
}
public T Load<T>(T t,string path)
{
bool isAndor = true;
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
isAndor = false;
break;
case RuntimePlatform.Android:
isAndor = true;
break;
}
if (isAndor)
{
string filePath = Application.persistentDataPath + path;
if (File.Exists(filePath))
{
StreamReader sr = new StreamReader(filePath);
string jsonStr = sr.ReadToEnd();
sr.Close();
t = JsonMapper.ToObject<T>(jsonStr);
}
if (t == null)
Debug.Log("读取失败,失败的读取物是:" + t.ToString());
return t;
}
else
{
string filePath = Application.streamingAssetsPath + path;
if (File.Exists(filePath))
{
StreamReader sr = new StreamReader(filePath);
string jsonStr = sr.ReadToEnd();
sr.Close();
t = JsonMapper.ToObject<T>(jsonStr);
}
if (t == null)
Debug.Log("读取失败,失败的读取物是:" + t.ToString());
return t;
}
}
一个问题,保存,读取都非常麻烦,以后再做这个,直接就跳过float去保存,不然这么一个个处理,太麻烦了
心得总结
1.安卓和PC不同,PC能读取excel的方法在安卓不一定适用,目前在安卓上,没有发现可以读取excel的方法(尝试了许多,都读取失败了),还是得老老实实Json,不过可以写个PC读取Excel的方法来加快策划速度,如果是做PC端的话,可以支持读写
2.保存Json的时候,最好把数据类型定在int,bool,string这几个里面,千万千万不要使用float,否则没法保存,得一个个存,很麻烦,最好在设定的时候就改好,自定义属性用int去代替,再用方法替换,float就直接放大1000倍来处理,例如暴击率就别保存成0.01f,直接保存成10或者1,到时写个方法处理一下就行了
3.保存的时候注意方法:Application.persistentDataPath(安卓:仅可读)和Application.streamingAssetsPath(电脑:可读可写) ,后者电脑可用,可以读写,但是安卓不能用,安卓用前者,只可读不可写(但是一般手机端也不太需要写)