密室逃脱——收集版

news2025/1/19 16:27:02
一、原版修改
1、导入资源

Unity Learn | 3D Beginner: Complete Project | URP

2、设置Scene

删除SampleScene,打开UnityTechnologies-3DBeginnerComplete下的MainScene

3、降低音量

(1) 打开Hierarchy面板上的Audio降低音量

(2) 打开Prefabs文件夹,找到Ghost,降低音量

4、给FaderCanvas添加组件

(1) Canvas Scaler

(2) Graphic Raycaster

二、新增收集事件
1、新增物体

(1) 新增物体:UI-Image。Questions。设置它的Rect Transform。

(2) 新增文本:ItemsText, TipText(可设置有透明度的黑色背景)

2、新建CollectedItems.cs
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;

public class CollectedItems : MonoBehaviour
{
    public QuestionCollision QuestionCollision;
    //public GameObject Questions;
    public TextMeshProUGUI ItemsText, TipText;
    static int nucleus=0, mitochondria = 0, GolgiApparatus = 0, endoplasmicReticulum = 0, ribosome = 0;
    void Start()
    {
        if (ItemsText == null || TipText == null)
        {
            Debug.LogError("Questions或ItemsText 或 TipText 未被正确分配!");
        }
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            RandomEvent();
        }
    }
    public void RandomEvent()
    {
        int numericValue = Random.Range(0, 100);
        if (numericValue < 5 && nucleus==0)
        {
            nucleus = 1;
            TipText.text = "你发现了细胞核!";
        }
        else if(numericValue < 26)
        {
            mitochondria++;
            TipText.text = "你得到了线粒体!";
        }
        else if (numericValue < 41)
        {
            endoplasmicReticulum++;
            TipText.text = "你得到了内质网*1!";
        }
        else if (numericValue < 56)
        {
            GolgiApparatus++;
            TipText.text = "你得到了高尔基体*1!";
        }
        else if (numericValue < 76)
        {
            ribosome++;
            TipText.text = "你得到了核糖体*1!";
        }
        else if (numericValue < 86)
        {
            QuestionCollision.ShowQuestions(true);
            //Questions.SetActive(true);
        }
        else
        {
            TipText.text = "你什么都没有发现……";
        }
        ItemsUpdate();
    }
    void ItemsUpdate()
    {
        ItemsText.text = "当前持有:细胞核" + nucleus + ";线粒体" + mitochondria + ";高尔基体" + GolgiApparatus + ";内质网" + endoplasmicReticulum + ";核糖体" + ribosome;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.UI;
using static UnityEngine.Rendering.DebugUI;

public class Observer : MonoBehaviour
{
    public Exercises exercises;
    public Transform player;
    public GameObject Questions;

    public TextMeshProUGUI ItemsText, TipText;
    static int nucleus=0, mitochondria = 0, GolgiApparatus = 0, endoplasmicReticulum = 0, ribosome = 0;

    bool canTriggerEffect = true;
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player")) // 玩家的标签为 "Player" 
        {
            exercises.ShowQuestion(0);
            RandomEvent(); 
        }
    }
    public void QuitBtn() 
    {
        GetComponent<UnityEngine.UI.Button>().gameObject.SetActive(false);
        Questions.SetActive(false);
    }
    void ItemsUpdate()
    {
        ItemsText.text =
            "当前持有:细胞核" + nucleus + ";线粒体" + mitochondria + ";高尔基体" + GolgiApparatus + ";内质网" + endoplasmicReticulum + ";核糖体" + ribosome;
    }
    void Start()
    {
        if (ItemsText == null || TipText == null)
        {
            Debug.LogError("ItemsText 或 TipText 未被正确分配!");
        }
    }
    void RandomEvent()
    {
        if (canTriggerEffect)
        {
            // 触发效果代码
            int numericValue = UnityEngine.Random.Range(0, 100);
            if (numericValue < 5 && nucleus == 0)//获取的随机数范围在0~4
            {
                nucleus = 1;
                TipText.text = "你发现了细胞核!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 21)
            {
                mitochondria++;
                TipText.text = "你得到了线粒体!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 41)
            {
                endoplasmicReticulum++;
                TipText.text = "你得到了内质网*1!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 61)
            {
                GolgiApparatus++;
                TipText.text = "你得到了高尔基体*1!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 81)
            {
                ribosome++;
                TipText.text = "你得到了核糖体*1!"; 
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 96)
            {
                Questions.SetActive(true);
            }
            else
            {
                TipText.text = "你什么都没有发现……";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            //gameEnding.CaughtPlayer ();
            ItemsUpdate();

            canTriggerEffect = false; // 触发效果,将canTriggerEffect设置为false
            StartCoroutine(CooldownRoutine()); // 启动冷却时间协程
        }
    }
    IEnumerator CooldownRoutine()
    {
        yield return new WaitForSeconds(60f); // 等待1分钟
        canTriggerEffect = true; // 冷却结束,可以再次触发效果
    }
    IEnumerator ClearTextRoutine(float delay)
    {
        yield return new WaitForSeconds(delay);
        TipText.text = "";
    }
}

3、更改enemy设置

(1) 复制 PointOfView预制体,得到PointOfView(1),更名为CollectedItems

(2) 移除CollectedItems上的Observer.cs,添加CollectedItems.cs

(3) 删除Hierarchy面板上的除Ghost (3)以外的敌人的PointOfView。添加CollectedItems预制体并赋值

三、编辑答题面板预制体
1、设置面板

(1) UI-Image,命名为Questions。

(2) 选中导入的图片,然后在Inspector面板中将Texture Type设置为Sprite (2D and UI)

(3) 更改Questions的Image,Transform

(4) 添加按钮,QuitBtn(以隐藏答题面板)

2、添加test

(1) 添加文本。TitleText

(2) 添加按钮。OptionBtnA,按钮下文本的名字OptionTextA,更改文字字体,复制这个按钮得到四个选项按钮

(3) 将Questions制成预制体

(4) 制作题目

3、建立题库——简单题库

A. 创建ChoiceQuestion.cs(不用挂载的脚本)可以与其他脚本放在一起

定义问题类(包含一个问题(question字段)、四个选项(options数组)和正确答案的索引(correctOptionIndex字段))

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

[System.Serializable]
public class Question
{
    public string question; // 问题文本
    public string[] options = new string[4]; // 选项数组,假设每个问题都有4个选项
    public int correctOptionIndex; // 正确答案的索引(0表示A,1表示B,依此类推)

    // 构造函数(可选),用于初始化问题
    public Question(string q, string[] opts, int correctIndex)
    {
        question = q;
        options = opts;
        correctOptionIndex = correctIndex;
    }
    // 检查答案是否正确
    public bool CheckAnswer(int playerChoice)
    {
        return playerChoice == correctOptionIndex;
    }
}

B. 在一个空物体上添加Exercises.cs,控制显示题目和选项、正误判断、答题后禁用按钮

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

public class Exercises : MonoBehaviour
{
    public Database_01 Database_01;//题库脚本
    public TextMeshProUGUI questionText;
    public Button[] optionButtons;

    private int currentQuestionIndex = 0; // 初始化当前问题索引为0


    public void ShowQuestion(int index)
    {
        if (index >= 0 && index < Database_01.questionsDatabase.Count)//如果index在questionsDatabase列表的有效范围内
        {
            // 显示题目(从列表中取出索引为index的问题,并将其文本内容显示在questionText的文本组件上)
            questionText.text = Database_01.questionsDatabase[index].question;

            // 显示选项(将Database_01中当前问题的选项文本显示在optionButtons数组或列表中的相应UI元素上)
            for (int i = 0; i < Database_01.questionsDatabase[index].options.Length; i++)
            {
                optionButtons[i].GetComponentInChildren<TextMeshProUGUI>().text = Database_01.questionsDatabase[index].options[i];
            }
        }
    }
    // 选项按钮的点击事件
    public void OnOptionButtonClicked(int buttonIndex)
    {

        foreach (var button in optionButtons)
        {
            button.interactable = false; // 设置为false以禁用按钮
        }
        // currentQuestionIndex:当前显示的问题的索引
        // 检查用户选择的答案是否正确
        bool isCorrect = Database_01.questionsDatabase[currentQuestionIndex].CheckAnswer(buttonIndex);

        // 根据检查结果执行相应的操作,比如更新UI、显示消息等
        if (isCorrect)
        {
            Debug.Log("回答正确!");
            currentQuestionIndex++; // 更新当前问题索引
        }
        else
        {
            Debug.Log("回答错误!");
        }
    }
}

C.给空物体添加Database_01.cs,以建立题库

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

public class Database_01 : MonoBehaviour
{
    public List<Question> questionsDatabase = new List<Question>(); // 选择题数据库

    void Start()
    {
        // 初始化选择题数据库
        InitializeQuestions();
    }

    void InitializeQuestions()
    {
        //添加一个问题到数据库
        questionsDatabase.Add(new Question(
            "…………是?",
            new string[] { "A. ……", "B. ……", "C. ……", "D. ……" },
            0 // 假设"选项A"是正确答案,所以索引是0
        ));

        //添加一个问题到数据库
        questionsDatabase.Add(new Question(
            "…………",
            new string[] { "A. 复杂性", "B. 多样性", "C. 统一性", "D. 稳定性" },
            2 // 假设"选项C"是正确答案,所以索引是2
        ));
    }
}
4、建立题库——导入txt文本的方式

(1) 加载文本

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

public class QuizManager : MonoBehaviour
{
    private Question currentQuestion;//存储当前展示的题目
    private List<Question> questionList;

    public TextMeshProUGUI questionTextComponent; // 用于显示题干的Text组件
    public TextMeshProUGUI optionATextComponent; // 用于显示选项A的Text组件
    public TextMeshProUGUI optionBTextComponent; // 用于显示选项B的Text组件
    public TextMeshProUGUI optionCTextComponent; // 用于显示选项C的Text组件
    public TextMeshProUGUI optionDTextComponent; // 用于显示选项D的Text组件

    void Start()
    {
        questionList = new List<Question>();
        LoadQuestionsFromTxt("QuestionBank.txt");
        GetRandomQuestion();
    }
    //加载文本文件
    void LoadQuestionsFromTxt(string filename)
    {
        // 组合文件的完整路径。Application.streamingAssetsPath是Unity的一个属性,
        // 指向StreamingAssets文件夹的路径
        string filePath = Path.Combine(Application.streamingAssetsPath, filename);
        // 检查文件是否存在
        if (File.Exists(filePath))
        {
            // 使用File.OpenText来打开文件,并创建一个StreamReader来读取内容
            using (StreamReader reader = File.OpenText(filePath))
            {
                // 声明一个字符串变量line,用于存储从文件中读取的每一行内容
                string line;
                // 逐行读取文件内容,直到读取到文件末尾
                while ((line = reader.ReadLine()) != null)
                {
                    // 使用 | 分隔每一行的内容
                    string[] data = line.Split('|');
                    // 检查是否至少有6个由竖线分隔的值(问题、四个选项和答案)
                    if (data.Length < 6)
                    {
                        Debug.LogError("Invalid line format in question file: " + line);
                        continue; // 跳过这一行,继续读取下一行
                    }
                    // 从分割后的数组中提取问题、选项和答案
                    string question = data[0];
                    string optionA = "A. " + data[1];
                    string optionB = "B. " + data[2];
                    string optionC = "C. " + data[3];
                    string optionD = "D. " + data[4];
                    string answer = data[5].ToUpper();

                    // 检查答案是否在给定的选项中
                    if (!IsValidAnswer(answer, optionA, optionB, optionC, optionD))
                    {
                        Debug.LogError("Invalid answer in question file: " + line);
                        continue; // 跳过这一行,继续读取下一行
                    }

                    // 创建一个新的Question对象,并将其添加到questionList列表中
                    Question newQuestion = new Question(question, optionA, optionB, optionC, optionD, answer.ToUpper());
                    questionList.Add(newQuestion);
                }
            }
        }
        else
        {
            Debug.LogError("Cannot find question file: " + filename);
        }
    }
    // 检查答案是否在给定的选项列表中
    bool IsValidAnswer(string answer, string optionA, string optionB, string optionC, string optionD)
    {
        //StringComparison.OrdinalIgnoreCase:确保比较时不区分大小写
        return answer.Equals("A", StringComparison.OrdinalIgnoreCase) ||
               answer.Equals("B", StringComparison.OrdinalIgnoreCase) ||
               answer.Equals("C", StringComparison.OrdinalIgnoreCase) ||
               answer.Equals("D", StringComparison.OrdinalIgnoreCase);
    }
    //从题目列表中随机选择一个题目,并将其赋值给currentQuestion变量
    public void GetRandomQuestion()
    {
        if (questionList.Count == 0)
        {
            Debug.LogError("No questions to display.");
            return;
        }
        int randomIndex = UnityEngine.Random.Range(0, questionList.Count);
        currentQuestion = questionList[randomIndex];
        questionList.RemoveAt(randomIndex);// 从列表中移除问题,防止重复
    }
        void UpdateQuestionDisplay()
        {
            // 分别设置各个Text组件的text属性
            questionTextComponent.text = currentQuestion.QuestionText;
            optionATextComponent.text = currentQuestion.OptionAText;
            optionBTextComponent.text = currentQuestion.OptionBText;
            optionCTextComponent.text = currentQuestion.OptionCText;
            optionDTextComponent.text = currentQuestion.OptionDText;
        }
    
    void OnUserAnswer()
    {
        // 处理用户答题后的操作

        // 获取下一个随机题目
        GetRandomQuestion();
        // 更新问题展示
        UpdateQuestionDisplay();
    }
}
// 定义一个名为Question的类,用于存储问题及其相关信息
[Serializable]
public class Question
{
    public string QuestionText;
    public string OptionAText;
    public string OptionBText;
    public string OptionCText;
    public string OptionDText;
    public string Answer; // 注意这里不需要ToUpper(),除非您有特定的需求

    public Question(string question, string optionA, string optionB, string optionC, string optionD, string answer)
    {
        QuestionText = question;
        OptionAText = optionA;
        OptionBText = optionB;
        OptionCText = optionC;
        OptionDText = optionD;
        Answer = answer;
    }
}

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

public class QuizManager : MonoBehaviour
{
    private Question currentQuestion;//存储当前展示的题目
    private List<Question> questionList;
    public TextMeshProUGUI questionText;

    void Start()
    {
        questionList = new List<Question>();
        LoadQuestionsFromTxt("QuestionBank.txt");
        GetRandomQuestion();
    }
    //加载文本文件
    void LoadQuestionsFromTxt(string filename)
    {
        // 组合文件的完整路径。Application.streamingAssetsPath是Unity的一个属性,
        // 指向StreamingAssets文件夹的路径
        string filePath = Path.Combine(Application.streamingAssetsPath, filename);
        // 检查文件是否存在
        if (File.Exists(filePath))
        {
            // 使用File.OpenText来打开文件,并创建一个StreamReader来读取内容
            using (StreamReader reader = File.OpenText(filePath))
            {
                // 声明一个字符串变量line,用于存储从文件中读取的每一行内容
                string line;
                // 逐行读取文件内容,直到读取到文件末尾
                while ((line = reader.ReadLine()) != null)
                {
                    // 使用 | 分隔每一行的内容
                    string[] data = line.Split('|');
                    // 检查是否至少有6个由竖线分隔的值(问题、四个选项和答案)
                    if (data.Length < 6)
                    {
                        Debug.LogError("Invalid line format in question file: " + line);
                        continue; // 跳过这一行,继续读取下一行
                    }
                    // 从分割后的数组中提取问题、选项和答案
                    string question = data[0];
                    string optionA = "A. " + data[1];
                    string optionB = "B. " + data[2];
                    string optionC = "C. " + data[3];
                    string optionD = "D. " + data[4];
                    string answer = data[5].ToUpper();

                    // 检查答案是否在给定的选项中
                    if (!IsValidAnswer(answer, optionA, optionB, optionC, optionD))
                    {
                        Debug.LogError("Invalid answer in question file: " + line);
                        continue; // 跳过这一行,继续读取下一行
                    }

                    // 创建一个新的Question对象,并将其添加到questionList列表中
                    Question newQuestion = new Question(question, optionA, optionB, optionC, optionD, answer.ToUpper());
                    questionList.Add(newQuestion);
                }
            }
        }
        else
        {
            Debug.LogError("Cannot find question file: " + filename);
        }
    }
    // 检查答案是否在给定的选项列表中
    bool IsValidAnswer(string answer, string optionA, string optionB, string optionC, string optionD)
    {
        //StringComparison.OrdinalIgnoreCase:确保比较时不区分大小写
        return answer.Equals("A", StringComparison.OrdinalIgnoreCase) ||
               answer.Equals("B", StringComparison.OrdinalIgnoreCase) ||
               answer.Equals("C", StringComparison.OrdinalIgnoreCase) ||
               answer.Equals("D", StringComparison.OrdinalIgnoreCase);
    }

    //从题目列表中随机选择一个题目,并将其赋值给currentQuestion变量
    public void GetRandomQuestion()
    {
        if (questionList.Count == 0)
        {
            Debug.LogError("No questions to display.");
            return;
        }
        int randomIndex = UnityEngine.Random.Range(0, questionList.Count);
        currentQuestion = questionList[randomIndex];
        questionList.RemoveAt(randomIndex);// 从列表中移除问题,防止重复
        string displayText = currentQuestion.QuestionText + "\n" + // 假设Question类有一个QuestionText属性
                             currentQuestion.OptionAText + "\n" + // 类似地,其他选项和答案也需要有相应的属性
                             currentQuestion.OptionBText + "\n" +
                             currentQuestion.OptionCText + "\n" +
                             currentQuestion.OptionDText;
        questionText.text = displayText;
    }
    void UpdateQuestionDisplay()
    {
        // 将currentQuestion的问题文本赋值
        // 将currentQuestion的问题文本赋值给questionText的text属性
        questionText.text = currentQuestion.QuestionText;
    }
    void OnUserAnswer()
    {
        // 处理用户答题后的操作

        // 获取下一个随机题目
        GetRandomQuestion();
        // 更新问题展示
        UpdateQuestionDisplay();
    }
}


// 定义一个名为Question的类,用于存储问题及其相关信息
[Serializable]
public class Question
{
    public string QuestionText;
    public string OptionAText;
    public string OptionBText;
    public string OptionCText;
    public string OptionDText;
    public string Answer; // 注意这里不需要ToUpper(),除非您有特定的需求

    public Question(string question, string optionA, string optionB, string optionC, string optionD, string answer)
    {
        QuestionText = question;
        OptionAText = optionA;
        OptionBText = optionB;
        OptionCText = optionC;
        OptionDText = optionD;
        Answer = answer;
    }
}

(1) 

(2) QuestionBank.txt文件位于Unity项目的StreamingAssets文件夹中,并且格式正确(即每行都有六个由 | 分隔的值)答案用ABCD表示

(3) 

(4)

4、设置调用test

(1) 给JohnLemon添加PlayerQuest.cs

5、判断正误

6、生命值脚本
using UnityEngine;

public class PlayerHealth : MonoBehaviour
{
    public int maxLives = 3;
    private int currentLives;

    private void Start()
    {
        currentLives = maxLives;
    }

    public void AddLife()
    {
        if (currentLives < maxLives)
        {
            currentLives++;
        }
    }

    public void LoseLife()
    {
        if (currentLives > 0)
        {
            currentLives--;
        }
        else
        {
            Debug.Log("角色死亡!退出游戏");
        }
    }
}

7、问题面板显示和隐藏脚本
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class QuestionCollision : MonoBehaviour
{
    public GameObject questionPanel;//问题面板
    public Button QuitBtn;
    public TextMeshProUGUI questionText;//问题文本
    public Button[] optionBtns;
    public PlayerHealth playerHealth;

    public void ShowQuestions(bool isQuestionActivated)
    {
        if (isQuestionActivated)
        {
            questionPanel.SetActive(true);
        }
        else
        {
            questionPanel.SetActive(false);
        }
        foreach (Button button in optionBtns)
        {
            button.onClick.AddListener(()=> CheckAnswer(button));
        }
    }
    public void OnClickQuitBtn()
    {
        questionPanel.SetActive(false);
    }
    void Start()
    {
        questionPanel.SetActive(false);
    }
    private void CheckAnswer(Button button)
    {
        if (button.CompareTag("CorrectAnswer"))
        {
            playerHealth.AddLife();
        }
        questionPanel.SetActive(false);
    }
}

    public List<Transform> bodyList = new List<Transform>();
    public GameObject bodyPrefab;
    public Sprite[] bodySprites = new Sprite[2];//数组中只含有2张图片
    private Transform canvas;
    private void Awake()
    {
        canvas = GameObject.Find("Canvas").transform;//找到Canvas的Transform
    }
    void BodyCreate()
    {
        //如果bodyList的元素数量是偶数,Index将被赋值为0。如果bodyList的元素数量是奇数,Index将被赋值为1
        int Index = (bodyList.Count % 2 == 0) ? 0 : 1;//bodyList.Count:列表中的元素数量(生成几种物体)
                                                      //bodyList.Count % 2:元素数量除以2,的余数
                                                      //bodyList.Count % 2 == 0:检查余数是否是0(是0,说明元素数量是偶数)
                                                      //? 0 : 1:如果元素数量是偶数(余数是0)则整个表达式的值是0。否则是1
        
        GameObject body = Instantiate(bodyPrefab,new Vector3(2000,2000,0),Quaternion.identity);//生成预制体在看不到的位置
        body.GetComponent<UnityImage>().sprite = bodySprites[Index];//从bodySprites数组中获取位于Index位置的图片
        body.transform.SetParent(canvas, false);//使Canvas成为body的父物体,而不使用它的世界坐标
        bodyList.Add(body.transform);
    }

ItemsBackground,ItemsText,TipText

九、暂存

1、隐藏按钮


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

public class ButtonHideObjectController : MonoBehaviour
{
    public GameObject objectToHide; // 在Inspector中设置这个引用

    void Start()
    {
        // 获取Button组件
        Button button = GetComponent<Button>();
        if (button != null)
        {
            // 添加点击事件监听器

            button.onClick.AddListener(HideObject);
            Debug.Log(button.interactable);
        }
    }

    // 点击按钮时调用的方法
    public void HideObject()
    {
        if (objectToHide != null)
        {
            objectToHide.SetActive(false); // 隐藏物体
            
        }
    }
}

2、含有构造函数的问题组成设置

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

[System.Serializable]
public class Question
{
    public string question; // 问题文本
    public string[] options = new string[4]; // 选项数组,假设每个问题都有4个选项
    public int correctOptionIndex; // 正确答案的索引(0表示A,1表示B,依此类推)

    // 构造函数(可选),用于初始化问题
    public Question(string q, string[] opts, int correctIndex)
    {
        question = q;
        options = opts;
        correctOptionIndex = correctIndex;
    }
    // 检查答案是否正确
    public bool CheckAnswer(int playerChoice)
    {
        return playerChoice == correctOptionIndex;
    }
}

3、题库脚本

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

public class Database_01 : MonoBehaviour
{
    public List<Question> questionsDatabase = new List<Question>(); // 选择题数据库

    void Start()
    {
        // 初始化选择题数据库
        InitializeQuestions();
    }

    void InitializeQuestions()
    {
        //添加一个问题到数据库
        questionsDatabase.Add(new Question(
            "生命系统最基本的结构层次是?",
            new string[] { "A. 细胞", "B. 组织", "C. 器官", "D. 系统" },
            0 // 假设"选项A"是正确答案,所以索引是0
        ));

        //添加一个问题到数据库
        questionsDatabase.Add(new Question(
            "细胞学说揭示了动物和植物的",
            new string[] { "A. 复杂性", "B. 多样性", "C. 统一性", "D. 稳定性" },
            2 // 假设"选项C"是正确答案,所以索引是2
        ));

    }
}

4、显示题目并判断对错

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

public class Exercises : MonoBehaviour
{
    public Database_01 Database_01;//题库脚本
    public TextMeshProUGUI questionText;
    public Button[] optionButtons;

    private int currentQuestionIndex = 0; // 初始化当前问题索引为0

    public void ShowQuestion(int index)
    {
        if (index >= 0 && index < Database_01.questionsDatabase.Count)//如果index在questionsDatabase列表的有效范围内
        {
            // 显示题目(从列表中取出索引为index的问题,并将其文本内容显示在questionText的文本组件上)
            questionText.text = Database_01.questionsDatabase[index].question;

            // 显示选项(将Database_01中当前问题的选项文本显示在optionButtons数组或列表中的相应UI元素上)
            for (int i = 0; i < Database_01.questionsDatabase[index].options.Length; i++)
            {
                optionButtons[i].GetComponentInChildren<TextMeshProUGUI>().text = Database_01.questionsDatabase[index].options[i];
            }
        }
    }
    // 选项按钮的点击事件
    public void OnOptionButtonClicked(int buttonIndex)
    {

        foreach (var button in optionButtons)
        {
            button.interactable = false; // 设置为false以禁用按钮
        }
        // currentQuestionIndex:当前显示的问题的索引
        // 检查用户选择的答案是否正确
        bool isCorrect = Database_01.questionsDatabase[currentQuestionIndex].CheckAnswer(buttonIndex);

        // 根据检查结果执行相应的操作,比如更新UI、显示消息等
        if (isCorrect)
        {
            Debug.Log("回答正确!");
            currentQuestionIndex++; // 更新当前问题索引
        }
        else
        {
            Debug.Log("回答错误!");
        }
    }
}

5、退出

using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameEnding : MonoBehaviour
{
    public float fadeDuration = 1f;
    public float displayImageDuration = 1f;
    public GameObject player;
    public CanvasGroup exitBackgroundImageCanvasGroup;
    public AudioSource exitAudio;
    public CanvasGroup caughtBackgroundImageCanvasGroup;
    public AudioSource caughtAudio;

    bool m_IsPlayerAtExit;
    bool m_IsPlayerCaught;
    float m_Timer;
    bool m_HasAudioPlayed;
    
    void OnTriggerEnter (Collider other)
    {
        if (other.gameObject == player)
        {
            m_IsPlayerAtExit = true;
        }
    }
    public void CaughtPlayer ()
    {
        m_IsPlayerCaught = true;
    }
    void Update ()
    {
        if (m_IsPlayerAtExit)
        {
            EndLevel (exitBackgroundImageCanvasGroup, false, exitAudio);
        }
        else if (m_IsPlayerCaught)
        {
            EndLevel (caughtBackgroundImageCanvasGroup, true, caughtAudio);
        }
    }
    void EndLevel (CanvasGroup imageCanvasGroup, bool doRestart, AudioSource audioSource)
    {
        if (!m_HasAudioPlayed)
        {
            audioSource.Play();
            m_HasAudioPlayed = true;
        }
            
        m_Timer += Time.deltaTime;
        imageCanvasGroup.alpha = m_Timer / fadeDuration;

        if (m_Timer > fadeDuration + displayImageDuration)
        {
            if (doRestart)
            {
                SceneManager.LoadScene (0);
            }
            else
            {
                Application.Quit ();
            }
        }
    }
}

6、获取物体

using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.UI;
using static UnityEngine.Rendering.DebugUI;

public class Observer : MonoBehaviour
{
    public Exercises exercises;
    public Transform player;
    public GameObject Questions;

    public TextMeshProUGUI ItemsText, TipText;
    static int nucleus=0, mitochondria = 0, GolgiApparatus = 0, endoplasmicReticulum = 0, ribosome = 0;

    bool canTriggerEffect = true;
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player")) // 玩家的标签为 "Player" 
        {
            exercises.ShowQuestion(0);
            RandomEvent(); 
        }
    }
    public void QuitBtn() 
    {
        GetComponent<UnityEngine.UI.Button>().gameObject.SetActive(false);
        Questions.SetActive(false);
    }
    void ItemsUpdate()
    {
        ItemsText.text =
            "当前持有:细胞核" + nucleus + ";线粒体" + mitochondria + ";高尔基体" + GolgiApparatus + ";内质网" + endoplasmicReticulum + ";核糖体" + ribosome;
    }
    void Start()
    {
        if (ItemsText == null || TipText == null)
        {
            Debug.LogError("ItemsText 或 TipText 未被正确分配!");
        }
    }
    void RandomEvent()
    {
        if (canTriggerEffect)
        {
            // 触发效果代码
            int numericValue = UnityEngine.Random.Range(0, 100);
            if (numericValue < 5 && nucleus == 0)//获取的随机数范围在0~4
            {
                nucleus = 1;
                TipText.text = "你发现了细胞核!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 21)
            {
                mitochondria++;
                TipText.text = "你得到了线粒体!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 41)
            {
                endoplasmicReticulum++;
                TipText.text = "你得到了内质网*1!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 61)
            {
                GolgiApparatus++;
                TipText.text = "你得到了高尔基体*1!";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 81)
            {
                ribosome++;
                TipText.text = "你得到了核糖体*1!"; 
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            else if (numericValue < 96)
            {
                Questions.SetActive(true);
            }
            else
            {
                TipText.text = "你什么都没有发现……";
                StartCoroutine(ClearTextRoutine(2f));
                print("随机数" + numericValue);
            }
            //gameEnding.CaughtPlayer ();
            ItemsUpdate();

            canTriggerEffect = false; // 触发效果,将canTriggerEffect设置为false
            StartCoroutine(CooldownRoutine()); // 启动冷却时间协程
        }
    }
    IEnumerator CooldownRoutine()
    {
        yield return new WaitForSeconds(60f); // 等待1分钟
        canTriggerEffect = true; // 冷却结束,可以再次触发效果
    }
    IEnumerator ClearTextRoutine(float delay)
    {
        yield return new WaitForSeconds(delay);
        TipText.text = "";
    }
}

7、

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1880983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享画布绘制矩形

简介 实现功能&#xff0c;在画布上绘制矩形&#xff0c;移动矩形。 在线演示 绘制矩形 实现代码 <!DOCTYPE html><html><head> <title>绘制矩形</title> </head><body><div style"margin: 10px"><input typ…

SpringBoot异常处理机制之自定义404、500错误提示页面 - 518篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

Redis持久化(RDB AOF)

Redis持久化 MySQL的事务&#xff0c;有四个比较核心的特性&#xff1a; 原子性一致性持久性&#xff08;和持久化一样&#xff09;&#xff0c;将数据存储在硬盘上&#xff0c;重启主机之后数据仍然存在隔离性 redis是一个内存数据库&#xff0c;把数据存储在内存中&#xff0…

基于SpringBoot的超市进销存系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 工具&#xff1a;MyEclipse、Tomcat 系统展示 首页 首页界面图 个人中心 个人中心…

Kafka~特殊技术细节设计:分区机制、重平衡机制、Leader选举机制、高水位HW机制

分区机制 Kafka 的分区机制是其实现高吞吐和可扩展性的重要特性之一。 Kafka 中的数据具有三层结构&#xff0c;即主题&#xff08;topic&#xff09;-> 分区&#xff08;partition&#xff09;-> 消息&#xff08;message&#xff09;。一个 Kafka 主题可以包含多个分…

【OpenREALM学习笔记:13】pose_estimation.cpp和pose_estimation.h

UML Class Diagram 图中红色框为头文件中所涉及到的函数、变量和结构体 核心函数 PoseEstimation::process() 其核心作用为执行位姿估计的处理流程&#xff0c;并返回是否在此循环中进行了任何处理。 在这个函数中判断并完成地理坐标的初始化或这地理坐标的更新。 这里需要…

【算法专题--栈】用队列实现栈 -- 高频面试题(图文详解,小白一看就懂!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐两个队列实现栈 &#x1f95d;解题思路 &#x1f34d;案例图解 ⭐用一个队列实现栈 &#x1f347;解题思路 &#x1f34d;案例图解 四、总结与提炼 五、共勉 一、前言 用队列实现栈 这道题&#xff0c;可以说是--栈…

springcloud第4季 分布式事务seata实现AT模式案例2【经典案例】

一 seata案例 1.1 背景说明 本案例使用seata的at模式&#xff0c;模拟分布式事务场景&#xff1a;【下订单&#xff0c;减库存&#xff0c;扣余额&#xff0c;改状态】 AT模式原理&#xff1a;是2pc方案的演变&#xff0c; 一阶段&#xff1a;业务数据和回滚日志记录在同一…

【MotionCap】conda 链接缺失的cuda库

conda 安装的环境不知道为啥python 环境里的 一些cuda库是空的要自己链接过去。ln 前面是已有的,后面是要新创建的 ln -s <path to the file/folder to be linked> cuda 有安装 libcublas 已经在cuda中 (base) zhangbin@ubuntu-server:~/miniconda3/envs/ai-mocap/lib/…

转让无区域商业管理公司基本流程和要求

无区域公司转让的条件和要求取决于您的业务需求和目标。我们的专业团队将与您合作&#xff0c;深入了解您的公司背景、行业情况和发展计划&#xff0c;为您量身定制适合您的转让方案。无论是公司规模、经营期限、资产状况还是法律形式&#xff0c;我们都将综合考虑确保达到您的…

学习C语言第一步:300行代码实现输出“Hello World“

学习所有语言的第一步几乎都是在控制台输出"Hello World",C语言也是如此&#xff0c;C语言支持结构化编程、词汇范围和递归等特性&#xff0c;C语言编写的代码在稍作修改或无需修改的情况下可以在多种不同的操作系统和平台上编译和运行&#xff0c;同时运行速度极快。…

如何为数据库中的位图添加动态水印

许多数据库存储了以blob或文件形式保存的位图&#xff0c;其中包括照片、文档扫描、医学图像等。当这些位图被各种数据库客户端和应用程序检索时&#xff0c;为了日后的识别和追踪&#xff0c;有时需要在检索时为它们添加唯一的水印。在某些情况下&#xff0c;人们甚至希望这些…

【数组】- 螺旋矩阵 II

1. 对应力扣题目连接 螺旋矩阵 II 题目简述&#xff1a; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。如图&#xff1a; 2. 实现案例代码 public class SpiralMatrix {public static…

网页搜索如何优化效果最好?

可以使用长尾关键词策略&#xff0c;长尾关键词策略是指在SEO优化中&#xff0c;除了使用常规的短关键词外&#xff0c;还深入挖掘和使用那些更长、更具体的关键词。虽然这些关键词的搜索量较低&#xff0c;但竞争也较少&#xff0c;且更具针对性&#xff0c;因此往往能带来更高…

我的世界服务器-高版本服务器-MC服务器-生存服务器-RPG服务器-幻世星辰

生存为主&#xff0c;RPG乐趣为辅&#xff0c;重视每位玩家的建议&#xff0c;一起打造心目中的服务器&#xff0c;与小伙伴一起探险我的世界&#xff01; 服务器版本: 1.18.2 ~ 1.20.4 Q群&#xff1a; 338238381 服务器官网: 星辰毛毛雨-Minecraft高版本生存服务器我的世界…

PMBOK® 第六版 结束项目或阶段

目录 读后感—PMBOK第六版 目录 不论是阶段的收尾还是项目整体的收尾&#xff0c;都应是令人振奋的事。然而&#xff0c;在实际生活中&#xff0c;收尾工作却相当艰难。会遭遇负责人调离、换任&#xff0c;导致不再需要已购产品&#xff1b;项目收尾时对照招标文件或合同&…

[AIGC] 深入了解标准与异常重定向输出

在操作系统和编程环境下&#xff0c;有时我们需要更加精细地控制程序的输入或输出过程&#xff0c;这就涉及到了标准输入输出流&#xff0c;以及重定向的概念。接下来&#xff0c;我们将详细介绍标准输出、标准错误输出&#xff0c;以及如何进行输出重定向。 文章目录 1. 标准输…

企业im(即时通讯)作为安全专属的移动数字化平台的重要工具

企业IM即时通讯作为安全专属的移动数字化平台的重要工具&#xff0c;正在越来越多的企业中发挥着重要的作用。随着移动技术和数字化转型的发展&#xff0c;企业对于安全、高效的内部沟通和协作工具的需求也越来越迫切。本文将探讨企业IM即时通讯作为安全专属的移动数字化平台的…

坏越的小世界的一些修改调整

留言区感觉不够高大上&#xff0c;功能也比较简单。我想了想还是仿照小红书设计一个。 先写个静态 这边想了想是将留言和评论各放一个表和首次加载的放在一个表好。想了想还是选择了后者 不过在sql上这样可能会很麻烦&#xff0c;还是建议分表&#xff0c;看下布局 每次展开会…

QT加载安装外围依赖库的翻译文件后翻译失败的现象分析:依赖库以饿汉式的形式暴露单例接口导致该现象的产生

1、前提说明 VS2019 QtClassLibaryDll是动态库,QtWidgetsApplication4是应用程序。 首先明确:动态库以饿汉式的形式进行单例接口暴露; 然后,应用程序加载动态库的翻译文件并进行全局安装; // ...QTranslator* trans = new QTranslator();//qDebug() << trans->…