killapp/Assets/Scripts/UI/Pages/Safetylearning/SafetylearningTestPage.cs
2026-04-24 16:57:44 +08:00

298 lines
8.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Kill.Managers;
using Kill.UI.Pages;
using UnityEngine;
using UnityEngine.UI;
public class SafetylearningTestPage : MonoBehaviour
{
public Transform questionContainer;
public GameObject questionPrefab;
public Button nextButton;
public Button submitButton;
public GameObject answerPrefab;
public List<GameObject> sonObjs;
// 题库所有未答对2次的题目
private List<QuestionInfo> questionBank = new List<QuestionInfo>();
// 答题队列(当前答题顺序)
public List<QuestionInfo> questionQueue = new List<QuestionInfo>();
// 答题记录(记录每道题答对次数)
private Dictionary<int, int> correctCountMap = new Dictionary<int, int>();
private int currentQuestionIndex = 0;
private int totalAnsweredCount = 0;
private SafetylearningQuestion currentQuestion;
private GameObject currentAnswerObj;
public void Init(List<QuestionInfo> questions)
{
// 初始化题库
questionBank = new List<QuestionInfo>(questions);
correctCountMap.Clear();
totalAnsweredCount = 0;
// 初始化答题队列(按顺序)
InitializeQueue();
// 显示第一题
ShowQuestion(0);
}
/// <summary>
/// 初始化答题队列(按顺序)
/// </summary>
private void InitializeQueue()
{
questionQueue.Clear();
// 按顺序将题库中所有题目加入队列
foreach (var question in questionBank)
{
questionQueue.Add(question);
}
currentQuestionIndex = 0;
Debug.Log($"初始化答题队列,共 {questionQueue.Count} 道题");
}
/// <summary>
/// 重新生成队列(答错时调用)
/// 清空队列,将题库中所有题目打乱顺序生成新队列
/// </summary>
private void RegenerateQueue()
{
questionQueue.Clear();
// 将题库中所有题目加入队列
foreach (var question in questionBank)
{
questionQueue.Add(question);
}
// 打乱队列
ShuffleList(questionQueue);
currentQuestionIndex = 0;
Debug.Log($"重新生成答题队列,共 {questionQueue.Count} 道题");
}
/// <summary>
/// 从题库中移除题目答对2次时调用
/// </summary>
private void RemoveFromBank(int questionId)
{
var question = questionBank.Find(q => q.id == questionId);
if (question != null)
{
questionBank.Remove(question);
Debug.Log($"题目 {questionId} 已从题库中移除");
}
}
/// <summary>
/// Fisher-Yates 洗牌算法
/// </summary>
private void ShuffleList<T>(List<T> list)
{
System.Random rng = new System.Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
/// <summary>
/// 显示指定题目
/// </summary>
private void ShowQuestion(int index)
{
// 检查队列是否为空,为空则通过
if (questionQueue.Count == 0)
{
Debug.Log("答题队列已空,通过!");
// 显示完成页面
SafetylearningPageCtrl.Instance?.ShowFinishPage();
return;
}
// 清除旧题目和解析
ClearCurrentQuestion();
currentQuestionIndex = index;
// 如果超出范围,从第一题开始
if (currentQuestionIndex >= questionQueue.Count)
{
currentQuestionIndex = 0;
}
// 创建新题目
GameObject questionObj = Instantiate(questionPrefab, questionContainer);
sonObjs.Add(questionObj);
currentQuestion = questionObj.GetComponent<SafetylearningQuestion>();
// 使用总答题序号作为题号(累加)
totalAnsweredCount++;
currentQuestion.Init(totalAnsweredCount, questionQueue[currentQuestionIndex]);
// 订阅选项选择事件
currentQuestion.OnOptionSelected += OnOptionSelected;
// 初始状态:隐藏提交和下一题按钮
submitButton.gameObject.SetActive(false);
nextButton.gameObject.SetActive(false);
// 绑定按钮事件
submitButton.onClick.RemoveAllListeners();
submitButton.onClick.AddListener(OnSubmitClick);
nextButton.onClick.RemoveAllListeners();
nextButton.onClick.AddListener(OnNextClick);
}
/// <summary>
/// 选项被选择
/// </summary>
private void OnOptionSelected()
{
// 有选择时显示提交按钮
if (currentQuestion != null && currentQuestion.HasSelectedAnswer())
{
submitButton.gameObject.SetActive(true);
}
}
/// <summary>
/// 提交答案
/// </summary>
private void OnSubmitClick()
{
if (currentQuestion == null) return;
// 禁用选项交互
currentQuestion.DisableAllOptions();
submitButton.gameObject.SetActive(false);
// 显示答案判断
currentQuestion.CheckAnswer();
// 判断是否正确
string userAnswer = currentQuestion.GetUserAnswer();
string correctAnswer = questionQueue[currentQuestionIndex].correctAnswer;
bool isCorrect = userAnswer == correctAnswer;
// 获取当前题目ID
int currentQuestionId = questionQueue[currentQuestionIndex].id;
if (isCorrect)
{
// 更新答对次数
if (!correctCountMap.ContainsKey(currentQuestionId))
{
correctCountMap[currentQuestionId] = 0;
}
correctCountMap[currentQuestionId]++;
// 检查是否答对2次
if (correctCountMap[currentQuestionId] >= 2)
{
// 从题库中移除
RemoveFromBank(currentQuestionId);
}
// 从队列中移除当前题目
questionQueue.RemoveAt(currentQuestionIndex);
// 索引保持不变,因为移除后后面的题目会前移
// 2秒后自动下一题
StartCoroutine(DelayNextQuestion());
}
else
{
// 答错:清空队列,重新生成
RegenerateQueue();
// 显示解析和下一题按钮
CreateAnswerExplanation();
nextButton.gameObject.SetActive(true);
// 重置索引,确保点击下一题从第一题开始
currentQuestionIndex = -1;
}
}
/// <summary>
/// 延迟下一题
/// </summary>
private IEnumerator DelayNextQuestion()
{
yield return new WaitForSeconds(2f);
ShowQuestion(currentQuestionIndex);
}
/// <summary>
/// 创建答案解析
/// </summary>
private void CreateAnswerExplanation()
{
if (answerPrefab == null) return;
currentAnswerObj = Instantiate(answerPrefab, questionContainer);
sonObjs.Add(currentAnswerObj);
currentAnswerObj.GetComponent<SafetylearningAnswer>().Init(
questionQueue[currentQuestionIndex].options,
questionQueue[currentQuestionIndex].videoUrl
);
}
/// <summary>
/// 下一题
/// </summary>
private void OnNextClick()
{
currentQuestionIndex++;
ShowQuestion(currentQuestionIndex);
}
/// <summary>
/// 清除当前题目和解析
/// </summary>
private void ClearCurrentQuestion()
{
// 取消订阅事件
if (currentQuestion != null)
{
currentQuestion.OnOptionSelected -= OnOptionSelected;
}
// 销毁所有子对象
foreach (var obj in sonObjs)
{
if (obj != null)
Destroy(obj);
}
sonObjs.Clear();
currentQuestion = null;
currentAnswerObj = null;
}
void OnDestroy()
{
submitButton?.onClick.RemoveAllListeners();
nextButton?.onClick.RemoveAllListeners();
if (currentQuestion != null)
{
currentQuestion.OnOptionSelected -= OnOptionSelected;
}
}
}