using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Xml; using TMPro; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; using static System.Collections.Specialized.BitVector32; public class QuizSystem : MonoBehaviour { public static QuizSystem Instance; public string FileName; // UI元素 public TextMeshProUGUI questionText; // 显示问题文本 public ToggleGroup optionsGroup; // 选项组,用于单选题 public List optionToggles; // 选项切换按钮列表 public TextMeshProUGUI progressText; // 显示答题进度 public Button submitButton; // 提交按钮 //上一题下一题页面 public GameObject CtrlPage; public Button nextButton; // 下一题按钮 //public Button previousButton; // 上一题按钮 public TextMeshProUGUI hintText; // 显示提示文本 //结果页面 public GameObject ResultPage;//结果页面 public TextMeshProUGUI resultText; // 显示结果文本 public Button MoreOnceBtn;//再来一次 //public Button hintButton; // 提示按钮 //public Slider timeSlider; // 时间滑动条 //public TextMeshProUGUI timerText; // 倒计时文本 // 问题列表和当前状态 private List questions = new List(); // 问题列表 private int currentQuestionIndex = 0; // 当前问题索引 private List> userAnswers = new List>(); // 用户答案列表 //private bool isSubmitted = false; // 是否已提交 // 总体倒计时 //private float totalTime = 1800f; // 总时间(秒) //private float remainingTime; // 剩余时间 private void Awake() { Instance = this; } void Start() { // 加载问题 LoadQuestions(); ToStartQuestion(); // 初始化倒计时 //remainingTime = totalTime; //UpdateTimerUI(); } public void ToStartQuestion() { //结果和控制页面消失 ResultPage.SetActive(false); CtrlPage.SetActive(false); userAnswers.Clear(); // 初始化用户答案列表 for (int i = 0; i < questions.Count; i++) { userAnswers.Add(new HashSet()); } currentQuestionIndex = 0; // 显示第一个问题 DisplayQuestion(); } void Update() { //// 更新倒计时 //if (remainingTime > 0) //{ // remainingTime -= Time.deltaTime; // UpdateTimerUI(); //} //else if (!isSubmitted) //{ // // 时间到,自动提交 // OnSubmitButtonClicked(); //} } void LoadQuestions() { questions = XmlTextReaderTest(); } void DisplayQuestion() { // 检查是否超出问题列表 if (currentQuestionIndex >= questions.Count) { return; } // 获取当前问题 Question question = questions[currentQuestionIndex]; questionText.text = question.Text; progressText.text = $"答题进度: {GetAnsweredCount()+1} / {questions.Count}"; // 显示选项 for (int i = 0; i < optionToggles.Count; i++) { if (i < question.Options.Length && (!question.IsJudgment || i < 2)) { optionToggles[i].gameObject.SetActive(true); var label = optionToggles[i].GetComponentInChildren(); if (label != null) { string sign = "A:"; switch (i) { case 0: sign = "A:"; break; case 1: sign = "B:"; break; case 2: sign = "C:"; break; case 3: sign = "D:"; break; } label.text = sign+question.Options[i]; } optionToggles[i].isOn = userAnswers[currentQuestionIndex].Contains(i + 1); // 判断题或单选题使用 ToggleGroup optionToggles[i].group = (question.IsSingleChoice || question.IsJudgment) ? optionsGroup : null; } else { optionToggles[i].gameObject.SetActive(false); } } } //选择结束后确认该题结果 public void OnSubmitButtonClicked() { // 提交答案 SaveUserAnswers(); //检查结果并显示 CheckCurrentAnswer(); } //保存用户答案 void SaveUserAnswers() { // 保存用户选择的答案 userAnswers[currentQuestionIndex].Clear(); int index = 0; foreach (Toggle toggle in optionToggles) { if (toggle.isOn) { userAnswers[currentQuestionIndex].Add(index); } index++; } } //检查是否正确 void CheckCurrentAnswer() { // 检查用户答案是否为正确答案的子集 if (questions[currentQuestionIndex].CorrectAnswers.IsSubsetOf(userAnswers[currentQuestionIndex])) { OnHintViewShow("正确"); } else { OnHintViewShow("错误"); } } //显示正确还是错误 public void OnHintViewShow(string result) { // 显示正确答案提示 Question question = questions[currentQuestionIndex]; string correctAnswerLetters = ConvertNumbersToLetters(question.CorrectAnswers); hintText.text = $"回答{result},答案为: {correctAnswerLetters}"; CtrlPage.SetActive(true); } //下一题 public void OnNextButtonClicked() { // 切换到下一题 if (currentQuestionIndex < questions.Count - 1) { //SaveUserAnswers(); currentQuestionIndex++; DisplayQuestion(); //hintText.gameObject.SetActive(false); } //计算结果并进入结果页面 else { CheckAllAnswers(); } //控制页面消失 CtrlPage.SetActive(false); } //检查所有答案结果并显示结果页面 void CheckAllAnswers() { // 检查所有答案并计算正确率 int correctCount = 0; for (int i = 0; i < questions.Count; i++) { // 检查用户答案是否为正确答案的子集 if (questions[i].CorrectAnswers.IsSubsetOf(userAnswers[i])) { correctCount++; } } resultText.text = $"正确率: {(float)correctCount / questions.Count * 100:F2}%"; ResultPage.SetActive(true); } //再来一遍 public void OnMoreDoOnce() { ToStartQuestion(); } //上一题 public void OnPreviousButtonClicked() { // 切换到上一题 if (currentQuestionIndex > 0) { SaveUserAnswers(); currentQuestionIndex--; DisplayQuestion(); //isSubmitted = false; // 重置提交状态 hintText.gameObject.SetActive(false); } } void UpdateTimerUI() { //// 更新滑动条和倒计时文本 //if (!isSubmitted) // 仅在未提交时更新 //{ // timeSlider.value = remainingTime / totalTime; // timerText.text = $"剩余时间: {Mathf.Ceil(remainingTime)}秒"; //} } //void LockSliderPosition() //{ // // 禁用滑块交互 // timeSlider.interactable = false; //} //void StopTimer() //{ // // 停止倒计时并更新文本 // timerText.text = $"本次用时:{totalTime - remainingTime:F0}s"; // timeSlider.value = 0; // 停止滑动条 //} int GetAnsweredCount() { // 获取已回答的问题数量 int count = 0; foreach (var answer in userAnswers) { if (answer.Count > 0) { count++; } } return count; } string ConvertNumbersToLetters(HashSet numbers) { // 将数字转换为字母 StringBuilder letters = new StringBuilder(); foreach (int number in numbers) { if (number >= 0 && number <= 3) { char letter = (char)('A' + number); letters.Append(letter); } } return letters.ToString(); } private List XmlTextReaderTest() { List questions = new List(); // 构建文件路径 string filePath = Path.Combine(Application.streamingAssetsPath, FileName+".xml"); if (!File.Exists(filePath)) { Debug.LogError("Questions file not found at: " + filePath); return questions; } string textmsg = File.ReadAllText(filePath); XmlDocument xmlDocument = new XmlDocument(); try { xmlDocument.LoadXml(textmsg); } catch (XmlException e) { Debug.LogError($"XML格式错误:{e.Message}"); return questions; } XmlNode rootNode = xmlDocument.SelectSingleNode("root"); if (rootNode == null) { Debug.LogError("XML中未找到节点"); return questions; } //遍历所有子节点 XmlNodeList questionNodes = rootNode.SelectNodes("question"); if (questionNodes == null || questionNodes.Count == 0) { Debug.LogWarning("未找到任何节点"); return questions; } // 提取每个question的属性值 foreach (XmlNode node in questionNodes) { Question question = new Question(); // 读取id属性(转换为int) if (!TryGetIntAttribute(node, "id", out int id)) { Debug.LogWarning("跳过无效的question节点(缺少id或格式错误)"); continue; } // 读取quesTitle属性(字符串) if (!TryGetStringAttribute(node, "quesTitle", out string title)) { Debug.LogWarning($"id为{id}的节点缺少quesTitle属性"); continue; } string[] allMsg = title.Split('|'); question.Text = allMsg[0]; if (allMsg.Length > 1) { question.Options=new string[allMsg.Length-1]; for (int i = 1;i(Array.ConvertAll(answer.ToCharArray(), c => int.Parse(c.ToString()))); // 读取type属性(转换为int) if (!TryGetIntAttribute(node, "type", out int type)) { Debug.LogWarning($"id为{id}的节点type格式错误"); continue; } question.IsSingleChoice = type == 1; question.IsJudgment = type == 0;// 判断题标识 // 添加到列表 questions.Add(question); } return questions; } // 辅助方法:获取节点的字符串属性 private bool TryGetStringAttribute(XmlNode node, string attrName, out string value) { XmlAttribute attr = node.Attributes[attrName]; if (attr != null) { value = attr.Value; return true; } value = null; return false; } // 辅助方法:获取节点的int属性(并验证格式) private bool TryGetIntAttribute(XmlNode node, string attrName, out int value) { if (TryGetStringAttribute(node, attrName, out string strValue)) { return int.TryParse(strValue, out value); } value = 0; return false; } } public class Question { public string Text; // 问题文本 public string[] Options; // 选项数组 public bool IsSingleChoice; // 是否为单选题 public HashSet CorrectAnswers; // 正确答案集合 public bool IsJudgment; // 是否为判断题 }