【unity小技巧】unity读excel配置表操作,excel转txt文本,并读取txt文本内容,实例说明

news2025/2/7 17:38:57

文章目录

  • 前言
  • 下载资源库
  • 导入资源库
  • excel转txt文本
    • 读取txt内容
  • 读取配置表所有的数据,并使用
  • 结束语

前言

关于unity读excel配置表操作,其实之前就有用过,这里只是单独整理出这部分知识,后续好使用。
感兴趣可以去看看:【用unity实现100个游戏之7】从零开始制作一个仿杀戮尖塔卡牌回合制游戏(附项目源码)

下载资源库

读取Excel需要用到Excel.dllICSharpCode.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);

效果
稍后补充

结束语

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1702563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【408精华知识】时钟周期、机器周期、总线周期、指令周期、存取周期还傻傻分不清?

在做题时&#xff0c;我们经常能遇到关于“周期”的表述&#xff0c;比如时钟周期、机器周期、总线周期、指令周期、存取周期&#xff0c;类似的表述让我们很容易迷茫&#xff0c;那么接下来我们就看看它们到底是什么、有什么区别&#xff1f; 周期特点时钟周期也称为CPU时钟周…

太速科技-基于FPGA Spartan6 的双路光纤PCIe采集卡(2路光纤卡)

基于FPGA Spartan6 的双路光纤PCIe采集卡(2路光纤卡) 1、板卡概述   板卡采用xilinx Spartan6系列芯片&#xff0c;支持 PCI Express Base Specification 1.1 x1。内含丰富的逻辑资源和存储单元&#xff0c;板卡FPGA外接双片32M*16bit DDR2缓存器&#xff0c;支持乒乓操作。…

【Linux进程篇】父子进程fork函数||进程生死轮回状态||僵尸进程与孤儿进程

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 前言&#xff1a;上篇文章中我们认识了进程&#xff0c;可执行程序在内存中加载运行被称作进程&#xff0c;而操作系统是通过给每一个可执行程序创建一个PCB来管理进程的。并且学习了一些查看进程的指令&#xff0c;认识…

利用机器非学习进行后门攻击

信息安全是一个古老的计算机领域。许多 80 后还记得自己小时候经常听到的瑞星杀毒和江民杀毒软件。这些 90 年代火遍大江南北的信息安全工具&#xff0c;至今仍然影响着使用互联网和信息技术的千家万户。随着人工智能的兴起和普及&#xff0c;有越来越多的商业软件使用了人工智…

5.2网安学习第五阶段第二周回顾(个人学习记录使用)

本周重点 ①HIDS的基本应用(suricata) ②Suricata的基本应用 ③Suricata的流量检测 ④Suricata的https流量检测 ⑤利用Elastic整合Suricata日志 ⑥利用Wazuh对Suricata主动响应 本周主要内容 ①HIDS的基本应用(suricata) 1、NIDS 1、定义&#xff1a;网络入侵检测系统…

【软件设计师】——6.程序设计语言与语言处理程序

目录 6.1基本概念 6.2编译与解释 6.3文法 6.4有限自动机 6.5正规式 6.6 表达式 6.7 传值与引用 6.8 数据类型与程序控制结构 6.9 程序语言特点 6.10 Java程序设计 6.11 C 6.12 python 6.1基本概念 语句&#xff1a;高级程序设计语言中描述程序的运算步骤、控制结构、…

vue3父组件改变 子组件不改变(uniapp)

项目中遇到了这么个问题 场景&#xff1a;封装select组件&#xff0c;通过子组件选中后传递值给父组件&#xff0c;父组件需要回显这个值&#xff08;这里使用 defineProps和defineEmits就可以实现&#xff0c;或者直接使用defineModel也可以实现&#xff0c;但是uniapp目前不…

语音深度鉴伪识别项目实战:基于深度学习的语音深度鉴伪识别算法模型(一)音频数据编码与预处理

前言 深度学习技术在当今技术市场上面尚有余力和开发空间的&#xff0c;主流落地领域主要有&#xff1a;视觉&#xff0c;听觉&#xff0c;AIGC这三大板块。目前视觉板块的框架和主流技术在我上一篇基于Yolov7-LPRNet的动态车牌目标识别算法模型已有较为详细的解说。与AIGC相关…

vue3父子组件通信,子组件修改父组件传过来的值

一、第一种&#xff0c;通过props方式传值&#xff1a; 父组件&#xff1a; 父组件调用子组件Child1时通过 :msg2 "msg2"把msg2的数据传给子组件&#xff0c;并且通过自定义事件接收子组件的emit通知&#xff0c;用来修改父组件的msg2数据。 源码&#xff1a; &l…

借助 CloudFlare 增强站点内容保护防采集

今天在一位站长的帮助下实测了 CloudFlare 增强站点内容保护实现防采集的功能,效果那是杠杠的,如果您的站点原创内容比较多的话,明月强烈建议试试 CloudFlare 这个内容保护,无论是 WordPress 、Typecho 都有非常好的效果,并且几乎没有任何误伤,搜索引擎爬虫蜘蛛更是不会影…

制作ARM架构 docker镜像

docker简介 docker客户端 Docker 客户端有两种替代选项:名为 docker 的命令行应用程序或名为 Docker Desktop 的基于图形用户界面 (GUI) 的应用程序。 CLI 和 Docker Desktop 均与 Docker 服务器交互。 来自 CLI 或 Docker Desktop 的 docker 命令使用 Docker REST API 将指…

Java与Gradle 的版本兼容性矩阵验证

1.下面这个表格显示了java和gradle的版本兼容性情况 2.根据上面这份表格理解&#xff0c;是不是java17就需要gradle 7.3之后来支持。用android studio 来试验一下: jdk选择: build成功: 说明JDK17并不是一定需要Gradle 7.3之后版本 3.使用JDK1.8、JDK11验证一下Grade 7.2是否可…

如何解决SEO排名上升后遭遇的攻击问题

随着搜索引擎优化&#xff08;SEO&#xff09;策略的成功实施&#xff0c;网站排名的提升往往会引来更多的流量与关注&#xff0c;但同时也可能成为恶意攻击的目标&#xff0c;包括DDoS攻击、SQL注入、XSS攻击等。这些攻击不仅影响用户体验&#xff0c;还可能导致网站降权甚至被…

报名倒计时!「飞天技术沙龙-CentOS 迁移替换专场」参会指南

为帮助广大用户诊断 CentOS 迁移替换过程中的疑难杂症&#xff0c;「飞天技术沙龙-CentOS 迁移替换专场」将于 5 月 29 日&#xff08;周三&#xff09;在北京举办&#xff0c;将围绕如何在确保服务的连续性和稳定性的前提下实现平滑迁移及如何最大限度地利用现有资源前提下确保…

沃飞携AE200真机亮相澳门,全方位赋能城市低空出行

5月22日-25日&#xff0c;第四届BEYOND国际科技创新博览会&#xff08;BEYOND Expo 2024&#xff09;在澳门盛大举行。吉利沃飞长空携旗下全自研产品AE200真机亮相&#xff0c;吸引了现场众多领导嘉宾以及媒体、观众的关注。 作为亚洲顶尖的年度科技盛会&#xff0c;本届BEYOND…

【C++】:vector容器的基本使用

目录 &#x1f352;1&#xff0c;vector的介绍&#x1f352;2&#xff0c;vector的使用&#x1f42f;2.1 vector的构造&#x1f981;2.2 vector iterator 的使用&#x1f33d;2.3 vector 空间增长问题&#x1f353;2.4 vector 增删查改&#x1f42f;2.5 vector 访问及遍历&…

2022全国大学生数学建模竞赛ABC题(论文+代码)

文章目录 &#xff08;1&#xff09;2022A波浪能最大输出功率&#xff08;2&#xff09;2022B无人机定位&#xff08;3&#xff09;2022C古代玻璃制品成分分析&#xff08;4&#xff09;论文和代码链接 &#xff08;1&#xff09;2022A波浪能最大输出功率 &#xff08;2&#x…

用(华为)三层交换技术解决不同vlan间通信问题

用三层交换技术解决不同vlan间通信问题 一、网络拓扑&#xff1a; 二、配置思路&#xff1a;自下而上配置 1.PC端配置基本IP信息包括网关 2.接入交换机S1上划分三个vlan&#xff0c;分别是VLAN 10 VLAN 20 VLAN 30 并且将对应的接口加入指定的vlan 3.给接入交换机配置trunk链路…