在Unity中使用Excel表开发单选题和多选题

前言:

去年还是小菜鸡的我写过在Unity中单选题和多选题的开发。现在进步一点点,这次可以直接编辑表格,在表格中增删改查数据即可,无需再对代码进行更改!
下载链接在文章末尾,需要的可以直接划到最后!

废话不多说,开始~

首先需要配置三个文件

  1. 读取表格的程序集:EPPlus
  2. 处理Json数据的程序集:Newtonsoft.Json
  3. 表格文件:question.xlsx

大概流程如下

创建StreamingAssets文件

  1. 首先我们在工程文件Assets文件下创建一个StreamingAssets(这里我们默认使用此路径为加载路径)在这里插入图片描述

  2. 我们在此文件夹下创建一个表格。这里我使用的是.xlsx在这里插入图片描述
    下面是表结构,大家如果要修改的话,记得同时修改Question.cs哦!
    在这里插入图片描述

创建Plugins文件

  1. 在Assets文件下创建一个名为Plugins文件夹
    在这里插入图片描述

  2. 将刚才上面说了两个程序集EPPlus和Newtonsoft.Json放入此文件下在这里插入图片描述

做完上面那些就可以导入我给大伙准备的脚本了

这里一共有三个脚本:

  • ExcelMgr.cs
  • Question.cs
  • UIQuesPanel.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OfficeOpenXml;
using System.IO;
using System.Data;
using System;
using Newtonsoft.Json.Linq;
using DialogEntity;

namespace vvb_ExcelMgr
{
    public class ExcelMgr : MonoBehaviour
    {
        static ExcelPackage package;//表文件缓存
        public static ExcelWorkbook dialogWorkbook;//表工作簿
        public List<Question> questionList = new List<Question>();//题目缓存列表
        public string quesPackPath="question";//题目文件地址,文件后缀默认为".xlsx"
        private void Awake()
        {
            ReadExcel(quesPackPath, () =>
            {
                UIQuesPanel.quesList = GetQuesList(package);
                questionList = UIQuesPanel.quesList;//这里为了在inspecter中能看到读取到达数据
            });
        }
        /// <summary>
        /// 打开表缓存
        /// </summary>
        public static ExcelWorkbook ReadExcel(string excelPath, Action action)
        {
            //Debug.Log(Application.streamingAssetsPath);
            excelPath = Application.streamingAssetsPath + "/"+excelPath+".xlsx";
            try
            {
                using (package = new ExcelPackage(new FileStream(excelPath, FileMode.Open)))
                {
                    action?.Invoke();
                    return package.Workbook;
                }
            }
            catch (NullReferenceException e)
            {
                Debug.LogError("空指针异常:" + e);
                return null;
            }
            catch (IOException e)
            {
                Debug.LogError("文件打开异常:" + e);
                return null;
            }
            catch (Exception e)
            {
                Debug.LogError("其他异常:" + e);
                return null;
            }
        }
        public List<Question> GetQuesList(ExcelPackage excelPackage)
        {
            List<Question> quesList = new List<Question>();
            int dataStartRow = 0;
            if (excelPackage.Workbook.Worksheets.Count < 0)
            {
                Debug.LogError("空表");
                return null;
            }
            ExcelWorksheet sheet = excelPackage.Workbook.Worksheets[1];
            for (int startRow = sheet.Dimension.Start.Row, endRow = sheet.Dimension.End.Row; startRow <= endRow; startRow++)
            {
                if (sheet.GetValue(startRow, 1).ToString().Equals("quesId"))//此行开始才是咱们真正需要的数据,当然在开发过程中这里是不需要的
                {
                    dataStartRow = startRow;
                    break;
                }
                //Debug.Log(sheet.GetValue(startRow, 1).ToString());
                //Debug.Log(sheet.GetValue(2, 1).ToString());
            }
            for (int startRow = dataStartRow+1, endRow = sheet.Dimension.End.Row; startRow <= endRow; startRow++)
            {
                JObject question = new JObject();//每一行实例化一个对象,用来存储到题目列表中
                for (int startColumn = sheet.Dimension.Start.Column, endColumn = sheet.Dimension.End.Column; startColumn <= endColumn; startColumn++)
                {
                    //这里要注意做一步特殊处理,因为当读取到选项内容那一行时,类型为数组,所以我们需要特殊处理一下
                    if (startColumn == 3)//在表中我们将选项内容放在C列,也就是第三项。或者各位也可以使用其他的方式判定
                    {
                        JArray options = new JArray();
                        string[] opsStr = sheet.GetValue(startRow, startColumn).ToString().Split(';');//这里先获取此处的字符串,然后再使用我们自定的符号切割以获得选项数组
                        options.Add(opsStr);
                        question.Add(sheet.GetValue(dataStartRow, startColumn).ToString(), options);
                    }
                    else
                    {
                        question.Add(sheet.GetValue(dataStartRow, startColumn).ToString(), sheet.GetValue(startRow, startColumn).ToString());
                    }
                }
                quesList.Add(JsonUtility.FromJson<Question>(question.ToString()));//转成Question对象添加入列表中
                Debug.Log(question);
            }
            return quesList;
        }
    }
}
using System;
[Serializable]
public class Question
{
    public int quesId;//当前题号
    public string tittleStr;//题目内容
    public string[] optionsStr;//选项内容
    public int quesType;//题目类型
    public string ans;//正确答案
    public string analysis;//解析
    public int nextQuesId;//下一题号
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIQuesPanel : MonoBehaviour
{
    //为了方便,所有变量均拖拽赋值。
    public static List<Question> quesList = new List<Question>();
    public Text tittleTxt;//题目内容
    public RectTransform optionsRoot;//选项生成根节点
    public List<Toggle> optionTogList;//选项
    public ToggleGroup toggleGroup;//根节点togglegroup组件
    public GameObject togPrefab;//选项预制体
    public Text analysisTxt;//解析文本
    public Button lastBtn;//上一题按钮
    public Button nextBtn;//下一题按钮
    public Button confirmBtn;//确认作答按钮
    public int curQuesIndex = -1;//当前题索引
    private void Start()
    {
        _UIQuesPanelInit();
    }
    /// <summary>
    /// 上一题
    /// </summary>
    public void OnLastBtnClick()
    {
        curQuesIndex--;
        if (curQuesIndex <0)
        {
            Debug.LogWarning("前面没有了!");
            curQuesIndex = 0;
            return;
        }
        _UpdateQues();
    }
    /// <summary>
    /// 下一题
    /// </summary>
    public void OnNextBtnClick()//这里加载下一题的方式也可以通过表中的字段nextQuesId,上一题同理(表中暂未设计)。
    {
        curQuesIndex++;
        if (curQuesIndex>quesList.Count-1)
        {
            Debug.LogWarning("后面没有了!");
            curQuesIndex = quesList.Count-1;
            return;
        }
        _UpdateQues();
    }
    /// <summary>
    /// 刷新题目
    /// </summary>
    private void _UpdateQues()
    {
        analysisTxt.gameObject.SetActive(false);
        tittleTxt.text = (curQuesIndex + 1).ToString() + "." + quesList[curQuesIndex].tittleStr;
        int optionsCount = optionsRoot.childCount;
        optionTogList.Clear();
        while (optionsCount > 0)
        {
            optionsCount--;
            Destroy(optionsRoot.GetChild(optionsCount).gameObject);
        }
        for (int i = 0; i < quesList[curQuesIndex].optionsStr.Length; i++)//根据选项个数创建相应的toggle数量
        {
            optionTogList.Add(Instantiate(togPrefab, optionsRoot).GetComponent<Toggle>());
            optionTogList[i].isOn = false;
            if (quesList[curQuesIndex].quesType == 0)
            {
                optionTogList[i].group = toggleGroup;
            }
            optionTogList[i].GetComponentInChildren<Text>().text = quesList[curQuesIndex].optionsStr[i];
        }
    }
    /// <summary>
    /// 确认作答
    /// </summary>
    public void OnConfirmBtnClick()
    {
        if (curQuesIndex<0||curQuesIndex>quesList.Count-1)
        {
            Debug.LogError("数组越界");
            return;
        }
        string selected=null;//用户选择
        analysisTxt.text = selected;
        analysisTxt.gameObject.SetActive(true);
        switch (quesList[curQuesIndex].quesType)
        {
            case 0://单选
                for (int i = 0; i < optionTogList.Count; i++)
                {
                    if (optionTogList[i].isOn)
                    {
                        selected = optionTogList[i].GetComponentInChildren<Text>().text[0].ToString();//默认第一个字符代表此选项,并与答案进行对比。这里正误判定也可以自己定义
                        Debug.Log("选择的答案为:" + selected);
                        break;
                    }
                }
                break;
            case 1://多选
                for (int i = 0; i < optionTogList.Count; i++)
                {
                    if (optionTogList[i].isOn)
                    {
                        selected += optionTogList[i].GetComponentInChildren<Text>().text[0].ToString();
                    }
                }
                break;
            default:
                break;
        }
        if (string.IsNullOrEmpty(selected))//没作答情况。具体可以自定义,比如你弹出一个面板提示什么的,强制答完才行。
        {
            selected = "未作答";
            Debug.LogError("请先选择选项!");
        }
        if (selected.Equals(quesList[curQuesIndex].ans))//与正确答案做比较
        {
            Debug.Log("正确");
            analysisTxt.text = "<color=green>回答正确</color>   ";
        }
        else
        {
            Debug.Log("错误");
            analysisTxt.text = "<color=red>回答错误</color>   ";
        }
        analysisTxt.text += "你的答案:" + selected + "   正确答案:" + quesList[curQuesIndex].ans+"\n解析:" + quesList[curQuesIndex].analysis;
    }
    /// <summary>
    /// 面板初始化
    /// </summary>
    private void _UIQuesPanelInit()
    {
    	//这里大伙儿可以自己默认调用一次“下一题”按钮的事件来默认更新第一道题。我就不写了
    	
        analysisTxt.gameObject.SetActive(false);
        if (optionsRoot.gameObject.GetComponent<ToggleGroup>())
        {
            toggleGroup = optionsRoot.gameObject.GetComponent<ToggleGroup>();
        }
        else
        {
            toggleGroup = optionsRoot.gameObject.AddComponent<ToggleGroup>();
        }
        toggleGroup.allowSwitchOff = true;
    }
}

具体的过程我就不详述了,大伙儿看代码自行体会!

有何疑问欢迎留言讨论!需要源码的可以评论区留言或者私聊。

下面是源工程的下载地址:
链接:https://pan.baidu.com/s/1hrmtq9PGJlDg4Ya_YO6FeQ
提取码:grnh

================================ 2023/04/18新增 ===============================
我已经将资源上传至CSDN了,各位需要的可以自行下载,放心进,我设置了0积分,纯免费下载。
创作不易,我就一个要求,如果对你有帮助的话,请给我点个赞,谢谢。下载地址

  • 36
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 69
    评论
### 回答1: Unity2D 是一款非常流行的游戏引擎,可以用于开发各种类型的游戏,包括答题游戏。许多开发者需要一个答题系统源码来参考和学习,这里就向大家介绍一下 Unity2D 答题系统源码。 Unity2D 答题系统源码主要包括两个部分:界面设计和功能实现。界面设计包括题目展示、选项显示、计时器、得分等,这些都需要通过 Unity2D 引擎实现。功能实现涉及到游戏逻辑、数据管理、UI 交互等方面,需要开发者根据自己的需求进行设计和编写。 在使用 Unity2D 答题系统源码时,需要注意以下几点: 1. 熟悉 Unity2D 引擎,掌握常用的 2D 游戏开发技术。 2. 根据游戏规则和要求进行功能设计和实现,包括题目难度、题型、分数计算等。 3. 使用 C# 编程语言进行代码编写,包括游戏逻辑、UI 交互、数据管理等。 4. 界面设计需要考虑用户体验,如何让用户更方便、更快速地进行答题操作。 5. 确保代码的可扩展性和可维护性,方便后续的修改和维护工作。 总体来说,Unity2D 答题系统源码可以让开发者更快速地实现答题游戏功能,并且可以根据自己的需要进行修改和扩展。但是需要开发者具备一定的编程和设计技能,才能更好地使用 Unity2D 引擎进行游戏开发。 ### 回答2: Unity2D答题系统源码是一个基于Unity2D引擎开发的答题游戏源码。该源码可以帮助初学者了解和掌握Unity2D的开发技巧,同时也可以作为答题游戏的基础代码,方便开发者快速进行二次开发。 该源码包含了题目的制作、难度等级的设置、计分系统、倒计时等核心功能。玩家可以通过点击正确的答案来获得积分,同时还可以利用道具来增加自己的分数和答题时间。 在该源码的开发过程,我们需要掌握Unity2D引擎的基本知识和编程技巧,比如物体的移动、碰撞检测、动画控制等。同时还需要了解答题游戏的设计原理和玩家习惯,才能开发出适合玩家的游戏。 总之,Unity2D答题系统源码是一个重要的学习资料,它可以帮助我们深入理解Unity2D引擎的开发技巧,同时也可以作为开发答题游戏的基础代码,提高游戏的开发效率和质量。 ### 回答3: Unity2D答题系统源码是一种基于Unity2D游戏引擎的答题系统源代码。它主要提供一组可定制的答题功能,包括题目类型、难度等。这个系统可以用于各种类型的测试,比如知识测试、考试、调查、竞赛等。 这个答题系统源码提供了一个完整的框架,可以方便地修改和扩展。它包含了一个用户管理系统、答题系统和结果分析系统。每个用户可以注册并登录,然后选择他们想参加的测试。用户可以选择一个或多个题目类型和难度,然后开始答题。测试结束后,用户可以看到自己的得分,并可以查看自己的答案和正确答案。管理员可以在后台管理用户和测试,查看测试结果和分析报告。 这个系统的优点是,它构建在Unity2D游戏引擎的基础之上,可扩展性强,可以适应不同的需求。它还具有用户友好的界面,可以吸引用户并提供良好的参与体验。此外,这个系统源码是免费提供的,任何人都可以使用和修改它,让它更好地满足自己的需求。
评论 69
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值