Unity答题系统2.0版本(修改答题面板形式(滚动视图显示),增加提交后得分结果显示)

搭建答题面板

1.添加一个画布(Canvas),在画布下新建一个空物体(Panel_Question),在空物体下添加一张图片(Image),作为答题背景图。然后在背景图下添加一个滚动视图(Scroll View),调整好宽高。在滚动视图的Content物体下新建空物体(Question),作为一道题目的父物体,content物体上添加两个组件【Content Size Fitter】和【Vertical Layout Group】,并设置相关属性和适当的参数,使其子物体可以自适应垂直布局。设置可参考下图:
在这里插入图片描述

  1. 题目(Question)物体下,添加Text文本(topic)作为问题文本;新建空物体(Item)作为选项的父物体,item下添加一个Toggle组件作为选项(命名为option),默认不勾选,添加组件【Layout Element】可以自动布局下设置其宽高;item物体上添加组件【Vertical Layout Group】和【Toggle Group】,分别用来控制选项的垂直布局和选项Toggle组的选中转台,其属性Allow Switch Off默认不勾选,表示在改组下,仅有一个toggle可以被选中,如果勾选,改组下所有toggle都可以不被选中。item面板如下:
    在这里插入图片描述
    再添加一张image(命名为line),作为题目与题目之间的分割线。其面板如下:
    在这里插入图片描述
    最后为题目Question物体添加组件【Vertical Layout Group】,设置如下:
    在这里插入图片描述
    还要将题目Question物体和选项option物体,拖到Resources文件加下作为预制体,用来实例化生成。
    最终答题面板效果如下:
    在这里插入图片描述

  2. 添加确认框和得分面板
    这两个很容易搭建,就是image、text、button拼接组合,不再详细描述,效果如下:
    在这里插入图片描述
    在这里插入图片描述
    4.新建Data文件夹保存题目的xml文档
    xml文档内容如下:
    在这里插入图片描述
    可根据需求修改。

脚本实现答题功能

1.NewQuestion.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
using UnityEngine.UI;
/// <summary>
/// 答题界面
/// </summary>
public class NewQuestion : MonoBehaviour 
{
    
    
    /// <summary>
    /// 题库xml路径
    /// </summary>
    private string problemXmlPath = "/Data/Problem.xml";
    /// <summary>
    /// 题目的父物体
    /// </summary>
    private Transform questionParent;
    /// <summary>
    /// 确认框
    /// </summary>
    private Transform hintBG;
    /// <summary>
    /// 确认提交面板
    /// </summary>
    private GameObject  affirmPanel;
    /// <summary>
    /// 得分结果面板
    /// </summary>
    private GameObject  resultPanel;
    /// <summary>
    /// 得分内容
    /// </summary>
    private Text resultText;
    /// <summary>
    /// 用来缓存每一道题目的答题情况数据
    /// </summary>
    private List<QuestionItem> questionItems;
    private void Start()
    {
    
    
        resultPanel = transform.Find("hintBG/resultPanel").gameObject;
        affirmPanel = transform.Find("hintBG/affirmPanel").gameObject;
        resultText = resultPanel.GetComponentInChildren<Text>();
        SetActive(false, resultPanel, affirmPanel);
        resultPanel.gameObject.SetActive(false);
        questionParent = transform.Find("answerBG/Scroll View/Viewport/Content");
        hintBG = transform.Find("hintBG");
        hintBG.localScale = Vector3.zero;
        transform.Find("answerBG/SubmitBtn").GetComponent<Button>().onClick.AddListener(() =>
        {
    
    
            hintBG.localScale = Vector3.one;
            SetActive(true, affirmPanel);
        });
        transform.Find("hintBG/affirmPanel/cancelBtn").GetComponent<Button>().onClick.AddListener(() =>{
    
    
            hintBG.localScale = Vector3.zero;
        });
        transform.Find("hintBG/affirmPanel/submitBtn").GetComponent<Button>().onClick.AddListener(SubmitClick);
        Init();
        questionItems = new List<QuestionItem>();
    }
    /// <summary>
    /// 设置物体显隐
    /// </summary>
    /// <param name="value"></param>
    /// <param name="obj"></param>
    private void SetActive(bool value,  params GameObject[] obj )
    {
    
    
        foreach (var item in obj)
        {
    
    
            item.SetActive(value);
        }
    }
    /// <summary>
    /// 提交事件
    /// </summary>
    private void SubmitClick()
    {
    
    
        int score = 0;
        int rightCount = 0;
        int wrongCount = 0;
        int notAnswerCount = 0;
        score = problem.problemData[0].score;
        for (int i = 0; i < problem.problemData.Count; i++)
        {
    
    
            //是否已选择
            if (questionItems[i].IsSelect)
            {
    
    
                //是否选择正确
                if (questionItems[i].isRight)
                {
    
    
                    rightCount++;
                }
                else
                {
    
    
                    wrongCount++;
                }
            }
            else
            {
    
    
                notAnswerCount++;
            }
        }
        resultText.text = string.Format("一共有{0}道题,每题{1}分,你答对了{2}道题,答错了{3}道题,{4}道题未作答,总得分{5}分。", problem.problemData.Count, score.ToString(), rightCount.ToString(), wrongCount.ToString(), notAnswerCount.ToString(), (rightCount*score).ToString());
        SetActive(false, affirmPanel);
        SetActive(true, resultPanel);
    }
    /// <summary>
    /// 初始化协程解析xml数据
    /// </summary>
    public void Init()
    {
    
    
        StartCoroutine(LoadingQuestion(problemXmlPath));
    }
    /// <summary>
    /// 题库
    /// </summary>
    private Problem problem;
    /// <summary>
    /// 解析题目xml文件
    /// </summary>
    /// <param name="path">xml路径</param>
    /// <returns></returns>
    IEnumerator LoadingQuestion(string path)
    {
    
    
        string filePath= "file://"+Application.dataPath + path;
        yield  return null;
        using (WWW www=new WWW(filePath))
        {
    
    
            yield return www;
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(www.text);
            problem=new Problem(doc.FirstChild);
        }
        //遍历题库生成所有题目
        for (int i = 0; i < problem.problemData.Count; i++)
        {
    
    
            CreateQuestionItem(problem.problemData[i]);
        }
    }
    /// <summary>
    /// 创建一道题目
    /// </summary>
    /// <param name="problemData">一道题的数据</param>
    private void CreateQuestionItem(ProblemData problemData)
    {
    
    
        //生成问题
        QuestionItem questionItem = GameObject.Instantiate(Resources.Load<QuestionItem>("Prefab/Question"));
        questionItem.transform.SetParent(questionParent);
        questionItem.transform.localScale = Vector3.one;
        questionItem.topicText.text = problemData.topicStr;
        //生成问题对应的选项
        for (int i = 0; i < problemData.optionData.Count; i++)
        {
    
    
            Toggle toggle = GameObject.Instantiate(Resources.Load<Toggle>("Prefab/option") as Toggle);
            toggle.transform.SetParent(questionItem.item);
            toggle.transform.localScale = Vector3.one;
            toggle.group = questionItem.itemGroup;
            questionItem.ItemInit(toggle, problemData.optionData[i]);
        }
        questionItems.Add(questionItem);
    }
}
/// <summary>
/// 题库内容类
/// </summary>
public class Problem
{
    
    
    public List<ProblemData> problemData;
    /// <summary>
    /// 遍历根节点下的子节点
    /// </summary>
    /// <param name="node">传入的是根节点Root</param>
    public Problem(XmlNode node)
    {
    
    
        problemData = new List<ProblemData>();
        for (int i = 0; i < node.ChildNodes.Count; i++)
        {
    
    
            problemData.Add(new ProblemData(node.ChildNodes[i]));
        }
    }
}
/// <summary>
/// 每一道题目
/// </summary>
public class ProblemData
{
    
    
    /// <summary>
    /// 题目分数
    /// </summary>
    public int score;
    /// <summary>
    /// 题目内容
    /// </summary>
    public string topicStr;
    /// <summary>
    /// 每道题对应的选项
    /// </summary>
    public List<OptionData> optionData;
    /// <summary>
    /// 解析question节点数据
    /// 有多少个question节点就有多少道题目
    /// </summary>
    /// <param name="node">传入的是Question节点</param>
    public ProblemData(XmlNode node)
    {
    
    
        score =int.Parse(node.Attributes["score"].InnerText);
        topicStr = node["Topic"].InnerText;
        optionData = new List<OptionData>();
        XmlNodeList nodelist = node["Answer"].ChildNodes;
        for (int i = 0; i < nodelist.Count; i++)
        {
    
    
            optionData.Add(new OptionData(nodelist[i]));
        }
    }
}
/// <summary>
/// 题目对应的选项
/// </summary>
public class OptionData
{
    
    
    /// <summary>
    /// 选项内容
    /// </summary>
    public string optionStr;
    /// <summary>
    /// 选项对应的分值
    /// </summary>
    public int score;
    /// <summary>
    /// 解析选项节点
    /// </summary>
    /// <param name="node">传入的是Item节点</param>
    public OptionData(XmlNode node)
    {
    
    
        optionStr = node.Attributes["Name"].InnerText;
        score = int.Parse(node.InnerText);
    }
}

挂载到Panel_Question物体上:
在这里插入图片描述
2.QuestionItem.cs
这个脚本表示每一道题的实例对象,用来缓存题目的数据

using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 每一道题
/// </summary>
public class QuestionItem : MonoBehaviour 
{
    
    
    /// <summary>
    /// 题目内容
    /// </summary>
    public Text topicText;
    /// <summary>
    /// 选项的父物体
    /// </summary>
    public Transform item;
    /// <summary>
    /// 一道题的Toggle组
    /// </summary>
    public ToggleGroup itemGroup;
    /// <summary>
    /// 当前题目是否选择正确
    /// </summary>
    public bool isRight;
    /// <summary>
    /// 当前题目是否选择答案
    /// </summary>
    public bool IsSelect = false;
    private Color selectColor;
    /// <summary>
    /// 初始化选项Toggel的内容
    /// </summary>
    /// <param name="toggle"></param>
    /// <param name="optionData"></param>
	public void ItemInit(Toggle toggle,OptionData optionData)
    {
    
    
        toggle.GetComponentInChildren<Text>().text = optionData.optionStr;
        //为每一个选择添加选中事件
        toggle.onValueChanged.AddListener((isSelect)=> {
    
    
            IsSelect = isSelect;
            //修改选中的选项的颜色
            ColorUtility.TryParseHtmlString("#F1BC52FF", out selectColor);
            toggle.GetComponentInChildren<Text>().color = selectColor;
            //当前题目选中的选项变颜色,其他选项恢复默认颜色
            for (int i = 0; i < item.childCount; i++)
            {
    
    
                if (!item.GetChild(i).GetComponent<Toggle>().isOn)
                {
    
    
                    item.GetChild(i).GetComponentInChildren<Text>().color = Color.black;
                }
                else
                {
    
    
                    //选项对应分值大于0表示该选项是正确答案,否则是错误答案
                    if (optionData.score>0)
                    {
    
    
                        isRight = true;
                    }
                    else
                    {
    
    
                        isRight = false;
                    }
                }
            }
        });
    }
}

挂载到Question物体上:
在这里插入图片描述

实现效果

直接运行即可
初始效果:
在这里插入图片描述
答题效果:
在这里插入图片描述
得分显示效果:
在这里插入图片描述
如果不了解如何解析xml节点信息的请参考答题系统1.0版本
文末有对解析xml节点的介绍。
2.0版本没有写多选题的相关逻辑,如要需要也可参考1.0版本,添加多选题逻辑和xml配置信息。

Guess you like

Origin blog.csdn.net/qq_42437783/article/details/122450184