Unity 編輯器開發 之 Excel導表工具

一個簡單的Excel導表工具,可以用來熱更數據配置

工具使用:

  1. 執行菜單 SDGSupporter/Excel/1.Excel2Cs 生成c#腳本。
  2. 等待C#類編譯完成
  3. 執行菜單 SDGSupporter/Excel/2.Excel2Bytes 生成XmI臨時文件,生成bytes二進制表格數據,刪除xml臨時文件。
  4. 運行場景SampleScene.unity Console面板打印表格內容。

工具代碼:

Assets\Editor\Excel2CsBytesTool.cs 文件夾路徑可配置在這里Assets\Scripts\BaseTable.cs Excel配置時支持的類型數組

源Excel文件夾:

ExcelData

生成的C#類:

eg: Assets \Scripts \DataTable \weapon.cs

生成的bytes文件:

eg: Resources \DataTable \weapon.bytes

首先準備一個Excel表 填入數據,注意需要放在Edior目錄下

然后編寫Excel2CsBytesTool.cs腳本

附上完整代碼:

using System.IO;
using Excel;
using System.Data;
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Table;
using System;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization.Formatters.Binary;/// <summary>
/// Excel生成bytes和cs工具
/// </summary>
public class Excel2CsBytesTool
{static string ExcelDataPath = Application.dataPath + "/../ExcelData";//源Excel文件夾,xlsx格式static string BytesDataPath = Application.dataPath + "/Resources/DataTable";//生成的bytes文件夾static string CsClassPath = Application.dataPath + "/Scripts/DataTable";//生成的c#腳本文件夾static string XmlDataPath = ExcelDataPath + "/tempXmlData";//生成的xml(臨時)文件夾..static string AllCsHead = "all";//序列化結構體的數組類.類名前綴static char ArrayTypeSplitChar = '#';//數組類型值拆分符: int[] 1#2#34 string[] 你好#再見 bool[] true#false ...static bool IsDeleteXmlInFinish = true;//生成bytes后是否刪除中間文件xml[MenuItem("SDGSupporter/Excel/Excel2Cs")]static void Excel2Cs(){Init();Excel2CsOrXml(true);}[MenuItem("SDGSupporter/Excel/Excel2Bytes")]static void Excel2Xml2Bytes(){Init();//生成中間文件xmlExcel2CsOrXml(false);//生成bytesWriteBytes();}static void Init(){if (!Directory.Exists(CsClassPath)){Directory.CreateDirectory(CsClassPath);}if (!Directory.Exists(XmlDataPath)){Directory.CreateDirectory(XmlDataPath);}if (!Directory.Exists(BytesDataPath)){Directory.CreateDirectory(BytesDataPath);}}static void WriteCs(string className, string[] names, string[] types, string[] descs){try{StringBuilder stringBuilder = new StringBuilder();stringBuilder.AppendLine("using System;");stringBuilder.AppendLine("using System.Collections.Generic;");stringBuilder.AppendLine("using System.IO;");stringBuilder.AppendLine("using System.Runtime.Serialization.Formatters.Binary;");stringBuilder.AppendLine("using System.Xml.Serialization;");stringBuilder.Append("\n");stringBuilder.AppendLine("namespace Table");stringBuilder.AppendLine("{");stringBuilder.AppendLine("    [Serializable]");stringBuilder.AppendLine("    public class " + className);stringBuilder.AppendLine("    {");for (int i = 0; i < names.Length; i++){stringBuilder.AppendLine("        /// <summary>");stringBuilder.AppendLine("        /// " + descs[i]);stringBuilder.AppendLine("        /// </summary>");stringBuilder.AppendLine("        [XmlAttribute(\"" + names[i] + "\")]");string type = types[i];if (type.Contains("[]")){//type = type.Replace("[]", "");//stringBuilder.AppendLine("        public List<" + type + "> " + names[i] + ";");//可選代碼://用_name字段去反序列化,name取_name.item的值,直接返回list<type>。//因為xml每行可能有多個數組字段,這樣就多了一層變量item,所以訪問的時候需要.item才能取到list<type>//因此用額外的一個變量直接返回List<type>。type = type.Replace("[]", "");stringBuilder.AppendLine("        public List<" + type + "> " + names[i] + "");stringBuilder.AppendLine("        {");stringBuilder.AppendLine("            get");stringBuilder.AppendLine("            {");stringBuilder.AppendLine("                if (_" + names[i] + " != null)");stringBuilder.AppendLine("                {");stringBuilder.AppendLine("                    return _" + names[i] + ".item;");stringBuilder.AppendLine("                }");stringBuilder.AppendLine("                return null;");stringBuilder.AppendLine("            }");stringBuilder.AppendLine("        }");stringBuilder.AppendLine("        [XmlElementAttribute(\"" + names[i] + "\")]");stringBuilder.AppendLine("        public " + type + "Array _" + names[i] + ";");}else{stringBuilder.AppendLine("        public " + type + " " + names[i] + ";");}stringBuilder.Append("\n");}stringBuilder.AppendLine("        public static List<" + className + "> LoadBytes()");stringBuilder.AppendLine("        {");stringBuilder.AppendLine("            string bytesPath = \"" + BytesDataPath + "/" + className + ".bytes\";");stringBuilder.AppendLine("            if (!File.Exists(bytesPath))");stringBuilder.AppendLine("                return null;");stringBuilder.AppendLine("            using (FileStream stream = new FileStream(bytesPath, FileMode.Open))");stringBuilder.AppendLine("            {");stringBuilder.AppendLine("                BinaryFormatter binaryFormatter = new BinaryFormatter();");stringBuilder.AppendLine("                all" + className + " table = binaryFormatter.Deserialize(stream) as all" + className + ";");stringBuilder.AppendLine("                return table." + className + "s;");stringBuilder.AppendLine("            }");stringBuilder.AppendLine("        }");stringBuilder.AppendLine("    }");stringBuilder.Append("\n");stringBuilder.AppendLine("    [Serializable]");stringBuilder.AppendLine("    public class " + AllCsHead + className);stringBuilder.AppendLine("    {");stringBuilder.AppendLine("        public List<" + className + "> " + className + "s;");stringBuilder.AppendLine("    }");stringBuilder.AppendLine("}");string csPath = CsClassPath + "/" + className + ".cs";if (File.Exists(csPath)){File.Delete(csPath);}using (StreamWriter sw = new StreamWriter(csPath)){sw.Write(stringBuilder);Debug.Log("生成:" + csPath);}}catch (System.Exception e){Debug.LogError("寫入CS失敗:" + e.Message);throw;}}static void WriteXml(string className, string[] names, string[] types, List<string[]> datasList){try{StringBuilder stringBuilder = new StringBuilder();stringBuilder.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");stringBuilder.AppendLine("<" + AllCsHead + className + ">");stringBuilder.AppendLine("<" + className + "s>");for (int d = 0; d < datasList.Count; d++){stringBuilder.Append("\t<" + className + " ");//單行數據string[] datas = datasList[d];//填充屬性節點for (int c = 0; c < datas.Length; c++){string type = types[c];if (!type.Contains("[]")){string name = names[c];string value = datas[c];stringBuilder.Append(name + "=\"" + value + "\"" + (c == datas.Length - 1 ? "" : " "));}}stringBuilder.Append(">\n");//填充子元素節點(數組類型字段)for (int c = 0; c < datas.Length; c++){string type = types[c];if (type.Contains("[]")){string name = names[c];string value = datas[c];string[] values = value.Split(ArrayTypeSplitChar);stringBuilder.AppendLine("\t\t<" + name + ">");for (int v = 0; v < values.Length; v++){stringBuilder.AppendLine("\t\t\t<item>" + values[v] + "</item>");}stringBuilder.AppendLine("\t\t</" + name + ">");}}stringBuilder.AppendLine("\t</" + className + ">");}stringBuilder.AppendLine("</" + className + "s>");stringBuilder.AppendLine("</" + AllCsHead + className + ">");string xmlPath = XmlDataPath + "/" + className + ".xml";if (File.Exists(xmlPath)){File.Delete(xmlPath);}using (StreamWriter sw = new StreamWriter(xmlPath)){sw.Write(stringBuilder);Debug.Log("生成文件:" + xmlPath);}}catch (System.Exception e){Debug.LogError("寫入Xml失敗:" + e.Message);}}static void Excel2CsOrXml(bool isCs){string[] excelPaths = Directory.GetFiles(ExcelDataPath, "*.xlsx");for (int e = 0; e < excelPaths.Length; e++){//0.讀Excelstring className;//類型名string[] names;//字段名string[] types;//字段類型string[] descs;//字段描述List<string[]> datasList;//數據try{string excelPath = excelPaths[e];//excel路徑  className = Path.GetFileNameWithoutExtension(excelPath).ToLower();FileStream fileStream = File.Open(excelPath, FileMode.Open, FileAccess.Read);IExcelDataReader excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(fileStream);// 表格數據全部讀取到result里DataSet result = excelDataReader.AsDataSet();// 獲取表格列數int columns = result.Tables[0].Columns.Count;// 獲取表格行數int rows = result.Tables[0].Rows.Count;// 根據行列依次讀取表格中的每個數據names = new string[columns];types = new string[columns];descs = new string[columns];datasList = new List<string[]>();for (int r = 0; r < rows; r++){string[] curRowData = new string[columns];for (int c = 0; c < columns; c++){//解析:獲取第一個表格中指定行指定列的數據string value = result.Tables[0].Rows[r][c].ToString();//清除前兩行的變量名、變量類型 首尾空格if (r < 2){value = value.TrimStart(' ').TrimEnd(' ');}curRowData[c] = value;}//解析:第一行類變量名if (r == 0){names = curRowData;}//解析:第二行類變量類型else if (r == 1){types = curRowData;}//解析:第三行類變量描述else if (r == 2){descs = curRowData;}//解析:第三行開始是數據else{datasList.Add(curRowData);}}}catch (System.Exception exc){Debug.LogError("請關閉Excel:" + exc.Message);return;}if (isCs){//寫CsWriteCs(className, names, types, descs);}else{//寫XmlWriteXml(className, names, types, datasList);}}AssetDatabase.Refresh();}static void WriteBytes(){string csAssemblyPath = Application.dataPath + "/../Library/ScriptAssemblies/Assembly-CSharp.dll";Assembly assembly = Assembly.LoadFile(csAssemblyPath);if (assembly != null){Type[] types = assembly.GetTypes();for (int i = 0; i < types.Length; i++){Type type = types[i];if (type.Namespace == "Table" && type.Name.Contains(AllCsHead)){string className = type.Name.Replace(AllCsHead, "");//讀取xml數據string xmlPath = XmlDataPath + "/" + className + ".xml";if (!File.Exists(xmlPath)){Debug.LogError("Xml文件讀取失敗:" + xmlPath);continue;}object table;using (Stream reader = new FileStream(xmlPath, FileMode.Open)){//讀取xml實例化table: all+classname//object table = assembly.CreateInstance("Table." + type.Name);XmlSerializer xmlSerializer = new XmlSerializer(type);table = xmlSerializer.Deserialize(reader);}//obj序列化二進制string bytesPath = BytesDataPath + "/" + className + ".bytes";if (File.Exists(bytesPath)){File.Delete(bytesPath);}using (FileStream fileStream = new FileStream(bytesPath, FileMode.Create)){BinaryFormatter binaryFormatter = new BinaryFormatter();binaryFormatter.Serialize(fileStream, table);Debug.Log("生成:" + bytesPath);}if (IsDeleteXmlInFinish){File.Delete(xmlPath);Debug.Log("刪除:" + bytesPath);}}}}if (IsDeleteXmlInFinish){Directory.Delete(XmlDataPath);Debug.Log("刪除:" + XmlDataPath);}}
}

接著是自定義的數據配置類:

using System;
using System.Collections.Generic;
using System.Xml.Serialization;/// <summary>
/// Excel2CsBytesTool
/// Excel可以配置的數組類型:string[] int[] bool[] 
/// 可自行擴展
/// </summary>
namespace Table
{[System.SerializableAttribute()][System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]public class stringArray{[System.Xml.Serialization.XmlElementAttribute("item")]public List<string> item { get; set; }}[System.SerializableAttribute()][System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]public class intArray{[System.Xml.Serialization.XmlElementAttribute("item")]public List<int> item { get; set; }}[System.SerializableAttribute()][System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]public class boolArray{[System.Xml.Serialization.XmlElementAttribute("item")]public List<bool> item { get; set; }}
}

然后就可以在Unity菜單界面看到我們的編輯器工具了

先點擊Execl2Cs生成相應的C#腳本(會先清除原先的) 其后點擊2Bytes,將數據序列化成二進制

等待執行完成后點擊運行。便可以看到我們的consloe界面出現我們在Excel表中配置的數據。

Excel導表工具就完成了。可以自行擴展。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91119.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91119.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91119.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【數據結構與算法】力扣 415. 字符串相加

題目描述 415. 字符串相加 給定兩個字符串形式的非負整數 num1 和num2 &#xff0c;計算它們的和并同樣以字符串形式返回。 你不能使用任何內建的用于處理大整數的庫&#xff08;比如 BigInteger&#xff09;&#xff0c; 也不能直接將輸入的字符串轉換為整數形式。 示例 1…

進階向:Manus AI與多語言手寫識別

Manus AI與多語言手寫識別:從零開始理解 手寫識別技術作為人工智能領域的重要應用之一,近年來在智能設備、教育、金融等行業得到了廣泛運用。根據市場調研機構IDC的數據顯示,2022年全球手寫識別市場規模已達到45億美元,預計到2025年將突破70億美元。其中,多語言手寫識別技…

Javaweb————HTTP請求頭屬性講解

??????????????????????前面我們已經說過http請求分為三部分&#xff0c;請求行&#xff0c;請求頭和請求體 請求頭包含若干個屬性&#xff1a;格式為屬性名&#xff1a;屬性值&#xff0c;這篇文章我們就來介紹一下http請求頭中一些常見屬性的含義 我們…

9.c語言常用算法

查找順序查找&#xff08;線性查找&#xff09;算法思想&#xff1a;從數組的第一個元素開始&#xff0c;逐個與目標值進行比較&#xff0c;直到找到目標值或查找完整個數組。時間復雜度&#xff1a;最好情況&#xff1a;O(1)&#xff08;目標在第一個位置&#xff09;最壞情況…

AI小智源碼分析——音頻部分(一)

一、源碼跳轉這里采用了函數重載來進行代碼復用&#xff0c;當需要對I2S接口的數據進行配置&#xff0c;比如左右音道切換&#xff0c;可以使用第二個構造函數&#xff0c;這里小智使用的是第一個構造函數&#xff0c;即只傳遞I2S相關的引腳參數&#xff08;不帶slot mask&…

【GNSS原理】【LAMBDA】Chapter.12 GNSS定位算法——模糊度固定LAMBDA算法[2025年7月]

Chapter.12 GNSS定位算法——模糊度固定LAMBDA算法 作者&#xff1a;齊花Guyc(CAUC) 文章目錄Chapter.12 GNSS定位算法——模糊度固定LAMBDA算法一.整周模糊度理論1.LAMBDA算法干了一件什么事情&#xff1f;2.LAMBDA算法步驟&#xff08;1&#xff09;去相關&#xff08;Z變換…

計算機畢業設計java在線二手系統的設計與實現 基于Java的在線二手交易平臺開發 Java技術驅動的二手物品管理系統

計算機畢業設計java在線二手系統的設計與實現z2n189&#xff08;配套有源碼 程序 mysql數據庫 論文&#xff09; 本套源碼可以在文本聯xi,先看具體系統功能演示視頻領取&#xff0c;可分享源碼參考。隨著互聯網技術的飛速發展&#xff0c;二手交易市場也逐漸從傳統的線下模式轉…

如何進行項目復盤?核心要點分析

進行項目復盤需要明確復盤目標、確定復盤參與人員、選擇合適的復盤方法、梳理項目過程與關鍵節點、分析成功與失敗的原因、總結經驗教訓并制定改進計劃。其中&#xff0c;選擇合適的復盤方法尤其關鍵&#xff0c;常見的復盤方法包括魚骨圖分析法、SWOT分析法、PDCA循環法&#…

LeetCode 923.多重三數之和

給定一個整數數組 arr &#xff0c;以及一個整數 target 作為目標值&#xff0c;返回滿足 i < j < k 且 arr[i] arr[j] arr[k] target 的元組 i, j, k 的數量。 由于結果會非常大&#xff0c;請返回 109 7 的模。 示例 1&#xff1a; 輸入&#xff1a;arr [1,1,2,2,…

.Net日志系統Logging-五

日志概念 日志級別 NET (Microsoft.Extensions.Logging) 中定義的 6 個標準日志級別&#xff0c;按嚴重性從低到高排列&#xff1a; 日志級別數值描述典型使用場景Trace0最詳細的信息&#xff0c;包含敏感數據&#xff08;如請求體、密碼哈希等&#xff09;。僅在開發或深度故…

中國貿促會融媒體中心出海活動負責人、出海星球創始人蒞臨綠算技術

近日&#xff0c;中國貿促會融媒體中心出海活動負責人、出海星球創始人王思諾一行蒞臨廣東省綠算技術有限公司&#xff0c;深入考察其核心技術產品與全球化布局。雙方圍繞綠算技術全棧產品體系、創新出海模式及生態共建展開深度對話。綠算技術作為國內智算基礎設施領域的領軍企…

【算法專題訓練】06、數組雙指針

1、數組 數組是由相同類型的元素組成的數據集合&#xff0c;并且占據一塊連續的內存&#xff0c;按照順序存儲數據。 1.1、數組的特性&#xff1a; 數組元素通過下標獲取數據數組對象初始化時&#xff0c;需要先指定數組容量大小&#xff0c;并根據容量大小分配內存。缺點&…

操作系統-lecture2(操作系統結構)

回顧下lecture1 swap區域不可以馬上執行&#xff0c;即虛擬內存的數據和指令不可以被執行&#xff0c;得交換回到內存區域 操作系統的服務 主要提供兩種服務 面向普通用戶&#xff1a;user interface面向程序員&#xff1a;應用級程序代碼 為用戶 為用戶提供了操作包括但不…

內網服務器實現從公網穿透

從6月份tplink的ddns失效之后&#xff0c;對于部分在內網運行的服務器&#xff0c;從公網訪問就收到了部分影響。有好幾個朋友找來&#xff0c;尋求幫助&#xff0c;看看怎么恢復原來的機制&#xff0c;可以從公網互聯網訪問內網服務器。方案一&#xff1a;如果有動態公網的客戶…

vcs-編譯+仿真+dump波形【IMP】

VCS仿真分為兩步式(編譯/compilation仿真/simulation)和三步式(分析/analysis細化/elaborationsimulation/仿真);注2:analysis/分析是三步式flow中仿真design的第一步&#xff0c;在此階段將使用vhdlan或vlogan分析VHDL、Verilog、SystemVerilog和OpenVera文件。下面的部分包括…

程序代碼篇---python向http界面發送數據

在 Python 中向 HTTP 界面發送數據&#xff0c;本質上是模擬用戶在網頁上填寫表單、點擊提交按鈕的過程。這在自動化測試、數據上報、接口調用等場景中非常常用。下面用通俗易懂的方式介紹具體方法、實例代碼和解析。核心原理網頁上的數據發送&#xff08;比如提交表單&#xf…

mybatis-plus由mysql改成達夢數據庫

前置條件: 達夢數據庫設置了大小寫敏感,我比較菜,改不動!先這么湊合著用吧; 因為設置了大小寫敏感,所以所有的sql語句都要加 引號; 這樣是會報錯的: SELECT remark,createDept,createBy,createTime,updateBy,updateTime FROM sys_oss_config這樣才可以 SELECT "create_…

設計模式:外觀模式 Facade

目錄前言問題解決方案結構代碼前言 外觀是一種結構型設計模式&#xff0c;能為程序庫、框架或其他復雜類提供一個簡單的接口。 問題 假設你必須在代碼中使用某個復雜的庫或框架中的眾多對象。正常情況下&#xff0c; 你需要負責所有對象的初始化工作、 管理其依賴關系并按正確…

【數據結構初階】--二叉樹(四)

&#x1f525;個人主頁&#xff1a;草莓熊Lotso &#x1f3ac;作者簡介&#xff1a;C研發方向學習者 &#x1f4d6;個人專欄&#xff1a; 《C語言》 《數據結構與算法》《C語言刷題集》《Leetcode刷題指南》 ??人生格言&#xff1a;生活是默默的堅持&#xff0c;毅力是永久的…

三、平面度檢測-差值法

方法一: dev_get_window (WindowHandle) *讀取3通道彩色融合圖 read_image (Image, ./XYZ彩色融合圖.tiff) *拆分3個通道 decompose3 (Image, x, y, z) *將3個通道圖像轉換為3D模型 xyz_to_object_model_3d (x,y, z, ObjectModel3D) *顯示動態3D模型 threshold (z, Regions,…