前言
关于unity读excel配置表操作,其实之前就有用过,这里只是单独整理出这部分知识,后续好使用。
感兴趣可以去看看:【用unity实现100个游戏之7】从零开始制作一个仿杀戮尖塔卡牌回合制游戏(附项目源码)
下载资源库
读取Excel需要用到Excel.dll 和ICSharpCode.SharpZipLib库文件
这里我把两个库都放在百度云了,大家可以自行去下载
链接:https://pan.baidu.com/s/1iM-E5TSAxtlWOAhMmWy1ZQ?pwd=s8o4
提取码:s8o4
导入资源库
将前面下载的这两个dll库放进项目即可
excel转txt文本
新建MyEditor.cs放在Editor
目录下
MyEditor.cs代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor;//编辑器的命名空间 using System.IO;//文件流 using Excel;//读取excel using System.Data; //编辑器脚本 public static class MyEditor { [MenuItem("我的工具/excel转成txt")] public static void ExportExcelToTxt() { //_Excel文件夹路径 string assetPath = Application.dataPath + "/_Excel"; //获得Excel文件夹中的excel文件 string[] files = Directory.GetFiles(assetPath, "*.xlsx"); for (int i = 0; i < files.Length; i++) { files[i] = files[i].Replace('\\', '/');//反斜杠替换成正斜杠 //通过文件流读取文件 using (FileStream fs = File.Open(files[i], FileMode.Open, FileAccess.Read)) { //文件流转成excel 对象 var excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(fs); //获得excel数据 DataSet dataSet = excelDataReader.AsDataSet(); //读取excel第一张表 DataTable table = dataSet.Tables[0]; //将表中内容 读取后 存储到 对应的txt文件 readTableToTxt(files[i], table); } } //刷新编辑器 AssetDatabase.Refresh(); } private static void readTableToTxt(string filePath, DataTable table) { // 获得文件名(不要文件后缀 生成与之名字相同的txt文件) string fileName = Path.GetFileNameWithoutExtension(filePath); // txt文件存储的路径 string path = Application.dataPath + "/Resources/Data/" + fileName + ".txt"; //判断Resources/Data文件夹中是否已经存在对应的txt文件,如果是 则删除 if (File.Exists(path)) { File.Delete(path); } // 文件流创建txt文件 using (FileStream fs = new FileStream(path, FileMode.Create)) { // 文件流转写入流方便写入字符串 using (StreamWriter sw = new StreamWriter(fs)) { // 遍历table for (int row = 0; row < table.Rows.Count; row++) { DataRow dataRow = table.Rows[row]; string str = ""; //遍历列 for (int col = 0; col < table.Columns.Count; col++) { string val = dataRow[col].ToString(); str = str + val + "\t";//每一项tab分割 } //写入 sw.Write(str); //如果不是最后一行换行 if (row != table.Rows.Count - 1) { sw.WriteLine(); } } } } } }
记得在Resources目录下新建Data文件夹用来存放生成的txt文本,我们的xlsx配置表信息就放在_Excel文件夹下,点击我的工具->excel转成txt
,会将_Excel文件夹里的xlsx文件生成为txt保存到/Resources/Data/目录下
配置表大概样式
card.xlsx
转为txt后内容如下
读取txt内容
新增GameConfigData,定义读取配置表类
using System.Collections; using System.Collections.Generic; using UnityEngine; // 游戏配置表类,每个对象对应一个xt配置表 public class GameConfigData { // 存储配置表中的所有数据 private List<Dictionary<string, string>> dataDic; // 构造函数,参数为字符串 public GameConfigData(string str) { // 初始化数据字典 dataDic = new List<Dictionary<string, string>>(); // 按换行符切割字符串 string[] lines = str.Split('\n'); // 第一行是存储数据的类型 string[] title = lines[0].Trim().Split('\t');//tab切割 // 从第三行(下标为2)开始遍历数据,第二行数据是解释说明 for (int i = 2; i < lines.Length; i++) { // 创建新的字典存储每行数据 Dictionary<string, string> dic = new Dictionary<string, string>(); // 按tab切割每行数据 string[] tempArr = lines[i].Trim().Split("\t"); // 将切割后的数据添加到字典中 for (int j = 0; j < tempArr.Length; j++) { dic.Add(title[j], tempArr[j]); } // 将字典添加到数据列表中 dataDic.Add(dic); } } // 获取所有行的数据 public List<Dictionary<string, string>> GetLines() { return dataDic; } // 根据ID获取一行数据 public Dictionary<string, string> GetOneById(string id) { // 遍历数据列表 for (int i = 0; i < dataDic.Count; i++) { // 获取当前字典 Dictionary<string, string> dic = dataDic[i]; // 如果字典中的ID与参数相同,返回该字典 if (dic["Id"] == id) { return dic; } } // 如果没有找到,返回null return null; } }
新增GameConfigManager.cs,读取不同配置表信息配置
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using UnityEngine; // 游戏配置管理类 public class GameConfigManager { // 单例模式 public static GameConfigManager Instance = new GameConfigManager(); private GameConfigData cardData;//卡牌表 private GameConfigData enemyData;//敌人表 private GameConfigData levelData;//关卡表 private GameConfigData cardTypeData; //卡牌类型 // 文本资源 private TextAsset textAsset; // 初始化配置文件(txt文件 存储到内存) public void Init() { // 加载卡牌数据 textAsset = Resources.Load<TextAsset>("Data/card"); cardData = new GameConfigData(textAsset.text); // 加载敌人数据 textAsset = Resources.Load<TextAsset>("Data/enemy"); enemyData = new GameConfigData(textAsset.text); // 加载关卡数据 textAsset = Resources.Load<TextAsset>("Data/level"); levelData = new GameConfigData(textAsset.text); //卡牌类型数据 textAsset = Resources.Load<TextAsset>("Data/cardType"); cardTypeData = new GameConfigData(textAsset.text); } // 获取卡牌行数据 public List<Dictionary<string, string>> GetCardLines() { return cardData.GetLines(); } // 获取敌人行数据 public List<Dictionary<string, string>> GetEnemyLines() { return enemyData.GetLines(); } // 获取关卡行数据 public List<Dictionary<string, string>> GetLevelLines() { return levelData.GetLines(); } // 根据ID获取卡牌数据 public Dictionary<string, string> GetCardById(string id) { return cardData.GetOneById(id); } // 根据ID获取敌人数据 public Dictionary<string, string> GetEnemyById(string id) { return enemyData.GetOneById(id); } // 根据ID获取关卡数据 public Dictionary<string, string> GetLevelById(string id) { return levelData.GetOneById(id); } //根据ID获取卡牌类型 public Dictionary<string, string> GetCardTypeById(string id) { return cardTypeData.GetOneById(id); } }
调用测试
//初始化配置表 GameConfigManager.Instance.Init(); //测试 string name = GameConfigManager.Instance.GetCardById("1001")["Name"]; print(name);
运行效果,输出正确
读取配置表所有的数据,并使用
比如配置表大概样式
level.xlsx
转换为txt文本后效果
GameConfigManager代码如下
using System.Collections.Generic; using UnityEngine; // 游戏配置管理类 public class GameConfigManager { public static GameConfigManager Instance = new GameConfigManager(); private GameConfigData levelData;//关卡数据 // 文本资源 private TextAsset textAsset; // 初始化配置文件(txt文件 存储到内存) public void Init() { // 加载关卡数据 textAsset = Resources.Load<TextAsset>("Data/level"); levelData = new GameConfigData(textAsset.text); } // 获取关卡行数据 public List<Dictionary<string, string>> GetLevelLines() { return levelData.GetLines(); } // 根据ID获取关卡数据 public Dictionary<string, string> GetLevelById(string id) { return levelData.GetOneById(id); } }
新增GenerateZombies 调用配置表信息并使用
using System.Collections; using System.Collections.Generic; using Unity.Mathematics; using Unity.VisualScripting; using UnityEngine; public class GenerateZombies : MonoBehaviour { public static GenerateZombies Instance { get; private set; } public GameObject zombiePrefab; //僵尸预制体 public int curLevelId = 1; //当前关卡 public int curProgressId = 1;//当前进度 public List<GameObject> curProgressZombie;//保存当前进度的敌人 int zOrderIndex = 0;//排序 private void Awake() { Instance = this; } private void Start() { curProgressZombie = new List<GameObject>(); //初始化配置表 GameConfigManager.Instance.Init(); TableCreateZombie(); } //生成僵尸 private void TableCreateZombie() { //判断是否是最后一波敌人,如果表格中当前进度没有可以创建的敌人,及游戏胜利 bool canCreate = false; //获取关卡行数据 List<Dictionary<string, string>> listData = GameConfigManager.Instance.GetEnemyLines(); listData.ForEach(data => { //属于当前关卡的僵尸 if (data["levelID"] == curLevelId.ToString() && data["progressId"] == curProgressId.ToString()) { //延迟一段时间创建僵尸 StartCoroutine(ITableCreateZombie(data)); //代表当前进度有敌人 canCreate = true; } }); if(!canCreate){ StopAllCoroutines();//停止所有的携程 //TODO:游戏胜利处理 Debug.Log("游戏胜利"); } } IEnumerator ITableCreateZombie(Dictionary<string, string> levelItem) { yield return new WaitForSeconds(float.Parse(levelItem["createTime"])); //加载预制件:从Resources文件夹中加载,例如Zombie1 GameObject zombiePrefab = Resources.Load("Prefabs/Zombie" + levelItem["zombieType"]) as GameObject; //生成僵尸实例 GameObject zombie = Instantiate(zombiePrefab); //根据配表的生成位置,找到父物体 Transform zombieLine = transform.GetChild(int.Parse(levelItem["bornPos"])); zombie.transform.parent = zombieLine; zombie.transform.localPosition = Vector3.zero; zombie.GetComponent<SpriteRenderer>().sortingOrder = zOrderIndex; zOrderIndex ++; curProgressZombie.Add(zombie); } //消灭敌人 public void ZombieDied(GameObject gameObject){ if(curProgressZombie.Contains(gameObject)){ curProgressZombie.Remove(gameObject); } //当前进度的僵尸全部消灭了,开启下一个进度 if(curProgressZombie.Count == 0){ curProgressId += 1; TableCreateZombie(); } } }
消灭敌人时调用,控制游戏进度变化
GenerateZombies.Instance.ZombieDied(gameObject);
效果
稍后补充