实际项目开发中,游戏中会存在很多的数值,而这些数值是由策划填表,程序员通过读表获取的。我们公司的表格是Excel表格(xlsx文件),实际程序中,我们会把Excel表转成Lua文件再读取,在这里,给大家分享一下转表功能的实现。
首先需要读取Excel,我们需要三个外部插件:Excel.dll、ICSharpCode.SharpZipLib.dll、System.Data.dll
Excel.dll和ICSharpCode.SharpZipLib.dll的下载地址:http://exceldatareader.codeplex.com/
system.data.dll的路径在unity安装路径下的Editor\Data\Mono\lib\mono\unity 这个路径下
把这三个类库引入Plugins以后,我们就可以开始写代码了
话不多说,上代码:
using UnityEngine;
using UnityEditor;
using System.IO;
using Excel;
using System.Data;
using System.Text.RegularExpressions;
using System.Text;
using System.Collections.Generic;
public class ExcleToLua : EditorWindow
{
[MenuItem("Tools/配置表/将全部Excel转为配置表")]
public static void ExcleAll()
{
string excleRoot = "Assets/table";
DirectoryInfo root = new DirectoryInfo(excleRoot);
FileInfo[] xlsxs = root.GetFiles("*.xlsx");//读取指定目录下所有Excel表数据,存储在数组中
foreach (FileInfo xlsx in xlsxs)
{
string path = xlsx.FullName;
path = path.Substring(path.IndexOf("Assets"));
SelectedExcelToLua(path);
}
AssetDatabase.Refresh();
Debug.Log("全部转表完成");
}
//Excel文件转换成Lua文件方法
static void SelectedExcelToLua(string path)
{
string tableName = Path.GetFileNameWithoutExtension(path);
bool encoderShouldEmitUTF8Identifier = true;
bool throwOnInvalidBytes = false;
bool append = false;
UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier, throwOnInvalidBytes);
StreamReader streamReader = new StreamReader("Assets/CustomEditor/Editor/Excel/ExcelToLuaConfig.txt", encoding);//转表配置文件
string text = streamReader.ReadToEnd();
streamReader.Close();
string[] lines = text.Split('\n');
string[] configs = null;
bool isInConfig = false;
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
if (line.IndexOf(tableName) != -1)
{
configs = line.Split('|');
tableName = configs[1];
isInConfig = true;
break;
}
}
if (!isInConfig)
{
Debug.Log("没有找到" + tableName + "配置,不生成");
return;//没配置就不生成。
}
Debug.Log("_开始转表:" + tableName);
FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read);
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);//调用Excel中IExcelDataReader接口读取数据
DataSet result = excelReader.AsDataSet();
string script =
@"local #TABLENAME#=
{
--[[
转表工具 beta 0.9
]]
#CONTENT#
}
return #TABLENAME#";
Dictionary<string, int> sheetConfigs = new Dictionary<string, int>();
if (configs != null && configs.Length > 2)
{
for (int i = 2; i < configs.Length; i++)
{
string[] config = configs[i].Split(':');
string sheetName = config[0];
int keyIndex = int.Parse(config[1]) - 1;
sheetConfigs.Add(sheetName, keyIndex);
}
}
StringBuilder content = new StringBuilder();
for (int i = 0; i < result.Tables.Count; i++)
{
int keyIndex;
if (!sheetConfigs.TryGetValue(result.Tables[i].TableName, out keyIndex))
keyIndex = -1;
content.Append(GetSheetString(result.Tables[i], keyIndex));
}
script = Regex.Replace(script, "#CONTENT#", content.ToString());
script = Regex.Replace(script, "#TABLENAME#", tableName);
tableName = Regex.Replace(tableName, "\n", "");
tableName = Regex.Replace(tableName, " ", "");
tableName = Regex.Replace(tableName, "\r", "");
string fileName = "Assets/LuaFramework/Lua/Config/" + tableName + ".lua";
StreamWriter streamWriter = new StreamWriter(fileName, append, encoding);
streamWriter.Write(script);
streamWriter.Close();
Debug.Log("转表:" + fileName);
}
static string GetSheetString(DataTable data, int keyIndex)
{
string script =
GetIndentString(2) + "#TABLENAME# = \n" + GetIndentString(2) + "{\n" +
@"--[[
#INDEX#
#NOTE#
]]
#CONTENT#"
+ GetIndentString(2) + "}," + "\n";
bool defaultKey = true;
if (keyIndex != -1)
defaultKey = false;
string tableName = data.TableName;
script = Regex.Replace(script, "#TABLENAME#", tableName);
int columns = data.Columns.Count;
int rows = data.Rows.Count;
StringBuilder content = new StringBuilder();
StringBuilder noteStr = new StringBuilder();
string[] keys = new string[columns];
string[] note = new string[columns];
for (int i = 0; i < columns; i++)
{
keys[i] = data.Rows[0][i].ToString();
note[i] = data.Rows[1][i].ToString();
noteStr.Append(GetIndentString(2) + keys[i] + ":" + note[i] + "\n");
}
script = Regex.Replace(script, "#INDEX#", GetIndentString(2) + "配置索引为:" + (defaultKey ? "默认数字索引" : keys[keyIndex]));
script = Regex.Replace(script, "#NOTE#", noteStr.ToString());
int itemIndex = 1;
bool keyIsString = false;
if (!defaultKey)
{
for (int i = 2; i < rows; i++)
{
float result;
string nvalue = data.Rows[i][keyIndex].ToString();
if (nvalue.Equals(string.Empty)) continue;
if (!float.TryParse(nvalue, out result))
{
keyIsString = true;
break;
}
}
}
for (int i = 2; i < rows; i++)
{
string key = null;
if (defaultKey)
key = itemIndex + "";
else
{
float result;
string nvalue = data.Rows[i][keyIndex].ToString();
if (!keyIsString && float.TryParse(nvalue, out result))
key = "" + nvalue + "";
else
key = "\"" + nvalue + "\"";
}
StringBuilder obj = new StringBuilder();
obj.Append(GetIndentString(4) + "[" + key + "]={");
itemIndex++;
bool valid = false;
for (int j = 0; j < columns; j++)
{
string nvalue = data.Rows[i][j].ToString();
if (nvalue.Equals(string.Empty)) continue;
float result;
if (float.TryParse(nvalue, out result) && nvalue.IndexOf(",") == -1)//"1,2,3":不能转为数字。
obj.Append(keys[j].Trim() + " = " + nvalue + " ,");
else
obj.Append(keys[j].Trim() + " = [[" + nvalue + "]] ,");
valid = true;
}
obj.Append("},\n");
if (valid == true)
content.Append(obj.ToString());
}
script = Regex.Replace(script, "#CONTENT#", content.ToString());
return script;
}
}
可以看出来,基本逻辑是,先去指定路径取出所有的配置表存在数组里,然后根据转表配置文件确定转表类型,使用Excel内部的接口读取数据,然后用循环把所有数据重新写入到Lua文件。