九宫格随机答题小游戏

一:界面展示

 

 

(录gif太长了,上传不了)

二:功能简述

  1. 点击主界面进入盲盒界面
  2. 点击任意一个盲盒进入答题界面,回答完一个题不需要返回,回答完一个3秒后进入下一题,一旦答对6题或答错4题,直接显示成功或失败界面(这个答对答错是可以通过代码修改的)
  3. 等待5秒后,返回主界面
  4. 点击任意盲盒的题目是不一样的,进入盲盒后,题目顺序也是不一样的,总结来说:就是盲盒中的题目不是固定的一个。
  5. 可以有单选题,多选题,判断题,题目数量可以内部修改,要是想做外部修改的话,加一个configDFile文件即可

三:代码梳理

主要代码:(这个是在原先的答题系统延申出来的)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.UI;

public class Panel_Question : MonoBehaviour
{
    [Header("root界面:首界面 开始答题 过度界面 答题界面 结束界面 ")]
    [SerializeField] GameObject firstRoot;
    [SerializeField] GameObject startRoot;
    [SerializeField] GameObject answerRoot;
    [SerializeField] GameObject endRoot;

    [Header("按钮:前往答题界面按钮 开始答题 上一题,提交,下一题")]
    [SerializeField] Button toStartRootBtn;
    [SerializeField] Button submitBtn;
    [SerializeField] Button[] startBtns;

    [Header("正确图片,错误图片 题型图片 题型英文图片")]
    [SerializeField] Image correntImg;
    [SerializeField] Image defeatImg;
    [SerializeField] Image  QTImg;
    [SerializeField] Image  QTEngImg;

    [SerializeField] List<Sprite> QTSprites;

    [Header("文本:题目序号 解析内容 ")]
    [SerializeField] Text questionID;
    [SerializeField] Text analysisData;

    [Header("内容scroll的content 单选scroll的content 选项scroll的content")]
    [SerializeField] Transform contentScrollContent;
    [SerializeField] Transform questionBtnRoot;
    [SerializeField] Transform selectContent;

    [SerializeField] ToggleGroup questionGroup;

    [Header("正确音效 错误音效 成功音效 失败音效")]
    [SerializeField] List<AudioClip> musics;
    // 答题界面数据内容
    private QuestionPanelData mQuestionPanelData;
    // 每一道题的题目内容
    private QuestionData mQuestionData;
    // 题目内容物体
    private GameObject mQuestion;
    // 选项的链表
    private List<Options> options = new List<Options>();

    private List<int> randomNum = new List<int>();  //存放随机数

    int index = 0;

    #region 单例和初始化
    static Panel_Question instance;

    public static Panel_Question GetInstance()
    {
        return instance;
    }

    private void Awake()
    {
        Init();
        instance = this;
    }
    #endregion


    #region 按钮监听和获取随机数
    private void Init()
    {
        //按钮监听
        toStartRootBtn.onClick.AddListener(ToStartRootEvent);
        submitBtn.onClick.AddListener(submitClick);
        for (int i = 0; i < startBtns.Length; i++)
        {
            startBtns[i].onClick.AddListener(StartAnswer);
        }

        //获取随机数
        GetRandomNum();
    }
    #endregion

    private void Start()
    {
        //读取xml文件,随机出一套题库
        StartCoroutine(LoadingQuesiton(DataPath.QuestionData));

        //初始界面的显示与隐藏
        firstRoot.SetActive(true);
        startRoot.SetActive(false);
        answerRoot.SetActive(false);
        endRoot.SetActive(false);

        //设置多选字段为空
        StringToNull();

        //默认提交按钮不能使用,没有提交
        submitBtn.interactable = false;
    }
    string[] optionContent;
    string temp;
    string optionA = "";
    string optionB = "";
    string optionC = "";
    string optionD = "";
    bool isSub;     //是否点击了提交按钮
    private void Update()
    {
        //提交按钮是否能使用
        foreach (var item in options)
        {
            //题型图片的设置
            if (mQuestionData.answerData.Count == 4)
            {
                if (mQuestionData.IsSingleChoice)//单选图片
                {
                    QTImg.sprite = QTSprites[0];
                    QTEngImg.sprite = QTSprites[3];
                }
                else                            //多选图片
                {
                    QTImg.sprite = QTSprites[1];
                    QTEngImg.sprite = QTSprites[4];
                }
            }
             else if (mQuestionData.answerData.Count == 2)//判断图片
            {
                QTImg.sprite = QTSprites[2];
                QTEngImg.sprite = QTSprites[5];
            }

            //提取选项
            optionContent = item.optionText.GetComponent<Text>().text.Split('.');

            //题目判断
            if (item.thisToggle.isOn)
            {
                if (!isSub)
                {
                    submitBtn.interactable = true;
                    isSub = true;
                }
                //如果是单选的话,直接把正确答案跟选择的答案比较
                if (mQuestionData.IsSingleChoice)
                {
                    temp = optionContent[0];
                    Debug.Log("单选" + optionContent[0]);
                }
                else
                {
                    if (optionContent[0] == "A")
                        optionA = "A";
                    else if (optionContent[0] == "B")
                        optionB = "B";
                    else if (optionContent[0] == "C")
                        optionC = "C";
                    else if (optionContent[0] == "D")
                        optionD = "D";
                    temp = optionA + optionB + optionC + optionD;
                }
            }
            else
            {
                if (!mQuestionData.IsSingleChoice)
                {
                    if (optionContent[0] == "A")
                        optionA = "";
                    else if (optionContent[0] == "B")
                        optionB = "";
                    else if (optionContent[0] == "C")
                        optionC = "";
                    else if (optionContent[0] == "D")
                        optionD = "";
                    temp = optionA + optionB + optionC + optionD;
                    Debug.Log("多选2" + temp);
                }
            }
            
        }
    }

    #region 读取xml文件
    IEnumerator LoadingQuesiton(string path)
    {
        yield return null;
        using (WWW www = new WWW(path))
        {
            yield return www;
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(www.text);
            new QuestionPanel(doc.FirstChild);

        }
    }
    #endregion

    #region 初始化第一道题
    public void InitQuestionPanel(QuestionPanelData questionPanelData)
    {
        randomNum.Clear();
        GetRandomNum();
        //this.gameObject.SetActive(true);
        mQuestionPanelData = questionPanelData;
        CreateQuestion(questionPanelData.questionData[randomNum[index]]);
    }
    #endregion

    #region 创建题目
    bool isFirst = false;
    public void CreateQuestion(QuestionData questionData)
    {
      
        //数据赋值
        analysisData.text = "";

        mQuestionData = questionData;
        questionID.text = string.Format("第{0}题(共" + mQuestionPanelData.questionData.Count + "题)", index + 1);
        if (mQuestion != null)
        {
            Destroy(mQuestion);
        }

        //实例化题目预制体
        QuestionText = "QuestionText";
        mQuestion = Instantiate(Resources.Load<GameObject>(QuestionText));
        mQuestion.transform.SetParent(contentScrollContent);
        mQuestion.transform.localScale = Vector3.one;
        mQuestion.GetComponent<Text>().text = questionData.problem;

        if (options.Count > 0)
        {
            for (int i = 0; i < options.Count; i++)
            {
                Destroy(options[i].gameObject);
            }
        }
        options = new List<Options>();

        //实例化按钮选项组序列
        if (!isFirst)
            for (int i = 0; i < mQuestionPanelData.questionData.Count; i++)
            {
                //Instantiate(prefab, scrollView);
                isFirst = true;
            }

        //实例化选项预制体
        for (int i = 0; i < questionData.answerData.Count; i++)
        {
            Options option = Instantiate(Resources.Load<Options>("Options"));
            option.Init(questionData.answerData[i]);
            option.transform.SetParent(selectContent);
            //如果是单选则设置为一个toggle组
            if (questionData.IsSingleChoice)
            {
                option.thisToggle.group = questionGroup;
            }

            options.Add(option);
        }
    }
    #endregion

    #region 前往盲盒界面 开始答题 上一题 下一题  提交按钮事件

    //前往盲盒界面
    void ToStartRootEvent()
    {
        firstRoot.SetActive(false);
        startRoot.SetActive(true);
        answerRoot.SetActive(false);
        endRoot.SetActive(false);
    }

    #region 开始答题
    string QuestionText;
    // 开始答题
    public void StartAnswer()
    {
        firstRoot.SetActive(false);
        startRoot.SetActive(false);
        answerRoot.SetActive(true);
        endRoot.SetActive(false);
        //QuestionText = DataPath.QuestionData;
        //StartCoroutine(LoadingQuesiton(DataPath.QuestionData));

        for (int i = 0; i < QuestionPanel.questionPanelData.Count; i++)
        {
            InitQuestionPanel(QuestionPanel.questionPanelData[i]);
        }

    }
    #endregion


    // 下一题点击事件
    private void nextClick()
    {
        if (index < mQuestionPanelData.questionData.Count - 1)
        {
            index++;
            CreateQuestion(mQuestionPanelData.questionData[randomNum[index]]);
        }

        submitBtn.interactable = false;
        isSub = false;

    }

    bool isCorrent;     //是否全部答对
    string rightAnswer;
    int correntNum = 0;     //正确题目个数
    int errerNUM = 0;       //错误题目个数
    // 题目提交事件
    private void submitClick()
    {
        isSub = true;
        //遍历当前题目的选项,有选择的就可以提交核验答案,并显示解析内容
        foreach (var item in options)
        {
            if (item.thisToggle.isOn)
            {
                rightAnswer = "";
                for (int i = 0; i < mQuestionData.answerData.Count; i++)
                {
                    switch (i)
                    {
                        case 0:
                            if (mQuestionData.answerData[i].Score > 0)//xml文档里面score属性对应的数值是用来判断该选项是否为正确选项
                            {
                                rightAnswer += "A";
                            }
                            break;
                        case 1:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "B";
                            }
                            break;
                        case 2:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "C";
                            }
                            break;
                        case 3:
                            if (mQuestionData.answerData[i].Score > 0)
                            {
                                rightAnswer += "D";
                            }
                            break;
                    }
                }
            }
            //选择一个选项之后不能在选择其他选项
            item.thisToggle.interactable = false;
        }

        //题目正确与否的判断
        if (rightAnswer == temp)
        {
            //正确数量计数
            correntNum += 1;
            Debug.Log("正确数量"+correntNum);
            //把多选的字符串置空
            StringToNull();
            analysisData.text = String.Format("恭喜你,答对啦!");
            GetComponent<AudioSource>().clip = musics[0];
            GetComponent<AudioSource>().Play();
        }
        else
        {
            //错误数量计数
            errerNUM += 1;
            Debug.Log("错的数量" + errerNUM);

            //把多选的字符串置空
            StringToNull();
            analysisData.text = String.Format("很遗憾,答错了!正确答案是:{0}\n", rightAnswer);
            //错误音效播放
            GetComponent<AudioSource>().clip = musics[1];
            GetComponent<AudioSource>().Play();
            defeatImg.gameObject.SetActive(true);
            
        }

        submitBtn.interactable = false;

        //答对题目数量大于等于6个,显示成功界面,打错数量>=4个,显示失败界面
        if ( correntNum >= 6)
        {
            isCorrent = true;
            Invoke("ShowLastRoot", 3);
        }
        else if (errerNUM >= 4)
        {
            isCorrent = false;
            Invoke("ShowLastRoot", 3);
        }
        else
            //三秒后到下一题
            Invoke("nextClick", 3);


        //提交后,该题目不可再选择修改

        submitBtn.interactable = false;
       
    }

    //返回主界面
    void BackToMain()
    {
        //返回主界面
        firstRoot.SetActive(true);
        startRoot.SetActive(false);
        answerRoot.SetActive(false);
        endRoot.SetActive(false);

        //计数归零
        index = 0;
        correntNum = 0;
        errerNUM = 0;

        //提交按钮的初始化
        submitBtn.interactable = false;
        isSub = false;
    }

    //显示结束界面
    void ShowLastRoot()
    {
        //界面的显示
        firstRoot.SetActive(false);
        startRoot.SetActive(false);
        answerRoot.SetActive(false);
        endRoot.SetActive(true);

        //如果答对显示正确界面,答错显示错误界面
        if (isCorrent)
        {
            correntImg.gameObject.SetActive(true);
            defeatImg.gameObject.SetActive(false);
            GetComponent<AudioSource>().clip = musics[2];
            GetComponent<AudioSource>().Play();
        }
        else
        {
            correntImg.gameObject.SetActive(false);
            defeatImg.gameObject.SetActive(true);
            GetComponent<AudioSource>().clip = musics[3];
            GetComponent<AudioSource>().Play();
        }

        
        //延迟3秒返回主界面
        Invoke("BackToMain", 5);
    }

    #region 多选字符串归零
    void StringToNull()
    {
        optionA = "";
        optionB = "";
        optionC = "";
        optionD = "";
    }
    #endregion
    #endregion

    #region 随机顺序出题
    void GetRandomNum()
    {
        //利用哈希函数获取随机数
        HashSet<int> nums = new HashSet<int>();
        System.Random r = new System.Random();
        while (nums.Count != 9)
        {
            nums.Add(r.Next(0, 9));
        }
        //Debug.Log(topicMax);
        foreach (var item in nums)
        {
            randomNum.Add(item);
        }
    }

    #endregion

}

#region 答题数据类
/// <summary>
/// 答题panel数据类
/// </summary>
public class QuestionPanel
{
    public static List<QuestionPanelData> questionPanelData;
    public QuestionPanel(XmlNode node)
    {
        questionPanelData = new List<QuestionPanelData>();
        for (int i = 0; i < node.ChildNodes.Count; i++)
        {
            questionPanelData.Add(new QuestionPanelData(node.ChildNodes[i]));
            //Debug.Log(questionPanelData);
        }
    }
}

/// <summary>
/// 答题界面数据类
/// </summary>
public class QuestionPanelData
{
    public List<QuestionData> questionData;
    public QuestionPanelData(XmlNode node)
    {
        questionData = new List<QuestionData>();
        for (int i = 0; i < node.ChildNodes.Count; i++)
        {
            questionData.Add(new QuestionData(node.ChildNodes[i]));
        }
    }
}

/// <summary>
/// 题目数据类
/// </summary>
public class QuestionData
{
    // 是否为单选,true为单选,false为多选
    private bool isSingleChoice;
    // 解析内容
    public string Analysis;
    // 题目内容
    public string problem;
    public List<AnswerData> answerData;

    public bool IsSingleChoice { get => isSingleChoice; set => isSingleChoice = value; }

    public QuestionData(XmlNode node)
    {
        isSingleChoice = bool.Parse(node.Attributes["SelectType"].InnerText);
        Analysis = node["Analysis"].InnerText;
        problem = node["Problem"].InnerText;
        answerData = new List<AnswerData>();
        XmlNodeList nodelist = node["Answer"].ChildNodes;
        for (int i = 0; i < nodelist.Count; i++)
        {
            answerData.Add(new AnswerData(nodelist[i]));
        }
    }
}

/// <summary>
/// 答案数据类
/// </summary>
public class AnswerData
{
    // 选项的内容
    public string option;
    // 选项对应的分数
    public int Score;
    public AnswerData(XmlNode node)
    {
        option = node.Attributes["option"].InnerText;
        Score = int.Parse(node.InnerText);
    }
}
#endregion

答案类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Options : MonoBehaviour
{
    /// <summary>
    /// 当前选项组件
    /// </summary>
    public Toggle thisToggle;
    /// <summary>
    /// 选项的内容文本
    /// </summary>
    public Text optionText;
    /// <summary>
    /// 选项对应的分数
    /// </summary>
    public int score;
    /// <summary>
    /// 选项的状态
    /// </summary>
    public bool IsSelect = false;

    public void Init(AnswerData answerData)
    {
        optionText.text = answerData.option;
        score = answerData.Score;
        thisToggle.onValueChanged.AddListener((isSelect) => { IsSelect =isSelect; });
    }
}

答题的xml文件位置

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 全局静态类,用来定义静态字段,方便调用
/// </summary>
public class DataPath
{
    public static string QuestionData = "file://" + Application.dataPath + "/StreamingAssets/" + 0 + ".xml";

    //public static string QuestionData;
    public static string QuestionText = "QuestionText";

}

四:UI界面

把第一个代码挂在canvas上面,然后把里面对应的内容拉进去就行了

(答题的那个内容的各个部分可以看上一个文章unity制作答题系统_unity答题系统_石阿包的博客-CSDN博客) 

猜你喜欢

转载自blog.csdn.net/shijinlinaaa/article/details/132364317