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 GameObject TiMuPage; 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 TextMeshProUGUI selfText; // 显示已选文本 //结果页面 public GameObject ResultPage;//结果页面 public TextMeshProUGUI resultText; // 显示结果文本 public Button MoreOnceBtn;//再来一次 public Sprite[] AllColors; //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() { // 确保数组不为空 if (optionToggles == null || optionToggles.Count == 0) { Debug.LogError("请先初始化optionToggles数组!"); return; } // 遍历每个Toggle,添加事件 for (int i = 0; i < optionToggles.Count; i++) { // 保存当前索引(避免lambda闭包捕获的i值异常) int index = i; // 清除旧监听(关键:避免重复添加导致多次触发) optionToggles[i].onValueChanged.RemoveAllListeners(); // 添加新监听(使用lambda绑定回调,可传入索引和状态) optionToggles[i].onValueChanged.AddListener((isOn) => { // 调用处理方法(也可直接在这里写逻辑) OnToggleValueChanged(index, isOn); }); } // 加载问题 LoadQuestions(); ToStartQuestion(); // 初始化倒计时 //remainingTime = totalTime; //UpdateTimerUI(); } // 处理Toggle状态变化的回调方法 void OnToggleValueChanged(int toggleIndex, bool isOn) { if (isOn) { //Debug.Log($"Toggle {toggleIndex} 被选中了!"); // 选中时的逻辑(例如:切换选项、更新UI等) OnSubmitButtonClicked(); } } public void ToStartQuestion() { //结果和控制页面消失 ResultPage.SetActive(false); CtrlPage.SetActive(false); TiMuPage.SetActive(true); userAnswers.Clear(); // 初始化用户答案列表 for (int i = 0; i < questions.Count; i++) { userAnswers.Add(-1); } 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++) { optionToggles[i].transform.Find("Background").GetComponent().sprite = AllColors[0]; optionToggles[i].transform.Find("Background/Checkmark").GetComponent().sprite = AllColors[0]; 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 = false; // 判断题或单选题使用 ToggleGroup optionToggles[i].group = (question.IsSingleChoice || question.IsJudgment) ? optionsGroup : null; } else { optionToggles[i].gameObject.SetActive(false); } } } //选择结束后确认该题结果 public void OnSubmitButtonClicked() { // 提交答案 SaveUserAnswers(); //检查结果并显示 CheckCurrentAnswer(); } //保存用户答案 void SaveUserAnswers() { // 保存用户选择的答案 int index = 0; foreach (Toggle toggle in optionToggles) { if (toggle.isOn) { userAnswers[currentQuestionIndex]=index; } index++; } } //检查是否正确 void CheckCurrentAnswer() { // 检查用户答案是否为正确答案的子集 if (questions[currentQuestionIndex].CorrectAnswers==userAnswers[currentQuestionIndex]) { OnHintViewShow(true); } else { OnHintViewShow(false); } } //显示正确还是错误 public void OnHintViewShow(bool isTrue) { // 显示正确答案提示 Question question = questions[currentQuestionIndex]; string correctAnswerLetters = ConvertNumbersToLetters(question.CorrectAnswers); string nowAnswerLetters = ConvertNumbersToLetters(userAnswers[currentQuestionIndex]); //如果是单选题 if (question.IsSingleChoice) { hintText.text = $"{correctAnswerLetters}"; selfText.text = $"{nowAnswerLetters}"; } //如果是判断题 else if (question.IsJudgment) { if (correctAnswerLetters == "A") { hintText.text = "对"; if (isTrue) { selfText.text = "对"; } else { selfText.text = "错"; } } else { hintText.text = "错"; if (isTrue) { selfText.text = "错"; } else { selfText.text = "对"; } } } Debug.Log(userAnswers[currentQuestionIndex]+" "+ currentQuestionIndex + " " + questions[currentQuestionIndex].CorrectAnswers); if (isTrue) { selfText.color= hintText.color; optionToggles[userAnswers[currentQuestionIndex]].transform.Find("Background/Checkmark").GetComponent().sprite = AllColors[1]; } else { selfText.color = Color.red; optionToggles[userAnswers[currentQuestionIndex]].transform.Find("Background/Checkmark").GetComponent().sprite = AllColors[2]; optionToggles[questions[currentQuestionIndex].CorrectAnswers].transform.Find("Background").GetComponent().sprite = AllColors[1]; } CtrlPage.SetActive(true); } //下一题 public void OnNextButtonClicked() { // 切换到下一题 if (currentQuestionIndex < questions.Count - 1) { //SaveUserAnswers(); currentQuestionIndex++; DisplayQuestion(); //hintText.gameObject.SetActive(false); } //计算结果并进入结果页面 else { TiMuPage.SetActive(false); CheckAllAnswers(); } //控制页面消失 CtrlPage.SetActive(false); } //检查所有答案结果并显示结果页面 void CheckAllAnswers() { // 检查所有答案并计算正确率 int correctCount = 0; for (int i = 0; i < questions.Count; i++) { // 检查用户答案是否为正确答案的子集 if (questions[i].CorrectAnswers==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 > -1) { count++; } } return count; } string ConvertNumbersToLetters(int number) { // 将数字转换为字母 StringBuilder letters = new StringBuilder(); 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