2D游戏案例:Unity答题系统(TXT+界面版)

Posted 代码骑士

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2D游戏案例:Unity答题系统(TXT+界面版)相关的知识,希望对你有一定的参考价值。

目录

一、作品展示

1、菜单界面:

2、答题界面:

3、学习模式界面:

二、代码展示:

1、菜单页面:

        三个场景跳转按钮:

        (1)学习党史按钮: 

        (2)答题测试按钮:

        (3)退出系统按钮:

  

 2、退出按钮:

5、学习界面代码:

(1)代码

4、答题界面代码:

(1)返回开始菜单按钮:

(2)答题处理主代码:

三、相应资源:

1、txt文件格式

 2、如何修改题目内容

四、尾声





一、作品展示

1、菜单界面:

 (注:由于特殊原因,原图无法展示,请谅解)

2、答题界面:

  (注:由于特殊原因,原图无法展示,请谅解)

3、学习模式界面:

  (注:由于特殊原因,原图无法展示,请谅解)

二、代码展示:

1、菜单页面:

        三个场景跳转按钮:

        (1)学习党史按钮: 

using UnityEngine.SceneManagement;
using UnityEngine;

public class EnterStudy : MonoBehaviour

    public void EnterStudy_()
    
        SceneManager.LoadScene("学习界面");
    

        (2)答题测试按钮:

using UnityEngine.SceneManagement;
using UnityEngine;

public class EnterTest : MonoBehaviour

    public void EnterTest_()
    
        SceneManager.LoadScene("example");
    

        (3)退出系统按钮:

using UnityEngine;

public class ExitSystem : MonoBehaviour

    public void Quit()
    
        Application.Quit();
    

  

 2、退出按钮:

using UnityEngine;

public class ExitSystem : MonoBehaviour

    public void Quit()
    
        Application.Quit();
    

5、学习界面代码:

(1)代码

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

public class TXT_OPRATION : MonoBehaviour

    //public TextAsset textTxt;
    //读取文档
    string[][] ArrayX;//题目数据
    string[] lineArray;//读取到题目数据

    public Text stuText;
    string[] items = new string[7]"题号:", "题目:", "A:", "B:", "C:", "D:", "答案:" ;

    void Start()
    
        LoadTxt();
        //Debug.Log(textTxt.text);
    

    private void LoadTxt()
    
        string UnityPath1 = Application.dataPath + "/StreamingAssets/题目5.txt";
        string[] allLineText = File.ReadAllLines(UnityPath1);
        for (int i = 0; i < allLineText.Length; i++)
        
            Debug.Log(allLineText.Length);
        
        ArrayX = new string[allLineText.Length][];
        //把csv中的数据储存在二维数组中  
        for (int i = 0; i < allLineText.Length; i++)
        
            ArrayX[i] = allLineText[i].Split(':');
        
        //查看保存的题目数据
        int k = 0;
        string texts = "";
        for (int i = 0; i < ArrayX.Length; i++)
        
            //texts += "题号:";
            for (int j = 0; j < ArrayX[i].Length; j++)
            
                //Debug.Log(ArrayX[i][j]);
                texts += items[k];
                texts += ArrayX[i][j];
                texts += '\\n';
                k++;
                if (k == 7)
                
                    k = 0;
                
            
        

        stuText.text = texts;

    

4、答题界面代码:

(1)返回开始菜单按钮:

using UnityEngine.SceneManagement;
using UnityEngine;

public class returnMenu : MonoBehaviour

    public void ReturnMenu()
    
        SceneManager.LoadScene("登录界面");
    

(2)答题处理主代码:

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

public class testAnswer : MonoBehaviour
 
    //读取文档
    string[][] ArrayX;//题目数据
    string[] lineArray;//读取到题目数据
    private int topicMax = 0;//最大题数
    private List<bool> isAnserList = new List<bool>();//存放是否答过题的状态

    //加载题目
    public GameObject tipsbtn;//提示按钮
    public Text tipsText;//提示信息
    public List<Toggle> toggleList;//答题Toggle
    public Text indexText;//当前第几题
    public Text TM_Text;//当前题目
    public List<Text> DA_TextList;//选项
    private int topicIndex = 0;//第几题

    //按钮功能及提示信息
    public Button BtnBack;//上一题
    public Button BtnNext;//下一题
    public Button BtnTip;//消息提醒
    public Button BtnJump;//跳转题目
    public InputField jumpInput;//跳转题目
    public Text TextAccuracy;//正确率
    private int anserint = 0;//已经答过几题
    private int isRightNum = 0;//正确题数

    void Awake()
    
        TextCsv();
        LoadAnswer();
    

    void Start()
    
        toggleList[0].onValueChanged.AddListener((isOn) => AnswerRightRrongJudgment(isOn, 0));
        toggleList[1].onValueChanged.AddListener((isOn) => AnswerRightRrongJudgment(isOn, 1));
        toggleList[2].onValueChanged.AddListener((isOn) => AnswerRightRrongJudgment(isOn, 2));
        toggleList[3].onValueChanged.AddListener((isOn) => AnswerRightRrongJudgment(isOn, 3));

        BtnTip.onClick.AddListener(() => Select_Answer(0));
        BtnBack.onClick.AddListener(() => Select_Answer(1));
        BtnNext.onClick.AddListener(() => Select_Answer(2));
        BtnJump.onClick.AddListener(() => Select_Answer(3));
    


    /*****************读取txt数据******************/
    void TextCsv()
    
        string UnityPath1 = Application.dataPath + "/StreamingAssets/题目5.txt";
        string[] allLineText = File.ReadAllLines(UnityPath1);
        for (int i = 0; i < allLineText.Length; i++)
        
            Debug.Log(allLineText.Length);
        
        ArrayX = new string[allLineText.Length][];
        //把csv中的数据储存在二维数组中  
        for (int i = 0; i < allLineText.Length; i++)
        
            ArrayX[i] = allLineText[i].Split(':');
        
        /*
        //查看保存的题目数据
        for (int i = 0; i < ArrayX.Length; i++)
        
            for (int j = 0; j < ArrayX[i].Length; j++)
            
                Debug.Log(ArrayX[i][j]);
            
        
        */
        //设置题目状态
        topicMax = allLineText.Length;
        for (int x = 0; x < topicMax; x++)
        
            isAnserList.Add(false);
        
    

    /*****************加载题目******************/
    void LoadAnswer()
    
        for (int i = 0; i < toggleList.Count; i++)
        
            toggleList[i].isOn = false;
        
        for (int i = 0; i < toggleList.Count; i++)
        
            toggleList[i].interactable = true;
        

        tipsbtn.SetActive(false);
        tipsText.text = "";

        indexText.text = "第" + (topicIndex + 1) + "题:";//第几题
        TM_Text.text = ArrayX[topicIndex][1];//题目
        int idx = ArrayX[topicIndex].Length - 3;//有几个选项
        for (int x = 0; x < idx; x++)
        
            DA_TextList[x].text = ArrayX[topicIndex][x + 2];//选项
        
    

    /*****************按钮功能******************/
    void Select_Answer(int index)
    
        switch (index)
        
            case 0://提示
                int idx = ArrayX[topicIndex].Length - 1;
                int n = int.Parse(ArrayX[topicIndex][idx]);
                string nM = "";
                switch (n)
                
                    case 1:
                        nM = "A";
                        break;
                    case 2:
                        nM = "B";
                        break;
                    case 3:
                        nM = "C";
                        break;
                    case 4:
                        nM = "D";
                        break;
                
                tipsText.text = "<color=#FFAB08FF>" + "正确答案是:" + nM + "</color>";
                break;
            case 1://上一题
                if (topicIndex > 0)
                
                    topicIndex--;
                    LoadAnswer();
                
                else
                
                    tipsText.text = "<color=#27FF02FF>" + "前面已经没有题目了!" + "</color>";
                
                break;
            case 2://下一题
                if (topicIndex < topicMax - 1)
                
                    topicIndex++;
                    LoadAnswer();
                
                else
                
                    tipsText.text = "<color=#27FF02FF>" + "哎呀!已经是最后一题了。" + "</color>";
                
                break;
            case 3://跳转
                int x = int.Parse(jumpInput.text) - 1;
                if (x >= 0 && x < topicMax)
                
                    topicIndex = x;
                    jumpInput.text = "";
                    LoadAnswer();
                
                else
                
                    tipsText.text = "<color=#27FF02FF>" + "不在范围内!" + "</color>";
                
                break;
        
    

    /*****************题目对错判断******************/
    void AnswerRightRrongJudgment(bool check, int index)
    
        if (check)
        
            //判断题目对错
            bool isRight;
            int idx = ArrayX[topicIndex].Length - 1;
            int n = int.Parse(ArrayX[topicIndex][idx]) - 1;
            if (n == index)
            
                tipsText.text = "<color=#27FF02FF>" + "恭喜你,答对了!" + "</color>";
                isRight = true;
                tipsbtn.SetActive(true);
            
            else
            
                tipsText.text = "<color=#FF0020FF>" + "对不起,答错了!" + "</color>";
                isRight = false;
                tipsbtn.SetActive(true);
            

            //正确率计算
            if (isAnserList[topicIndex])
            
                tipsText.text = "<color=#FF0020FF>" + "这道题已答过!" + "</color>";
            
            else
            
                anserint++;
                if (isRight)
                
                    isRightNum++;
                
                isAnserList[topicIndex] = true;
                TextAccuracy.text = "正确率:" + ((float)isRightNum / anserint * 100).ToString("f2") + "%";
            

            //禁用掉选项
            for (int i = 0; i < toggleList.Count; i++)
            
                toggleList[i].interactable = false;
            
        
    

三、相应资源:

1、txt文件格式

题号:题目:A选项:B选项:C选项:D选项:答案的序号
题号:题目:A选项:B选项:C选项:D选项:答案的序号
题号:题目:A选项:B选项:C选项:D选项:答案的序号
题号:题目:A选项:B选项:C选项:D选项:答案的序号
题号:题目:A选项:B选项:C选项:D选项:答案的序号
……
(注:最后一题的末尾不加回车,所有冒号都是英文格式)

 2、如何修改题目内容

        这是本系统的一大亮点,也是Unity开发的一个神奇的特性。往往我们做的程序想要修改信息都要连接云服务器、数据库什么的,很少有能在本地直接修改的,并且修改完内置文件之后往往都会使程序崩溃,本系统使用的数据修改方法是将题目写在外部文档,使程序能够动态读取和修改题目信息。这种方式支持的文档格式可以是txt、xml、json,本系统用的是最简便的txt文本。

        这是因为我们在Unity中新建一个StreamingAssets文件夹,这个文件夹中的内容可以在应用发布时原封不动地打包进去(不会被加密和压缩),一般用来存放二进制文件。

        有了这个文件夹,我们就可以在打包完之后也可以进行文件中的修改(只限制于StreamingAssets文件夹)从而实现增删题目的功能。

        唯一的限制就是添加修改题目要满足固定格式,不然读取会出现错误。

 (按此路径找到题目文件)

E:\\xx学习系统5.0plus\\xx学习与答题系统_Data\\StreamingAssets

四、尾声

 诚挚感谢博主恬静的小魔龙 、

York_New和的文章令我受益匪浅。

参考文章:(8条消息) 【Unity3D应用案例系列】答题系统开发_恬静的小魔龙的博客-CSDN博客_unity答题系统https://blog.csdn.net/q764424567/article/details/117259582?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165191697316781483767112%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165191697316781483767112&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-117259582-null-null.142%5Ev9%5Epc_search_result_control_group,157%5Ev4%5Econtrol&utm_term=unity%E7%AD%94%E9%A2%98&spm=1018.2226.3001.4187

(2条消息) Unity学习篇之txt文本文档的多种读写方式_York_New的博客-CSDN博客_unity读取文本https://blog.csdn.net/York_New/article/details/84302895?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-1-84302895-null-null.pc_agg_new_rank&utm_term=unity%E4%BF%AE%E6%94%B9txt&spm=1000.2123.3001.4430(4条消息) Unity学习篇之txt文本文档的多种读写方式_York_New的博客-CSDN博客_unity读取文本https://blog.csdn.net/York_New/article/details/84302895?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-1-84302895-null-null.pc_agg_new_rank&utm_term=unity%E4%BF%AE%E6%94%B9txt&spm=1000.2123.3001.4430

(2条消息) unity修改txt - CSDNhttps://www.csdn.net/tags/Mtjacg5sMTI3NjEtYmxvZwO0O0OO0O0O.html

最后放上作品链接,大家一起来学习吧!

链接:https://pan.baidu.com/s/1Em67E803tY_HHyEcg7tgCw 
提取码:uf29

工程文件资源获取:

unity游戏案例:知识学习系统-Unity3D文档类资源-CSDN下载

Unity-3D-H2

1、简答题【建议做解释 游戏对象(GameObjects) 和 资源(Assets)的区别与联系。

    •   游戏对象:直接出现在游戏的场景中,是资源整合的具体表现,对象通过层次结构来组织,通过整体-部分的关系构成层次结构。资源:资源通过文件夹的形式组织,包含常用的图像,视频,脚本文件,预制文件等等,可以被一个或者多个对象使用。
  • 下载几个游戏案例,分别总结资源、对象组织的结构(指资源的目录组织结构与游戏对象树的层次结构)
    • 资源的目录组织结构主要包含文件、材质、模型、预制件、场景、脚本、标准资源这几个部分。资源里面又包含了图片,游戏需要用到的音乐等等。游戏对象树就如同Windows的文件资源管理器一样,树目录结构:一个游戏对象(文件夹)包含多个子对象(子文件夹),子对象(子文件夹)又可以继续包含多个子对象(子文件夹)。
  • 编写一个代码,使用 debug 语句来验证 MonoBehaviour 基本行为或事件触发的条件
    • 基本行为包括 Awake() Start() Update() FixedUpdate() LateUpdate()
    • 常用事件包括 OnGUI() OnDisable() OnEnable()
    • using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class testBehavior : MonoBehaviour
      
          void Start()
               Debug.Log("Start");
          
      
          void Awake()
              Debug.Log("Awake");
          
      
          void Update()
              Debug.Log("Update");
          
      
          void FixedUpdate()
              Debug.Log("FixedUpdate");
          
      
          void LateUpdate()
          
              Debug.Log("LateUpdate");
          
      
          void OnGUI()
              Debug.Log("OnGUI");
          
      
          void OnDisable()
              Debug.Log("OnDisable");
          
      
          void OnEnable()
              Debug.Log("OnEnable");
          
      
      

        

  • 查找脚本手册,了解 GameObject,Transform,Component 对象
    • 分别翻译官方对三个对象的描述(Description)
      • GameObject:是Unity场景里面所有实体的基类.
        Transform:物体的位置、旋转和缩放。
        Component:一切附加到游戏物体的基类。
    • 描述下图中 table 对象(实体)的属性、table 的 Transform 的属性、 table 的部件
      • 本题目要求是把可视化图形编程界面与 Unity API 对应起来,当你在 Inspector 面板上每一个内容,应该知道对应 API。
      • 例如:table 的对象是 GameObject,第一个选择框是 activeSelf 属性。
      • activeSelf:修改对象的名称,动静态等属性(图中对象名称是table,动态)
        Transform:调整对象的位置、面向方向、大小(默认位置大小)
        Box Collider:调整坐标系的位置、大小
        Add Component:给对象增加行为

    • 用 UML 图描述 三者的关系(请使用 UMLet 14.1.1 stand-alone版本出图)
      • 技术图片

         

         

  • 资源预设(Prefabs)与 对象克隆 (clone)
  • 预设(Prefabs)有什么好处?
    • 预设 (Prefab) 是一种资源 - 存储在工程视图 (Project View) 中可重复使用的游戏对象 (GameObject)。预设 (Prefabs) 可放入到多个场景中,且每个场景可使用多次。向场景添加一个预设 (Prefab) 时,就会创建它的一个实例。所有预设 (Prefab) 实例都链接到原始预设 (Prefab),实质上是原始预设的克隆。不管您的工程中有多少个实例,您对预设 (Prefab) 作薄出任何更改时,您会看到这些更改应用于所有实例。预设与对象
    • 克隆 (clone or copy or Instantiate of Unity Object) 关系?
    • 在Unity3D当中,为了快速复制出游戏对象,主要有克隆游戏对象与创建预制两种方法。

      两者区别在于:

              1、克隆游戏对象需要场景中有被克隆对象,而创建预制只需事先创建预制即可,允许场景中一开始并不存在该游戏对象。

              2、克隆出来的游戏对象并不会随着被克隆体的变化而发生变化,但是使用预制创建出来的对象会随着预制的改变而发生改变。

    • 制作 table 预制,写一段代码将 table 预制资源实例化成游戏对象
    • 将table预制体放到 Resource 文件夹下使用
      • public GameObject obj;
        void Start () 
            GameObject instance = (GameObject)Instantiate(obj.gameObject, transform.position, transform.rotation);
        
        

2、 编程实践,小游戏

  • 游戏内容: 井字棋 或 贷款计算器 或 简单计算器 等等
  • 技术限制: 仅允许使用 IMGUI 构建 UI
  • 作业目的:
    • 了解 OnGUI() 事件,提升 debug 能力
    • 提升阅读 API 文档能力
    • using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class Chess : MonoBehaviour 
      
          private int turn = 1;
          private int[,] grid = new int[3, 3];
      
          // 重新开始游戏
          void Start () 
              Restart();
          
      
          void Restart()
          
              turn = 1;
              for (int i = 0; i < 3; ++i)
              
                  for (int j = 0; j < 3; ++j)
                  
                      grid[i, j] = 0;
                  
              
          
      
          void OnGUI()
          
              //设置button中字体的大小
              GUI.skin.button.fontSize = 20; 
      
              //设置label中字体大小和颜色
              GUIStyle style = new GUIStyle();
              style.fontSize = 40;
              style.normal.textColor = new Color(255, 255, 255);
      
              //判断是否点击Restart按钮
              if(GUI.Button(new Rect(360, 500, 80, 80), "Restart"))
                  Restart();
              
      
              //判断游戏是否结束
              int result = judge();
              if (result == 1)
              
                  GUI.Label(new Rect(340, 170, 100, 50), "O wins!", style);
              
              else if (result == 2)
              
                  GUI.Label(new Rect(340, 170, 100, 50), "X wins!", style);
              else if (result == 3)
              
                  GUI.Label(new Rect(300, 170, 100, 50), "GameOver!", style);
              
      
              //生成棋盘并判断格子是否被点击
              for (int i=0; i<3; i++)
              
                  for(int j=0; j<3; j++) 
                      if (grid[i, j] == 1)
                      
                          GUI.Button(new Rect(280 + i * 80, 220 + j * 80, 80, 80), "O");
                      else if (grid[i, j] == 2)
                      
                          GUI.Button(new Rect(280 + i * 80, 220 + j * 80, 80, 80), "X");
                      else if (GUI.Button(new Rect(280 + i * 80, 220 + j * 80, 80, 80), "")&&result==0)
                      
                          if (turn == 1)
                          
                              grid[i, j] = 1;
                          else
                          
                              grid[i, j] = 2;
                          
                          turn = -turn;
                      
                  
              
          
      
          int judge()
          
              // 横向连线    
              for (int i = 0; i < 3; ++i)
              
                  if (grid[i, 0] != 0 && grid[i, 0] == grid[i, 1] && grid[i, 1] == grid[i, 2])
                  
                      return grid[i, 0];
                  
              
              //纵向连线    
              for (int j = 0; j < 3; ++j)
              
                  if (grid[0, j] != 0 && grid[0, j] == grid[1, j] && grid[1, j] == grid[2, j])
                  
                      return grid[0, j];
                  
              
              //斜向连线    
              if (grid[1, 1] != 0 &&
                  grid[0, 0] == grid[1, 1] && grid[1, 1] == grid[2, 2] ||
                  grid[0, 2] == grid[1, 1] && grid[1, 1] == grid[2, 0])
              
                  return grid[1, 1];
              
              //全部格子都被点击
              bool allClick = true;
              for (int i=0; i<3; i++)
              
                  for (int j=0; j<3; j++)
                  
                      if (grid[i, j] == 0)
                      
                          allClick = false;
                      
                  
              
              if (allClick)
                  return 3;
      
              return 0;
          
      
      

        视频链接:

3、思考题【选做】

  • 微软 XNA 引擎的 Game 对象屏蔽了游戏循环的细节,并使用一组虚方法让继承者完成它们,我们称这种设计为“模板方法模式”。
    • 为什么是“模板方法”模式而不是“策略模式”呢?
  • 将游戏对象组成树型结构,每个节点都是游戏对象(或数)。
    • 尝试解释组合模式(Composite Pattern / 一种设计模式)。
    • 使用 BroadcastMessage() 方法,向子对象发送消息。你能写出 BroadcastMessage() 的伪代码吗?
  • 一个游戏对象用许多部件描述不同方面的特征。我们设计坦克(Tank)游戏对象不是继承于GameObject对象,而是 GameObject 添加一组行为部件(Component)。
    • 这是什么设计模式?
    • 为什么不用继承设计特殊的游戏对象?

作业提交要求

  • 仅能用博客或在线文档提交作业,建议使用 Github 提交代码和作业。不能使用docx、pdf等需要下载阅读的格式
  • deadline 问课程 TA

以上是关于2D游戏案例:Unity答题系统(TXT+界面版)的主要内容,如果未能解决你的问题,请参考以下文章

unity2D横版游戏教程5-UI

小白可以用unity 制作2D 横版游戏吗?

Unity3D应用案例系列答题系统开发

Unity3D应用案例系列答题系统开发

Unity2D横版游戏地形生成

unity2D横版游戏教程-1 让人物动起来