Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

这篇具有很好参考价值的文章主要介绍了Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

答题系统修改说明

1、3.0版本的答题系统同样延续了前两个版本一样的方式,题库信息存储在xml文档中,通过www的形式加载并解析,构建题目数据类。3.0版本增加了一个管理题目选项的数据结构,修复了1.0版本中题目选择后点击下一题或上一题已经选择的题目信息不保存的bug,这次可以通过题目管理类QuestionNumber来维护这些数据,让题目初始化的时候全部创建好并缓存到该类的数据结构中,需要的时候直接显示或隐藏即可,避免了频繁的实例化题目对象,浪费内存。
2、3.0版本保存了上一题、下一题和交卷功能,同时增加了左侧题目导航栏功能,可以选答任一题目;增加了正误标识图功能,提交后显示答题结果:选对的标识图为绿色,选错或未选的为红色。
3、题库xml文档节点信息如下:
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

答题界面搭建

  • 答题主界面
    Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)
    答题主界面由题目、选项、上一下、下一题、交卷和关闭按钮组成,题目是一个Text文本,实例化时根据题库题目数量生成,均保存在父物体contentText_X 下,生成所有题目的选项toggle,均保存在QuestionItem_X 下。制作好之后,在Resources文件夹下新建一个Question文件夹,将题目Text和选项Toggle拖拽到Question下作为预制体,动态实例化创建。
  • 左侧题目导航栏
    Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)
    用一个滚动视图(Scroll View)来管理题目导航toggle,题库有多少道题目就生成多少个toggle组件,命名为QuestionTog,生成的QuestionTog均保存在ButtonConten_X父物体下,buttonconten_需添加自动布局组件,同样将QuestionTog拖拽到Question文件夹下作为预制体使用。
  • 下方正误标识栏
    Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)
    正误标识栏也是用一个滚动视图来管理,用一张Image图,并添加一个text组件作为子物体表示是第几道题,将Image命名为tagImage,生成的tagImage均保存在TagContent_X 下,同理作为预制体。

以上预支体工作完成之后可以将其从Hierarchy视图里删除或隐藏掉。
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

核心脚本代码

  • Question.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Xml;
public class Question : MonoBehaviour
{
    /// <summary>
    /// 左边题目导航栏,用作题目管理
    /// </summary>
    public class QuestionNumber
    {
        /// <summary>
        /// 题目对应的问题和选项
        /// </summary>
        public class QuestionContent
        {
            private QuestionNumber number;
            private List<ToggleItem> options;
            public QuestionContent(QuestionNumber _number, List<ToggleItem> tog)
            {
                number = _number;
                options = tog;
            }
            /// <summary>
            /// 控制选项的显隐
            /// </summary>
            /// <param name="value"></param>
            public void SetVisible(bool value)
            {
                foreach (ToggleItem item in options)
                {
                    item.gameObject.SetActive(value);
                }
            }
        }
        private List<QuestionContent> cacheQuestions = new List<QuestionContent>();
        private QuestionBtnItem BtnItem;
        private GameObject text;
        public QuestionNumber(QuestionBtnItem btnItem, GameObject tex)
        {
            BtnItem = btnItem;
            text = tex;
        }
        /// <summary>
        /// 控制题目显隐
        /// </summary>
        /// <param name="value"></param>
        public void SetVisible(bool value)
        {
            text.SetActive(value);
        }
        /// <summary>
        /// 添加题目到题目缓存列表
        /// </summary>
        /// <param name="question"></param>
        public void AddQuestion(QuestionContent question)
        {
            cacheQuestions.Add(question);
        }
        public void RemoveQuestion(QuestionContent question)
        {
            cacheQuestions.Remove(question);
        }

    }
    public static Question Instance;//脚本单例,提供给外部访问
    public Button previousBtn;//上一题按钮
    public Button nextBtn;//下一题按钮
    public Button closeBtn;//关闭按钮
    public Button submitBtn;//提交按钮
    public Transform questionItem;//选项toggle父物体
    public Transform btnContent;//题目导航父物体
    public Transform tagContent;//正误标识父物体
    public Transform contentText;//题目文本父物体
    private string questionPath;//题库xml文件路径
    private int questionCount = 0;//当前题目序号
    private ToggleGroup questionGroup;
    private ToggleGroup questionItemGroup;
    //private List<ToggleItem> _AnswerData;//
    [HideInInspector]
    public List<QuestionBtnItem> _QuesitonBtnItemDatas;//左侧题目列表数据
    List<Image> tagImages = new List<Image>();//正误标识图
    private List<QuestionNumber> mQuestionlist = new List<QuestionNumber>();//左侧题目列表
    private List<QuestionNumber.QuestionContent> mContenList = new List<QuestionNumber.QuestionContent>();//题目选项列表
    QuestionDatas questionData;//题库数据
    int questionTotalScore = 0;//总分
    private void Awake()
    {
        Instance = this;
    }
    private void Start()
    {
        questionPath = "file://" + Application.dataPath + "/data/Question/Question.xml";
        Init();
    }
    /// <summary>
    /// 初始化
    /// </summary>
    private void Init()
    {
        questionGroup = questionItem.GetComponent<ToggleGroup>();
        questionItemGroup = btnContent.GetComponent<ToggleGroup>();
        //_AnswerData = new List<ToggleItem>();
        StartCoroutine(LoadQuestion(questionPath));
        closeBtn.onClick.AddListener(delegate
        {
            gameObject.SetActive(false);
        });
        previousBtn.onClick.AddListener(PreviousClick);
        submitBtn.onClick.AddListener(SubmitClick);
        nextBtn.onClick.AddListener(NextClick);
    }
    
    /// <summary>
    /// 加载题库协程
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    IEnumerator LoadQuestion(string path)
    {
        yield return null;

        using (WWW www = new WWW(path))
        {
            yield return www;
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(www.text);
            questionData = new QuestionDatas(doc.FirstChild);
        }
        InitQuestionPanel(questionData);
    }
    /// <summary>
    /// 初始化答题面板
    /// </summary>
    /// <param name="questionData"></param>
    private void InitQuestionPanel(QuestionDatas questionData)
    {
        _QuesitonBtnItemDatas = new List<QuestionBtnItem>();
        for (int i = 0; i < questionData.questionItemDatas.Count; i++)
        {
            GameObject text = GameObject.Instantiate(Resources.Load<GameObject>("Question/Text"));//实例化题目
            text.GetComponent<Text>().text = questionData.questionItemDatas[i].Problem;
            text.transform.SetParent(contentText);
            text.transform.localScale = Vector3.one;
            QuestionBtnItem btnItem = GameObject.Instantiate(Resources.Load<QuestionBtnItem>("Question/QuestionTog"));//实例化左侧题目导航
            Image tagImg = GameObject.Instantiate(Resources.Load<Image>("Question/tagImage"));//实例化下方正误标识图
            tagImg.gameObject.GetComponentInChildren<Text>().text = (i + 1).ToString();
            tagImg.transform.SetParent(tagContent);
            tagImg.transform.localScale = Vector3.one;
            tagImages.Add(tagImg);
            _QuesitonBtnItemDatas.Add(btnItem);

            btnItem.Init(i, (id) =>
            {
                CallBackId(id);
            });
            QuestionNumber tmpQuestion = new QuestionNumber(btnItem, text);//初始化题目对象
            tmpQuestion.SetVisible(false);
            mQuestionlist.Add(tmpQuestion);
            btnItem.thisBtn.group = questionItemGroup;
            btnItem.transform.SetParent(btnContent);
            btnItem.transform.localScale = Vector3.one;
            CreateQuestionItem(questionData.questionItemDatas[i]);
        }
        mQuestionlist[questionCount].SetVisible(true);//初始显示第一题
        mContenList[questionCount].SetVisible(true);
    }
    /// <summary>
    /// 点击左侧题目回调函数
    /// </summary>
    /// <param name="id"></param>
    private void CallBackId(int id)
    {
        if (id != questionCount)
        {
            mQuestionlist[questionCount].SetVisible(false);//上一道题目隐藏
            mContenList[questionCount].SetVisible(false);
            questionCount = id;
            mQuestionlist[questionCount].SetVisible(true);//显示当前题目内容
            mContenList[questionCount].SetVisible(true);
        }
    }
    /// <summary>
    /// 创建题目
    /// </summary>
    /// <param name="questionItemData"></param>
    private void CreateQuestionItem(QuestionItemDatas questionItemData)
    {
        List<ToggleItem> tmp = new List<ToggleItem>();
        for (int i = 0; i < questionItemData.answerDatas.Count; i++)
        {
            ToggleItem tog = GameObject.Instantiate(Resources.Load<ToggleItem>("Question/Toggle"));//实例化选项toggle
            tog.Init(questionItemData, questionItemData.answerDatas[i]);//toggle初始化
            tog.thisTog.group = questionGroup;
            tog.transform.SetParent(questionItem);
            tog.transform.localScale = Vector3.one;
            tmp.Add(tog);
        }
        QuestionNumber.QuestionContent questionContent = new QuestionNumber.QuestionContent(mQuestionlist[questionCount], tmp);//初始化选项对象
        questionContent.SetVisible(false);
        mQuestionlist[questionCount].AddQuestion(questionContent);
        mContenList.Add(questionContent);
    }
    /// <summary>
    /// 上一题点击事件
    /// </summary>
    private void PreviousClick()
    {
        if (questionCount > 0)
        {
            questionCount--;
            CheckOtherQuestion();
            _QuesitonBtnItemDatas[questionCount].ChangeQuestionState(QuestionState.Select);
            
        }
    }
    /// <summary>
    /// 下一题点击事件
    /// </summary>
    private void NextClick()
    {
        if (questionCount < questionData.questionItemDatas.Count - 1)
        {
            questionCount++;
            CheckOtherQuestion();
            _QuesitonBtnItemDatas[questionCount].ChangeQuestionState(QuestionState.Select);
        }
    }
    /// <summary>
    /// 检查其他未作答的题目
    /// </summary>
    private void CheckOtherQuestion()
    {
        for (int i = 0; i < _QuesitonBtnItemDatas.Count; i++)
        {
            if (!_QuesitonBtnItemDatas[i].isSelectAnswer)
            {
                _QuesitonBtnItemDatas[i].img.sprite = _QuesitonBtnItemDatas[i].Default;//未作答恢复默认状态
            }
        }
    }
    /// <summary>
    /// 提交事件
    /// </summary>
    private void SubmitClick()
    {
        //double questionTotalScore = 0;
        for (int i = 0; i < _QuesitonBtnItemDatas.Count; i++)
        {
            if (_QuesitonBtnItemDatas[i].QuestionScore > 0)
            {
                questionTotalScore += questionData.questionItemDatas[i].RightVar;
                tagImages[i].color = Color.green;
            }
            else
            {
                tagImages[i].color = Color.red;
            }
        }
    }
    /// <summary>
    /// 题目数据类
    /// </summary>
    public class QuestionDatas
    {
        public List<QuestionItemDatas> questionItemDatas;

        public QuestionDatas(XmlNode node)
        {
            questionItemDatas = new List<QuestionItemDatas>();
            for (int i = 0; i < node.ChildNodes.Count; i++)
            {
                questionItemDatas.Add(new QuestionItemDatas(node.ChildNodes[i]));
            }
        }
    }
    /// <summary>
    /// 一道题目数据类
    /// </summary>
    public class QuestionItemDatas
    {
        /// <summary>
        /// 正确答案分值
        /// </summary>
        public int RightVar;
        /// <summary>
        /// 问题
        /// </summary>
        public string Problem;
        public int Id;
        public QuestionItemDatas(XmlNode node)
        {
            answerDatas = new List<AnswerDatas>();
            Problem = node["Name"].InnerText;
            Id = int.Parse(node.Attributes["Id"].InnerText);
            XmlNodeList answerList = node["Answer"].ChildNodes;
            for (int i = 0; i < answerList.Count; i++)
            {
                answerDatas.Add(new AnswerDatas(answerList[i]));
            }
        }
        public List<AnswerDatas> answerDatas;
    }
    /// <summary>
    /// 一道题目对应的选项数据类
    /// </summary>
    public class AnswerDatas
    {
        /// <summary>
        /// 选项对应的分数
        /// </summary>
        public int score;
        /// <summary>
        /// 选项内容
        /// </summary>
        public string answerName;

        public AnswerDatas(XmlNode node)
        {
            answerName = node.Attributes["Name"].InnerText;
            score = int.Parse(node.InnerText);
        }
    }
}

将该脚本拖拽到UI上即可,并给其中对象拖拽赋值:
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

  • QuestionBtnItem.cs
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 题目默认、选中、完成作答三个状态
/// </summary>
public enum QuestionState
{
    Default,
    Select,
    Finished
}

public class QuestionBtnItem : MonoBehaviour 
{
    public int Id;
    public Image img;
    public Toggle thisBtn;
    public Sprite Default;//默认灰色图
    public Sprite Finished;//完成深色图
    public Sprite Select;//选中颜色图
    private System.Action<int> callBack;
    private QuestionState questionState = QuestionState.Default;//题目默认未选中状态
    public bool isSelectAnswer = false;//当前题目是否已选择答案
    //public string SelectAnswer = "";
    private float questionScore = 0;
    public float QuestionScore
    {
        get { return questionScore; }
        set { questionScore = value; }
    }

    public void Init(int i,System.Action<int > callBack=null)
    {
        thisBtn = gameObject.GetComponent<Toggle>();
        if (i == 0)
        {
            ChangeQuestionState(QuestionState.Select);//默认选中第一道题
        }
        Id = i;
        this.callBack = callBack;
        thisBtn.name = (i+1).ToString();
        thisBtn.GetComponentInChildren<Text>().text = "第 " + thisBtn.name + " 题";
        thisBtn.onValueChanged.AddListener((isSelect) =>
        {
            if (callBack!=null)
            {
                callBack(Id);//选中就调用一次回调函数
            }
        });

    }
    /// <summary>
    /// 修改题目状态
    /// </summary>
    /// <param name="state"></param>
    public void ChangeQuestionState(QuestionState state)
    {
        switch (state)
        {
            case QuestionState.Default:
                img.sprite = Default;
                break;
            case QuestionState.Select:
                thisBtn.isOn = true;
                break;
            case QuestionState.Finished:
                isSelectAnswer = true;
                img.sprite = Finished;
                break;
        }
    }
}

将该脚本拖拽给QuestionTog对象:赋值题目的三种状态图
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

  • ToggleItem.cs
using UnityEngine;
using UnityEngine.UI;


public class ToggleItem : MonoBehaviour 
{
	public Toggle thisTog;
    public Text optionText;//选项文本
    public float Score;//选项对应分值
    public void Init(Question.QuestionItemDatas questionItemData, Question.AnswerDatas answerData)
    {
        Score = answerData.score;
        optionText.text = answerData.answerName;
        thisTog.onValueChanged.AddListener((isSelect) =>
        {
            Question.Instance._QuesitonBtnItemDatas[questionItemData.Id].ChangeQuestionState(QuestionState.Finished);
            Question.Instance._QuesitonBtnItemDatas[questionItemData.Id].QuestionScore = Score;//将选择的选项分值赋值给当前题目
        });
    }
}

将改脚本拖拽给选项Toggle:
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

运行效果

Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)

Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)
Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)
创作不易,喜欢就一键三连呀,点点关注哦!文章来源地址https://www.toymoban.com/news/detail-437591.html

到了这里,关于Unity答题系统3.0版本(增加题目导航栏和提交后显示题目正误标识功能)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android隐藏导航栏和状态栏的方法

    一。去除状态栏 以下是Android去除状态栏的代码示例: 1. 在Activity的onCreate()方法中添加以下代码: getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 2. 在AndroidManifest.xml文件中的Activity节点中添加以下属性: android:theme=\\\"@android:style/Theme.NoTitleB

    2024年02月16日
    浏览(38)
  • 删除左导航栏和我的电脑旁边wps云盘图标

    win+R打开命令行输入regedit打开注册表,找到如下位置删除文件。 1.资源管理-左导航栏:(中间数字可能有区别,看好开头结尾即可) HKEY_USERSS-1-5-21-1514480548-2261916930-1024021491001SoftwareMicrosoftWindowsCurrentVersionExplorerDesktopNameSpace{7AE6DE87-C956-4B40-9C89-3D166C9841D3} 2.资源管理=我的电

    2024年02月13日
    浏览(40)
  • Android开发:利用Android Studio自带的底部导航栏和ViewPager+TabLayout创建顶部导航栏

    目录 效果图 底部导航栏 ​编辑 顶部导航栏 底部导航栏首个Fragment代码 适配器代码 顶部导航栏首个Fragment代码  顶部导航栏另外三个Fragment代码  ​编辑 顶部导航栏四个Fragment的XML 补充 学Android开发开始实操,第一步肯定要把大致布局搞定。做这个布局用到的知识难点有fr

    2024年02月03日
    浏览(59)
  • 【vue3】固定上导航栏和左侧导航栏,只显示其他内容在主内容区域

    在一个单独的vue组件文件中只写出上导航栏和左侧导航栏的内容 将你想要展示的页面主内容写到单独的组件中 在index.js写路由,将【想要展示的页面主内容的路由】作为【子路由】写在【只写出上导航栏和左侧导航栏的路由】的下面; 在elment-plus官网上找到自己需要的布局容

    2024年02月12日
    浏览(43)
  • uniapp全屏弹窗,覆盖原生控件导航栏和tabbar,全局调用

    在uniapp中popup弹窗及对话框的遮罩层是覆盖不了原生的导航栏和tab栏的,在tabbar页中使用弹出框会非常的违和,接下来告诉大家实现的思路。 创建一个页面放置components或者pages中,接着在pages.json中注册当前页面,并设置背景色透明及取消导航栏。 配置创建页面的背景色透明

    2024年02月10日
    浏览(44)
  • uniapp使用自定义导航栏和手机自带的状态栏重叠

    【问题界面】: 【正常界面】: 【解决方法】: 在页面顶部添加代码 !-- #ifndef H5 -- statusBar/statusBar !-- #endif -- 2.引入占位条并注册

    2024年02月15日
    浏览(35)
  • 在uniapp中获取微信小程序状态栏和导航栏的高度

    在微信小程序中,可以使用  uni.getSystemInfo()  方法获取设备的系统信息,包括状态栏的高度和顶部导航栏的高度。您可以使用这些信息计算顶部图标距离。 下面是一个示例代码,展示如何在 UniApp 中获取顶部图标距离: 在上述示例代码中,我们通过调用  uni.getSystemInfo()  方

    2024年02月07日
    浏览(44)
  • Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换

    通过几次的踩雷和摸索,完成了以上的操作,本教程写的详细全面,包教包会,对新手有好,看了不会的联系我,我倒立洗头给你看。 所需控件: fragment 作为Android中最常用的控件,它有自己的声明周期,可以粗略地等比为能够分屏的activity,但是和activity有区别,fragment有自

    2024年02月08日
    浏览(47)
  • Android全屏弹出Dialog显示状态栏和导航栏的问题及解决方案

    在移动端开发中,有时候我们需要在Android应用中弹出一个全屏的Dialog。然而,当我们尝试实现这样的Dialog时,可能会遇到一个问题:状态栏和导航栏在全屏Dialog中仍然可见,这可能会影响用户体验。本文将介绍如何解决这个问题,并提供相应的源代码。 问题描述: 当我们使

    2024年02月05日
    浏览(41)
  • vue-router + element-plus实现面包屑导航栏和路由标签栏

    首先,先解释一下什么是面包屑导航栏和路由标签栏。 如下图所示,面包屑导航栏就是展示当前所处路由信息和父辈路由信息的导航栏,它的作用是提示用户当前页面所在位置;路由标签栏就类似于浏览器的标签栏,每个标签对应一个路由页面,点击该标签可以进入该路由页

    2023年04月23日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包