美文网首页
Unity实现可移植答题模块的简单实现

Unity实现可移植答题模块的简单实现

作者: Moment__格调 | 来源:发表于2019-11-22 23:45 被阅读0次

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/qq_17367039/article/details/102936483
    Unity实现可移植答题模块的简单实现
    前言
    在最近的几天里,领导交代开发一个答题功能的模块,需要很方便地移植到其他项目中。因为我之前开发过答题功能的项目,所以对这个需求也不虚,但是开发这种类似于插件的功能,我还是没有搞过的。于是我翻了翻之前的项目,看了看代码,思考了一下,感觉还是可以搞出来的,于是研究了两天,将这个可以方便移植的答题模块搞了出来,先看下效果图。
    效果图1:

    效果图2:

    效果图3:

    效果图4:

    步骤一
    在场景中创建一个Scroll View组件,在其子物体Content里添加两个组件,Vertical Layout Group和Content Size Fitter,如下图所示:

    步骤二
    在Content下创建TopicSelect物体,在下面添加几种UI组件,将其做成Prafab,结构如图所示:

    步骤三
    添加TopicSelectScr脚本:代码如下图所示:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    //using SUIFW;
    /// <summary>
    /// 一道选择题
    /// </summary>
    public class TopicSelectScr : MonoBehaviour
    {
    /// <summary>
    /// 自身的考试题 需要赋值的数据
    /// </summary>
    public ExaminationDate examination;
    /// <summary>
    /// 是否选择正确,通过属性判断成绩
    /// </summary>
    public bool isCorrect;
    //查找组件
    public Text IdTxt;
    public Text SubjectTxt;
    public Toggle Toggle_A;
    public Text Toggle_A_Label;
    public Toggle Toggle_B;
    public Text Toggle_B_Label;
    public Toggle Toggle_C;
    public Text Toggle_C_Label;
    public Toggle Toggle_D;
    public Text Toggle_D_Label;
    public int topicId;
    public Text answerText;

    GameObject rootGo;
    
    public GameObject[] toggleBackGround;
    
    private void Awake()
    {
        Toggle_A.isOn = false;
        Toggle_B.isOn = false;
        Toggle_C.isOn = false;
        Toggle_D.isOn = false;
    

    }

    /// <summary>
    /// 赋值完数据之后,需要更新UI的显示,并提供题号的id
    /// </summary>
    /// <param name="id"></param>
    public void OnChangeUIShow(int id,int FontSize=28)
    {
        topicId = id;
        IdTxt.text = id.ToString();
        SubjectTxt.text = examination.Topic;
        Toggle_A_Label.text = examination.Select[0];
        Toggle_A_Label.fontSize = FontSize;
        Toggle_B_Label.text = examination.Select[1];
        Toggle_B_Label.fontSize = FontSize;
        Toggle_C_Label.text = examination.Select[2];
        Toggle_C_Label.fontSize = FontSize;
        Toggle_D_Label.text = examination.Select[3];
        Toggle_D_Label.fontSize = FontSize;
        answerText.text = examination.Analysis;
        Toggle_A.onValueChanged.AddListener(TogSelectA);
        Toggle_B.onValueChanged.AddListener(TogSelectB);
        Toggle_C.onValueChanged.AddListener(TogSelectA);
        Toggle_D.onValueChanged.AddListener(TogSelectB);
    }
    /// <summary>
    /// 选择1
    /// </summary>
    /// <param name="ison"></param>
    void TogSelectA(bool ison)
    {
        int id = 0;//该选择的判断标识
        int res;
        if (ison)
        {
            if (int.TryParse(examination.Answer, out res))//将json的正确答案对比
            {
                if (id == res)//判断否正确
                {
                    isCorrect = true;
                }
                else
                {
                    isCorrect = false;
                }
            }
        }
        else
        {
            isCorrect = false;
        }
    }
    /// <summary>
    /// 选择2
    /// </summary>
    /// <param name="ison"></param>
    void TogSelectB(bool ison)
    {
        int id = 1;
        int res;
        if (ison)
        {
            if (int.TryParse(examination.Answer, out res))
            {
                if (id == res)
                {
                    isCorrect = true;
                }
                else
                {
                    isCorrect = false;
                }
            }
        }
        else
        {
            isCorrect = false;
        }
    }
    /// <summary>
    /// 选择3
    /// </summary>
    /// <param name="ison"></param>
    void TogSelectC(bool ison)
    {
        int id = 2;
        int res;
        if (ison)
        {
            if (int.TryParse(examination.Answer, out res))
            {
                if (id == res)
                {
                    isCorrect = true;
                }
                else
                {
                    isCorrect = false;
                }
            }
        }
        else
        {
            isCorrect = false;
        }
    }
    /// <summary>
    /// 选择4
    /// </summary>
    /// <param name="ison"></param>
    void TogSelectD(bool ison)
    {
        int id = 3;
        int res;
        if (ison)
        {
            if (int.TryParse(examination.Answer, out res))
            {
                if (id == res)
                {
                    isCorrect = true;
                }
                else
                {
                    isCorrect = false;
                }
            }
        }
        else
        {
            isCorrect = false;
        }
    }
    
    /// <summary>
    /// 隐藏勾选对象
    /// </summary>
    internal void ToHideToggle()
    {
        for (int i = 0;i<toggleBackGround.Length;i++)
        {
            toggleBackGround[i].SetActive(false);
        }
    }
    

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    步骤四
    将TopicSelectScr脚本挂载到TopicSelect物体上,将里面组件拖到脚本中,制作完预制体后在场景中将其删除,物体上的组件如下图所示:

    步骤五
    在场景中建立StreamingAssets文件夹,在其中创建一个JsonTest.json文件,用文本编辑器打开,里面数据如图所示:

    步骤六
    开始解析json功能的开发,首先创建ExaminationDate.CS脚本,脚本代码如下所示:

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

    [Serializable]
    public class ExaminationDate
    {
    //题目
    public string Topic;
    //答案选择
    public string[] Select;
    //正确的id
    public string Answer;
    //答案解析
    public string Analysis;

    public ExaminationDate()
    {
        Select = new string[4];
    }
    
    public override string ToString()
    {
        return Topic + " " + Select[0] + " " + Select[1] + " " + Select[2] + " " + Select[3] + " " + Answer + Analysis;
    }
    

    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    步骤七
    json解析以及题目展示、判断核心代码如下所示:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.Text;
    using System.Text.RegularExpressions;
    using System;
    using System.IO;
    using LitJson;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;

    public class ExamTestScr : MonoBehaviour
    {
    //解析芯片之后得到所有的考题信息
    List<ExaminationDate> examList = new List<ExaminationDate>();
    //错误题的集合信息
    public List<ExaminationDate> WrongList = new List<ExaminationDate>();
    //考题的预设体
    public TopicSelectScr topicSelectFormPro;
    public RectTransform contentParent;//考试题预设体的父物体
    float t_Height = 0;//获取单个预设体UI的高度
    //临时保存考题的实例化集合
    List<TopicSelectScr> topicSelectS = new List<TopicSelectScr>();
    //错题的标记id
    public List<TopicSelectScr> topicMarkS = new List<TopicSelectScr>();
    int TopicNum = 0;
    //核对几道正确的题
    public float index = 0;
    //错题的标记id 临时保存
    public List<TopicSelectScr> TopicMarks = new List<TopicSelectScr>();
    //public static string Examination = "http://www.techvew.com/Data/Examination/Examination.json";
    public string Examination;
    //每题的分数
    int thisScore = 0;
    //展示分数的Panel
    public GameObject showScorePanel;
    //展示分数的Text组件
    public Text showScoreText;
    //文本管理类
    ConfigTest configTest;
    //场景名称
    string scenceName = "";
    //计算分数按钮
    public GameObject countButton;
    //进入实验按钮
    public GameObject intoGameButton;
    //答题父物体
    public GameObject content;

    // Use this for initialization
    void Start ()
    {
        Examination = Application.streamingAssetsPath + "/JsonTest.json";
        BeginString();
        StartCoroutine(ToAnalysisExamOKInfo());
    }
    
    /// <summary>
    /// 加载物体
    /// </summary>
    void BeginString()
    {
        configTest = GameObject.Find("configTest").GetComponent<ConfigTest>();
        StartCoroutine(ToBeginString());
    }
    /// <summary>
    /// 初始化字符串
    /// </summary>
    /// <returns></returns>
    IEnumerator ToBeginString()
    {
        yield return new WaitForSeconds(0.1f);
        TopicNum = int.Parse(configTest.dic["题数"]["TiNumber"]);
        scenceName = configTest.dic["场景名称"]["ScenceName"];
        thisScore = int.Parse(configTest.dic["每题分数"]["thisScore"]);
    }
    
    /// <summary>
    /// 延时执行解析题目
    /// </summary>
    /// <returns></returns>
    IEnumerator ToAnalysisExamOKInfo()
    {
        yield return new WaitForSeconds(0.2f);
        AnalysisExamOKInfo();
    }
    
    /// <summary>
    /// 解析考试题
    /// </summary>
    void AnalysisExamOKInfo()
    {
        StartCoroutine(OnWwwDoenLoad(Examination));
    }
    /// <summary>
    /// 实例化一定数量的考试题
    /// </summary>
    /// <param name="TopicNum">考题的数量</param>
    public void InfoExamTopic(float TopicNum)
    {
        //集合数据清除
        if (topicSelectS.Count > 0)//如果有原始的题号
        {
            for (int i = 0;i < topicSelectS.Count;i++)
            {
                Destroy(topicSelectS[i].gameObject);
            }
        }
        if (examList.Count <= 0)
        {
            Debug.Log("解析失败,数据个数为0");
            return;
        }
        //动态设置父物体的高度
        contentParent.sizeDelta = new Vector2(contentParent.rect.width,TopicNum * t_Height);
        //实例化一定数量的考题
        if (TopicNum > 0)//给定的数值必须大于0
        {
            int index = UnityEngine.Random.Range(0,examList.Count - (int)TopicNum);
            topicSelectS.Clear();
            for (int i = 0;i < TopicNum;i++)
            {
                TopicSelectScr Select = Instantiate(topicSelectFormPro);
                topicSelectS.Add(Select);//添加到集合中,方便审核成绩
                Select.transform.SetParent(contentParent);
                Select.gameObject.transform.localScale = Vector3.one;
                Select.examination = examList[index++];
                Select.OnChangeUIShow(i + 1,30);
            }
        }
    }
    /// <summary>
    /// 接在网络路径的json 解析
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    IEnumerator OnWwwDoenLoad(string url)
    {
        WWW www = new WWW(url);
        yield return www;
        if (!string.IsNullOrEmpty(www.text))
        {
            string ExamContent = www.text;
            //Debug.Log(ExamContent);
            examList = JsonMapper.ToObject<List<ExaminationDate>>(ExamContent);
            //print("A" + examList.Count);
        }
        //解析数据之后
        InfoExamTopic(TopicNum);
    }
    /// <summary>
    /// 提交按钮,统计成绩
    /// </summary>
    public void SubmitInfo()
    {
        index = 0;//重置正确的数量
        topicMarkS.Clear();//清空错题id
        //计算正确的题号
        for (int i = 0;i < topicSelectS.Count;i++)
        {
            if (topicSelectS[i].isCorrect == true)//得到正确的数量
            {
                index++;
                topicSelectS[i].gameObject.SetActive(false);
            }
            else
            {
                topicMarkS.Add(topicSelectS[i]);//捕获错误的题号id
                topicSelectS[i].answerText.gameObject.SetActive(true);
                topicSelectS[i].ToHideToggle();
            }
        }
        StartCoroutine(ToCountScore());
    }
    /// <summary>
    /// 计算分数的协程
    /// </summary>
    /// <returns></returns>
    IEnumerator ToCountScore()
    {
        yield return new WaitForSeconds(0.1f);
        thisScore = (int)index * 10;
        showScorePanel.SetActive(true);
        //Debug.Log("您的分数为:" + thisScore.ToString());
        showScoreText.text = "您的分数为:" + thisScore.ToString();
    }
    
    /// <summary>
    /// 开始试验
    /// </summary>
    public void ToBeginGame()
    {
        SceneManager.LoadScene(scenceName);
    }
    
    /// <summary>
    /// 显示错题
    /// </summary>
    public void ToShowWrong()
    {
        showScorePanel.SetActive(false);
        countButton.SetActive(false);
        intoGameButton.SetActive(true);
        content.transform.localPosition = new Vector3(0f,0f); 
    }
    

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    步骤八
    将此脚本挂载到daTiPanel上,如下图所示:

    步骤九
    为了便于一直,我在这个工程中添加了本地配置文件的功能,通过修改本地配置文件的参数可以修改生成题的数量和每道题的分数,在StreamingsAssets文件夹下添加Config.txt文件,里面参数设置如下所示:

    步骤十
    添加ConfigTest脚本,挂载到场景的物体上,代码如下图所示:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    using System;

    /// <summary>
    /// 配置文件读取
    /// </summary>
    public class ConfigTest : MonoBehaviour
    {
    private string configPath;

    public Dictionary<string, Dictionary<string, string>> dic;
    
    private void Awake()
    {
        //读取配置文件(StreamingAssets)路径
        configPath = Path.Combine(Application.streamingAssetsPath,"Config.txt");
        if (dic == null)
        {
            dic = new Dictionary<string, Dictionary<string, string>>();
            LoadConfig();
        }
    }
    
    /// <summary>
    /// 读取所有的数据
    /// </summary>
    void LoadConfig()
    {
        string[] lines = null;
        if (File.Exists(configPath))
        {
            lines = File.ReadAllLines(configPath);
            BuildDic(lines);
        }
    }
    /// <summary>
    /// 处理所有的数据
    /// </summary>
    /// <param name="lines"></param>
    private void BuildDic(string[] lines)
    {
        string mainKey = null;//主键
        string subKey = null;//子键
        string subValue = null;//值
        foreach (var item in lines)
        {
            string line = null;
            line = item.Trim();//去除空白行
            if (!string.IsNullOrEmpty(line))
            {
                if (line.StartsWith("["))//取主键
                {
                    mainKey = line.Substring(1, line.IndexOf("]") - 1);
                    if (dic.ContainsKey(mainKey))
                    {
                        return;
                    }
                    dic.Add(mainKey, new Dictionary<string, string>());
                }
                else//取主键
                {
                    var configValue = line.Split(new char[] { '='},StringSplitOptions.RemoveEmptyEntries);
                    subKey = configValue[0].Trim();
                    subValue = configValue[1].Trim();
                    subValue = subValue.StartsWith("\"") ? subValue.Substring(1) : subValue;
                    dic[mainKey].Add(subKey,subValue);
                }
            }
        }
    }
    

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    步骤十一
    在ExamTestScr.cs中脚本调用配置文件脚本里的方法,如下图所示:

    总结
    通过以上的步骤,基本实现了可移植答题模块功能的实现,具体想增加什么功能还需要在以后的项目中慢慢添加吧!
    ————————————————
    版权声明:本文为CSDN博主「波波斯维奇」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_17367039/article/details/102936483

    相关文章

      网友评论

          本文标题:Unity实现可移植答题模块的简单实现

          本文链接:https://www.haomeiwen.com/subject/qiecwctx.html