实际项目开发中,游戏中会存在很多的数值,而这些数值是由策划填表,程序员通过读表获取的。我们公司的表格是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文件。