Unity游戏中加载配置文件系列:1. 从Excel中读取配置文件

欢迎关注个人公众号:游戏码小喵

在游戏开发过程中,读取配置文件是必不可少的,读取配置文件的方式有多种多样。转Unity差不多1年了,有很多知识学了忘,忘了学,现在希望通过写文章的方式记录一些东西,以防再忘记,也希望我的文章能帮助那些像我一样刚入门的程序员。

废话不多少,开始正题。下面说说这系列的文章都要写些什么。昨天看到知乎上一个名为毛豆爹的文章回复中这样写到 “对于不同的数据采用不同的配置方法,不要什么数据都用excel,对于有可视化需求的配置,比如ui或者角色身上需要装配一些武器的,提供可视化的工具。对于需要描述父子关系的例如技能树解锁之类的用json或者xml来描述,对于纯数字逻辑的就用csv就好了。” 所以这一些列文章就打算写写配置文件的加载方式。

 

计划分为四篇文章,分别为:

  1. 从Excel文件中读取配置文件
  2. 从json文件中读取配置文件
  3. 从xml文件中读取配置文件
  4. 从csv文件中读取配置文件
  5. 从本地数据库读取配置文件


从Excel文件中读取,这种方式我已经实现过了,但是后面三种本人还未动手实现。这也让我有动力学习一下后三种方式,在未来的几周我会逐一学习,然后把自己的所得分享出来。让大家见笑了,也希望得到大家的意见和建议。

系列之一:从Excel文件中读取配置文件

 

现在大多数公司,大多数项目都会通过Excel配置游戏中用到的数据,今天就说说我从Excel中读取配置的方式。

我的方式是这样的:从Excel文件中读文件保存到ScriptableObject数据格式中,保存在项目中,然后运行游戏的时候从 ScriptableObject文件中读取需要的数据。

这种方式中需要做的几个步骤:

  1. 配置好Excel文件,而且对Excel文件需要一些特殊的配置方式
  2. 通过Excel文件生成其对应的类(项目中需要用到)
  3. 定义一个继承于ScriptableObject的类,用于加载Excel文件中的数据

下面分别对这3个步骤进行分析:(在项目中需要导入Excel.dll和System.Data.dll两个库,https://pan.baidu.com/s/1mimIkGg, 提取码 4mhm)

(1)先说说Excel中的数据如何配置:

 

 

解释一下:

第1行:注释,策划能够清楚配置的列是什么意思(在生成的类中也用于注释);

第2行:属性,(在生成类中用于属性名,例如:Id这个属性,会在类中生成一个id变量和其对应的Id的get,set方法)

第3行:属性的类型,(在生成类中用于属性的类型,Int32对应int,String对应string,Single 对应float,为什么这样配置?

      是因为在System命令空间中只能找到Int32,String,Single等属性)

第4行之后:为游戏中需要用到的数据

(2)读取Excel文件中的数据(上代码):

 

 
string[] excelFiles = Directory.GetFiles(EditorStaticValue.DataFolderPath);
foreach (string fileName in excelFiles)
{
    if (fileName.EndsWith("xlsx"))
    {
        string[] pathFiled = fileName.Split('/');
        if (pathFiled.Length > 0)
        {
            string xlsfileName = pathFiled[pathFiled.Length - 1];
            DataSet dataSet = ReadExcel(xlsfileName);
            DataTableCollection tables = dataSet.Tables;

//          CreateExcelClass(tables[0].TableName, tables[0].Rows);
            foreach(DataTable table in tables)
            {
				CreateExcelClass(table.TableName, table.Rows);
            }
        }
    }
}
  • path :Excel文件存放的位置。
  • excelFiles :存放所有的excel文件
  • 通过for循环,读取excelFiles中保存的所有的文件中表格数据
    DataSet dataSet = ReadExcel(xlsfileName);
    DataTableCollection tables = dataSet.Tables;
  • 灰色代码的意思是只读取excel文件中的第一张表。
  • foreach中读取每张excel文件中的每张表
  • CreateExcelClass创建excel表中table对应的class,传入的参数为,table的名称(定义为class的名称),table中的每一行
private static void CreateExcelClass(string tableName, DataRowCollection collection)
{
    object[] propertyRow = collection[0].ItemArray;

    List allColumnStrList = new List();

    allColumnStrList.Add(GetColumnString(propertyRow));
    for (int row = 1; row < collection.Count; row++)
    {
        allColumnStrList.Add(GetColumnString(collection[row].ItemArray));
    }

    string[] fileLineContent = allColumnStrList.ToArray();
    if (fileLineContent.Length > 0)
    {
        //注释的名字
        string[] noteContents = fileLineContent[0].Split(new string[] {"$"}, System.StringSplitOptions.None);
        //变量的名字
        string[] VariableNameContents = fileLineContent[1].Split(new string[] {"$"}, System.StringSplitOptions.None);
        //变量的类型
        string[] TypeNameContents = fileLineContent[2].Split(new string[] {"$"}, System.StringSplitOptions.None);

        AutoCreateClass(tableName, TypeNameContents, VariableNameContents, noteContents,
            EditorStaticValue.OutClassNameSpace);
    }
}

private static string GetColumnString(object[] rowData)
{
    List ss = new List();

    for (int i = 0; i < rowData.Length; i++)
    {
        ss.Add(rowData[i].ToString());
    }
    return string.Join("$", ss.ToArray());
} allColumnStrList = new List();

    allColumnStrList.Add(GetColumnString(propertyRow));
    for (int row = 1; row < collection.Count; row++)
    {
        allColumnStrList.Add(GetColumnString(collection[row].ItemArray));
    }

    string[] fileLineContent = allColumnStrList.ToArray();
    if (fileLineContent.Length > 0)
    {
        //注释的名字
        string[] noteContents = fileLineContent[0].Split(new string[] {"$"}, System.StringSplitOptions.None);
        //变量的名字
        string[] VariableNameContents = fileLineContent[1].Split(new string[] {"$"}, System.StringSplitOptions.None);
        //变量的类型
        string[] TypeNameContents = fileLineContent[2].Split(new string[] {"$"}, System.StringSplitOptions.None);

        AutoCreateClass(tableName, TypeNameContents, VariableNameContents, noteContents,
            EditorStaticValue.OutClassNameSpace);
    }
}

private static string GetColumnString(object[] rowData)
{
    List ss = new List();

    for (int i = 0; i < rowData.Length; i++)
    {
        ss.Add(rowData[i].ToString());
    }
    return string.Join("$", ss.ToArray());
}

这段代码主要的用意在于通过表中的信息自动创建其对应的类文件。
下面这段代码我认为是这个项目的精华之一:
private static void AutoCreateClass(string className, string[] typeNames, string[] propertyNames, string[] noteNames, string nameSpace)
{
    //声明自定义类
    CodeTypeDeclaration customerClass = new CodeTypeDeclaration(className);
    customerClass.IsClass = true;
    customerClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
    customerClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializableAttribute))));
    CodeCompileUnit customerUnit = new CodeCompileUnit();//创建代码单元


    string ExtensionsClassName = string.Format("{0}{1}", className, "Extend");
    CodeTypeDeclaration customerExtensionsClass = new CodeTypeDeclaration(ExtensionsClassName);
    customerExtensionsClass.IsClass = true;
    customerExtensionsClass.TypeAttributes = TypeAttributes.Public;
    CodeCompileUnit customerExtensionsUnit = new CodeCompileUnit();//创建代码单元

    //创建命名空间
    if (!string.IsNullOrEmpty(nameSpace))
    {
        CodeNamespace customerNameSpace = new CodeNamespace(nameSpace);
        customerNameSpace.Imports.AddRange(new CodeNamespaceImport[] { new CodeNamespaceImport("System") });
        customerNameSpace.Types.Add(customerClass);
        customerUnit.Namespaces.Add(customerNameSpace);

        CodeNamespace customerExtensionsNameSpace = new CodeNamespace(nameSpace);
        customerExtensionsNameSpace.Types.Add(customerExtensionsClass);
        customerExtensionsUnit.Namespaces.Add(customerExtensionsNameSpace);
    }

    for (var i = 0; i < propertyNames.Length; i++)
    {
        string propertyName = propertyNames[i];
        //创建类中的变量
        //                Type.GetType(string.Format("System.{0}", typeNames[i]));
        string fieldName = propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
        CodeMemberField field = new CodeMemberField(Type.GetType(string.Format("System.{0}", typeNames[i])), fieldName);
		field.Attributes = MemberAttributes.Public;
        customerClass.Members.Add(field);

        //创建类中的属性
        CodeMemberProperty property = new CodeMemberProperty();
        property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
        property.Name = propertyName.Substring(0, 1).ToUpper() + propertyName.Substring(1);
        property.HasGet = true;
        property.HasSet = true;
        property.Type = new CodeTypeReference(Type.GetType(string.Format("System.{0}", typeNames[i])));
        property.Comments.Add(new CodeCommentStatement(noteNames[i]));
        property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));
        property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression()));
        customerClass.Members.Add(property);
    }

    //创建代码生成类-C#
    CodeDomProvider providerCS = CodeDomProvider.CreateProvider("C#");
    CodeGeneratorOptions options = new CodeGeneratorOptions();
    options.BracingStyle = "C";
    options.BlankLinesBetweenMembers = true;

    //生成代码
    string outputFile = string.Format("{0}{1}.cs", EditorStaticValue.OutConfigClassPath, className);
    using (StreamWriter sw = new StreamWriter(outputFile))
    {
        providerCS.GenerateCodeFromCompileUnit(customerUnit, sw, options);
    }

    string outputExtensionsFile = string.Format("{0}{1}.cs", EditorStaticValue.OutConfigExtendClassPath, ExtensionsClassName);
    if (!File.Exists(outputExtensionsFile))
    {
        using (StreamWriter sw = new StreamWriter(outputExtensionsFile))
        {
            providerCS.GenerateCodeFromCompileUnit(customerExtensionsUnit, sw, options);
        }
    }

    AssetDatabase.Refresh();
    EditorUtility.DisplayDialog("输出类文件", "成功输出所有类文件!!", "确定");
}

如果读者运行这段代码后会发现生成了两个类文件,一个class文件对应的是table表,还有一个class文件对应第一个class的扩展,这个扩展class需要自动加上static(本人不知道如何生成带static的类,如有知道的朋友请给我留言)
 

(3)定义一个继承于ScriptableObject的类

using System.Collections.Generic;
using ConfigClassExport;
using UnityEngine;

namespace Assets.Scripts.Config.DataBase
{
    public class ConfigData : ScriptableObject
    {
        public DataScene[] DataSceneList;
		public DataPlayer[] DataPlayerList;
    }
}

(4)将数据保存在ScriptableObject的实例中

 

private static void AddDataToHolder(string className, DataRowCollection collection)
{
    int index = 0;
    object[] propertyRow = collection[EditorStaticValue.ExcelPropertyLine].ItemArray;

    var str = string.Format("{0}.{1}", EditorStaticValue.OutClassNameSpace, className);

	var elementNum = collection.Count - EditorStaticValue.ExcelValueLineStart;



	var arr = Array.CreateInstance(CureentAssembly.GetType(str), elementNum);

    for (int row = EditorStaticValue.ExcelValueLineStart; row < collection.Count; row++)
    {
//                object obj = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(str, false);
		object obj = CureentAssembly.CreateInstance(str, false);
        if (obj == null)
            return;

        if (collection[row].IsNull(0))
        {
            continue;
        }
        for (int i = 0; i < propertyRow.Length; i++)
        {
            string propertyName = propertyRow[i].ToString();

            if (string.IsNullOrEmpty(propertyName))
            {
                continue;
            }

            PropertyInfo info = obj.GetType().GetProperty(propertyName);

            if (info == null)
            {
                throw new Exception(string.Format("{0}.cs中{1}属性无法获取,检查是否少写了{1}属性!!!", className, propertyName));
            }

            if (info.PropertyType.IsArray)
            {
                string s = collection[row][i].ToString();
				var strArr = s.Split(',');
				var n = strArr.Length;

				Type elementType = info.PropertyType.GetElementType();
				var arr11 = Array.CreateInstance(elementType, n);
				for(int j=0;j
这样最后就能生成一个存有配置信息的scriptableObject。

 

然后在运行游戏的时候读取这个scriptableObject,加载数据存在字典中就行了
ConfigData configdata = Resources.Load(EditorStaticValue.LocalConfigAssetNames) as ConfigData;

完整的代码如下:
ConfigEditor.cs
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using Assets.Scripts.Comman;
using Assets.Scripts.Config.DataBase;
using Excel;
using UnityEditor;
using UnityEngine;

namespace Assets.Editor
{
    public class ConfigEditor {

        [MenuItem("游戏配置/1 -> 生成Excel对应的Class", false, 1001)]
        private static void Excel2Class()
        {
            if (CreateAllFolder())
            {
                string[] excelFiles = Directory.GetFiles(EditorStaticValue.DataFolderPath);
                foreach (string fileName in excelFiles)
                {
                    if (fileName.EndsWith("xlsx"))
                    {
                        string[] pathFiled = fileName.Split('/');
                        if (pathFiled.Length > 0)
                        {
                            string xlsfileName = pathFiled[pathFiled.Length - 1];
                            DataSet dataSet = ReadExcel(xlsfileName);
                            DataTableCollection tables = dataSet.Tables;

//                            CreateExcelClass(tables[0].TableName, tables[0].Rows);
                            foreach(DataTable table in tables)
                            {
								CreateExcelClass(table.TableName, table.Rows);
                            }
                        }
                    }
                }
            }
            AssetDatabase.Refresh();
        }

        private static string currentExcelName = "";

        [MenuItem("游戏配置/2 -> 生成游戏中使用的配置文件", false, 1001)]
        private static void CreateScriptObject()
        {
            ConfigData data = ScriptableObject.CreateInstance();
            ExcelAccess.SelectConfigExcel(ref data);

            if (!Directory.Exists(EditorStaticValue.ConfigScriptObjectPath))
            {
                Directory.CreateDirectory(EditorStaticValue.ConfigScriptObjectPath);
            }
            AssetDatabase.CreateAsset(data, EditorStaticValue.ConfigScriptObjectPath + "Config.asset");
            AssetDatabase.Refresh();
        }

       

        private static DataSet ReadExcel(string excelName)
        {
            string path = FilePath(excelName);
            try
            {
                FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);

                DataSet result = excelReader.AsDataSet();
                return result;
            }
            catch (Exception ex)
            {
                string[] strArr = ex.Message.Split('\\');
                throw new Exception(string.Format("先关闭{0}", strArr[strArr.Length - 1]));
            }
        }
        private static string FilePath(string path)
        {
            return EditorStaticValue.DataFolderPath + "/" + path;
        }
        private static void CreateExcelClass(string tableName, DataRowCollection collection)
        {
            object[] propertyRow = collection[0].ItemArray;

            List allColumnStrList = new List();

            allColumnStrList.Add(GetColumnString(propertyRow));
            for (int row = 1; row < collection.Count; row++)
            {
                allColumnStrList.Add(GetColumnString(collection[row].ItemArray));
            }

            string[] fileLineContent = allColumnStrList.ToArray();
            if (fileLineContent.Length > 0)
            {
                //注释的名字
                string[] noteContents = fileLineContent[0].Split(new string[] {"$"}, System.StringSplitOptions.None);
                //变量的名字
                string[] VariableNameContents = fileLineContent[1].Split(new string[] {"$"}, System.StringSplitOptions.None);
                //变量的类型
                string[] TypeNameContents = fileLineContent[2].Split(new string[] {"$"}, System.StringSplitOptions.None);

                AutoCreateClass(tableName, TypeNameContents, VariableNameContents, noteContents,
                    EditorStaticValue.OutClassNameSpace);
            }
        }

        private static bool CreateAllFolder()
        {
            if (!Directory.Exists(EditorStaticValue.DataFolderPath))
            {
                Directory.CreateDirectory(EditorStaticValue.DataFolderPath);
                Debug.LogError(string.Format("把xlsx配置文件放入{0}文件夹内", EditorStaticValue.DataFolderPath));
                return false;
            }
            if (!Directory.Exists(EditorStaticValue.OutConfigClassPath))
            {
                Directory.CreateDirectory(EditorStaticValue.OutConfigClassPath);
            }
            else
            {
                DeleteAllFileInFolder(EditorStaticValue.OutConfigClassPath, "OutConfigClassPath  Class");
            }
            if (!Directory.Exists(EditorStaticValue.OutConfigExtendClassPath))
            {
                Directory.CreateDirectory(EditorStaticValue.OutConfigExtendClassPath);
            }
            return true;
        }
        private static string GetColumnString(object[] rowData)
        {
            List ss = new List();

            for (int i = 0; i < rowData.Length; i++)
            {
                ss.Add(rowData[i].ToString());
            }
            return string.Join("$", ss.ToArray());
        }
        private static void DeleteAllFileInFolder(string path, string note)
        {
            DirectoryInfo dir = new DirectoryInfo(path);
            FileInfo[] files = dir.GetFiles();

            foreach (var item in files)
            {
                File.Delete(item.FullName);
            }
//            Debug.Log(string.Format("成功删除所有{0}文件!!", note));
        }
        /// 
        /// 自动生成类
        /// 
        ///类名.
        ///属性名称数组.
        ///注释数组.
        ///命名空间.
        private static void AutoCreateClass(string className, string[] typeNames, string[] propertyNames, string[] noteNames, string nameSpace)
        {
            //声明自定义类
            CodeTypeDeclaration customerClass = new CodeTypeDeclaration(className);
            customerClass.IsClass = true;
            customerClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            customerClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializableAttribute))));
            CodeCompileUnit customerUnit = new CodeCompileUnit();//创建代码单元


            string ExtensionsClassName = string.Format("{0}{1}", className, "Extend");
            CodeTypeDeclaration customerExtensionsClass = new CodeTypeDeclaration(ExtensionsClassName);
            customerExtensionsClass.IsClass = true;
            customerExtensionsClass.TypeAttributes = TypeAttributes.Public;
            CodeCompileUnit customerExtensionsUnit = new CodeCompileUnit();//创建代码单元

            //创建命名空间
            if (!string.IsNullOrEmpty(nameSpace))
            {
                CodeNamespace customerNameSpace = new CodeNamespace(nameSpace);
                customerNameSpace.Imports.AddRange(new CodeNamespaceImport[] { new CodeNamespaceImport("System") });
                customerNameSpace.Types.Add(customerClass);
                customerUnit.Namespaces.Add(customerNameSpace);

                CodeNamespace customerExtensionsNameSpace = new CodeNamespace(nameSpace);
                customerExtensionsNameSpace.Types.Add(customerExtensionsClass);
                customerExtensionsUnit.Namespaces.Add(customerExtensionsNameSpace);
            }

            for (var i = 0; i < propertyNames.Length; i++)
            {
                string propertyName = propertyNames[i];
                //创建类中的变量
                //                Type.GetType(string.Format("System.{0}", typeNames[i]));
                string fieldName = propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
                CodeMemberField field = new CodeMemberField(Type.GetType(string.Format("System.{0}", typeNames[i])), fieldName);
				field.Attributes = MemberAttributes.Public;
                customerClass.Members.Add(field);

                //创建类中的属性
                CodeMemberProperty property = new CodeMemberProperty();
                property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                property.Name = propertyName.Substring(0, 1).ToUpper() + propertyName.Substring(1);
                property.HasGet = true;
                property.HasSet = true;
                property.Type = new CodeTypeReference(Type.GetType(string.Format("System.{0}", typeNames[i])));
                property.Comments.Add(new CodeCommentStatement(noteNames[i]));
                property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));
                property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression()));
                customerClass.Members.Add(property);
            }

            //创建代码生成类-C#
            CodeDomProvider providerCS = CodeDomProvider.CreateProvider("C#");
            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.BracingStyle = "C";
            options.BlankLinesBetweenMembers = true;

            //生成代码
            string outputFile = string.Format("{0}{1}.cs", EditorStaticValue.OutConfigClassPath, className);
            using (StreamWriter sw = new StreamWriter(outputFile))
            {
                providerCS.GenerateCodeFromCompileUnit(customerUnit, sw, options);
            }

            string outputExtensionsFile = string.Format("{0}{1}.cs", EditorStaticValue.OutConfigExtendClassPath, ExtensionsClassName);
            if (!File.Exists(outputExtensionsFile))
            {
                using (StreamWriter sw = new StreamWriter(outputExtensionsFile))
                {
                    providerCS.GenerateCodeFromCompileUnit(customerExtensionsUnit, sw, options);
                }
            }

            AssetDatabase.Refresh();
            EditorUtility.DisplayDialog("输出类文件", "成功输出所有类文件!!", "确定");
        }
    }
}
();
            ExcelAccess.SelectConfigExcel(ref data);

            if (!Directory.Exists(EditorStaticValue.ConfigScriptObjectPath))
            {
                Directory.CreateDirectory(EditorStaticValue.ConfigScriptObjectPath);
            }
            AssetDatabase.CreateAsset(data, EditorStaticValue.ConfigScriptObjectPath + "Config.asset");
            AssetDatabase.Refresh();
        }

       

        private static DataSet ReadExcel(string excelName)
        {
            string path = FilePath(excelName);
            try
            {
                FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);

                DataSet result = excelReader.AsDataSet();
                return result;
            }
            catch (Exception ex)
            {
                string[] strArr = ex.Message.Split('\\');
                throw new Exception(string.Format("先关闭{0}", strArr[strArr.Length - 1]));
            }
        }
        private static string FilePath(string path)
        {
            return EditorStaticValue.DataFolderPath + "/" + path;
        }
        private static void CreateExcelClass(string tableName, DataRowCollection collection)
        {
            object[] propertyRow = collection[0].ItemArray;

            List allColumnStrList = new List();

            allColumnStrList.Add(GetColumnString(propertyRow));
            for (int row = 1; row < collection.Count; row++)
            {
                allColumnStrList.Add(GetColumnString(collection[row].ItemArray));
            }

            string[] fileLineContent = allColumnStrList.ToArray();
            if (fileLineContent.Length > 0)
            {
                //注释的名字
                string[] noteContents = fileLineContent[0].Split(new string[] {"$"}, System.StringSplitOptions.None);
                //变量的名字
                string[] VariableNameContents = fileLineContent[1].Split(new string[] {"$"}, System.StringSplitOptions.None);
                //变量的类型
                string[] TypeNameContents = fileLineContent[2].Split(new string[] {"$"}, System.StringSplitOptions.None);

                AutoCreateClass(tableName, TypeNameContents, VariableNameContents, noteContents,
                    EditorStaticValue.OutClassNameSpace);
            }
        }

        private static bool CreateAllFolder()
        {
            if (!Directory.Exists(EditorStaticValue.DataFolderPath))
            {
                Directory.CreateDirectory(EditorStaticValue.DataFolderPath);
                Debug.LogError(string.Format("把xlsx配置文件放入{0}文件夹内", EditorStaticValue.DataFolderPath));
                return false;
            }
            if (!Directory.Exists(EditorStaticValue.OutConfigClassPath))
            {
                Directory.CreateDirectory(EditorStaticValue.OutConfigClassPath);
            }
            else
            {
                DeleteAllFileInFolder(EditorStaticValue.OutConfigClassPath, "OutConfigClassPath  Class");
            }
            if (!Directory.Exists(EditorStaticValue.OutConfigExtendClassPath))
            {
                Directory.CreateDirectory(EditorStaticValue.OutConfigExtendClassPath);
            }
            return true;
        }
        private static string GetColumnString(object[] rowData)
        {
            List ss = new List();

            for (int i = 0; i < rowData.Length; i++)
            {
                ss.Add(rowData[i].ToString());
            }
            return string.Join("$", ss.ToArray());
        }
        private static void DeleteAllFileInFolder(string path, string note)
        {
            DirectoryInfo dir = new DirectoryInfo(path);
            FileInfo[] files = dir.GetFiles();

            foreach (var item in files)
            {
                File.Delete(item.FullName);欢迎关注个人公众号:游戏码小喵欢迎关注个人公众号:游戏码小喵
            }
//            Debug.Log(string.Format("成功删除所有{0}文件!!", note));
        }
        /// 
        /// 自动生成类
        /// 
        ///类名.
        ///属性名称数组.
        ///注释数组.
        ///命名空间.
        private static void AutoCreateClass(string className, string[] typeNames, string[] propertyNames, string[] noteNames, string nameSpace)
        {
            //声明自定义类
            CodeTypeDeclaration customerClass = new CodeTypeDeclaration(className);
            customerClass.IsClass = true;
            customerClass.TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
            customerClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(SerializableAttribute))));
            CodeCompileUnit customerUnit = new CodeCompileUnit();//创建代码单元


            string ExtensionsClassName = string.Format("{0}{1}", className, "Extend");
            CodeTypeDeclaration customerExtensionsClass = new CodeTypeDeclaration(ExtensionsClassName);
            customerExtensionsClass.IsClass = true;
            customerExtensionsClass.TypeAttributes = TypeAttributes.Public;
            CodeCompileUnit customerExtensionsUnit = new CodeCompileUnit();//创建代码单元

            //创建命名空间
            if (!string.IsNullOrEmpty(nameSpace))
            {
                CodeNamespace customerNameSpace = new CodeNamespace(nameSpace);
                customerNameSpace.Imports.AddRange(new CodeNamespaceImport[] { new CodeNamespaceImport("System") });
                customerNameSpace.Types.Add(customerClass);
                customerUnit.Namespaces.Add(customerNameSpace);

                CodeNamespace customerExtensionsNameSpace = new CodeNamespace(nameSpace);
                customerExtensionsNameSpace.Types.Add(customerExtensionsClass);
                customerExtensionsUnit.Namespaces.Add(customerExtensionsNameSpace);
            }

            for (var i = 0; i < propertyNames.Length; i++)
            {
                string propertyName = propertyNames[i];
                //创建类中的变量
                //                Type.GetType(string.Format("System.{0}", typeNames[i]));
                string fieldName = propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
                CodeMemberField field = new CodeMemberField(Type.GetType(string.Format("System.{0}", typeNames[i])), fieldName);
				field.Attributes = MemberAttributes.Public;
                customerClass.Members.Add(field);

                //创建类中的属性
                CodeMemberProperty property = new CodeMemberProperty();
                property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                property.Name = propertyName.Substring(0, 1).ToUpper() + propertyName.Substring(1);
                property.HasGet = true;
                property.HasSet = true;
                property.Type = new CodeTypeReference(Type.GetType(string.Format("System.{0}", typeNames[i])));
                property.Comments.Add(new CodeCommentStatement(noteNames[i]));
                property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));
                property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression()));
                customerClass.Members.Add(property);
            }

            //创建代码生成类-C#
            CodeDomProvider providerCS = CodeDomProvider.CreateProvider("C#");
            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.BracingStyle = "C";
            options.BlankLinesBetweenMembers = true;

            //生成代码
            string outputFile = string.Format("{0}{1}.cs", EditorStaticValue.OutConfigClassPath, className);
            using (StreamWriter sw = new StreamWriter(outputFile))
            {
                providerCS.GenerateCodeFromCompileUnit(customerUnit, sw, options);
            }

            string outputExtensionsFile = string.Format("{0}{1}.cs", EditorStaticValue.OutConfigExtendClassPath, ExtensionsClassName);
            if (!File.Exists(outputExtensionsFile))
            {
                using (StreamWriter sw = new StreamWriter(outputExtensionsFile))
                {
                    providerCS.GenerateCodeFromCompileUnit(customerExtensionsUnit, sw, options);
                }
            }

            AssetDatabase.Refresh();
            EditorUtility.DisplayDialog("输出类文件", "成功输出所有类文件!!", "确定");
        }
    }
}


ExcelAccess.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using Assets.Scripts.Comman;
using Excel;
using UnityEngine;
using System.Reflection;
using Assets.Scripts.Config.DataBase;

namespace Assets.Editor
{
    public class ExcelAccess  {

		public static Assembly CureentAssembly = Assembly.Load("Assembly-CSharp");
		public static Assembly EdiotrAssembly = Assembly.Load("Assembly-CSharp-Editor");

        private static ConfigData _holder;
//        private static string currentExcelName = "";

        public static void SelectConfigExcel(ref ConfigData holder)
        {
            _holder = holder;

            string path = Application.dataPath + "/Config/";
            string[] excelFiles = Directory.GetFiles(path);
            foreach (string fileName in excelFiles)
            {
                if (fileName.EndsWith("xlsx"))
                {
                    string[] pathFiled = fileName.Split('/');
                    if (pathFiled.Length > 0)
                    {
                        string xlsfileName = pathFiled[pathFiled.Length - 1];
//                        currentExcelName = xlsfileName;
                        DataSet dataSet = ReadExcel(xlsfileName);
                        DataTableCollection tables = dataSet.Tables;

                        for (int j = 0; j < tables.Count; j++)
                        {
                            AddDataToHolder(tables[j].TableName, tables[j].Rows);
                        }
                    }
                }
            }
        }
        private static void AddDataToHolder(string className, DataRowCollection collection)
        {
            int index = 0;
            object[] propertyRow = collection[EditorStaticValue.ExcelPropertyLine].ItemArray;

            var str = string.Format("{0}.{1}", EditorStaticValue.OutClassNameSpace, className);

			var elementNum = collection.Count - EditorStaticValue.ExcelValueLineStart;



			var arr = Array.CreateInstance(CureentAssembly.GetType(str), elementNum);

            for (int row = EditorStaticValue.ExcelValueLineStart; row < collection.Count; row++)
            {
//                object obj = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(str, false);
				object obj = CureentAssembly.CreateInstance(str, false);
                if (obj == null)
                    return;

                if (collection[row].IsNull(0))
                {
                    continue;
                }
                for (int i = 0; i < propertyRow.Length; i++)
                {
                    string propertyName = propertyRow[i].ToString();

                    if (string.IsNullOrEmpty(propertyName))
                    {
                        continue;
                    }

                    PropertyInfo info = obj.GetType().GetProperty(propertyName);

                    if (info == null)
                    {
                        throw new Exception(string.Format("{0}.cs中{1}属性无法获取,检查是否少写了{1}属性!!!", className, propertyName));
                    }

                    if (info.PropertyType.IsArray)
                    {
                        string s = collection[row][i].ToString();
						var strArr = s.Split(',');
						var n = strArr.Length;

						Type elementType = info.PropertyType.GetElementType();
						var arr11 = Array.CreateInstance(elementType, n);
						for(int j=0;j

EditorStaticValue.cs
using UnityEngine;

namespace Assets.Scripts.Comman
{
    public class EditorStaticValue
    {
        public static readonly string DataFolderPath = Application.dataPath + "/Config/";
        public static readonly string OutConfigClassPath = Application.dataPath + "/Scripts/Config/ConfigDataBase/";
        public static readonly string OutConfigExtendClassPath = Application.dataPath + "/Scripts/Config/ConfigExtend/";
        public static readonly string OutClassNameSpace = "ConfigClassExport";
        public static readonly string ConfigScriptObjectPath = "Assets/Resources/ConfigAsset/";
        public static readonly int ExcelPropertyLine = 1;
        public static readonly int ExcelValueLineStart = 3;

		public static readonly string LocalConfigAssetNames = "ConfigAsset/Config";
    }
}

主要的代码就是这样,如有疑问可以留言,我会认真回复,也希望大家给我留下意见和建议,第一次写,写得不好,见笑了。

 

欢迎关注个人公众号:游戏码小喵

 

 

Unity读取Excel配置文件的插件有很多,其比较常用的有NPOI和ExcelDataReader。 NPOI是 Apache 的一个开源项目,它可以帮助我们在Unity读取、写入和操作Excel文件。NPOI提供了一系列的类和方法,可以很方便地打开Excel文件,读取的数据,并将其转换成对应的对象。我们只需要将NPOI的DLL文件导入到Unity项目,并在代码引入相关命名空间,就可以开始使用NPOI了。 另一个常用的插件是ExcelDataReader,它也是一个开源项目,可以在Unity读取Excel文件。与NPOI不同的是,ExcelDataReader不需要额外导入文件,它是直接在运行时解析Excel文件的。我们可以通过ExcelDataReader提供的API来打开Excel文件,并读取的数据。ExcelDataReader支持各种常见的Excel文件格式,包括XLS、XLSX等。 无论是使用NPOI还是ExcelDataReader,读取Excel配置文件的过程基本相似。首先,我们需要确定Excel文件的路径,然后使用相应的方法打开Excel文件。接下来,我们可以使用循环遍历的方式读取Excel表格的每一行,然后获取每个单元格的值。在读取Excel数据后,我们可以将其转化为我们需要的数据结构,例如数组、字典或自定义的对象。最后,我们可以根据读取到的数据进行相应的处理,例如初始化游戏的配置参数或生成游戏的物体。 总之,Unity读取Excel配置文件的插件可以帮助我们方便地获取Excel的数据,并在游戏进行处理和应用。根据具体需求,我们可以选择合适的插件来实现读取Excel配置文件的功能。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值