killapp/Assets/Scripts/UI/Pages/Safetylearning/SafetylearningTestPage.cs

299 lines
8.3 KiB
C#
Raw Normal View History

2026-04-24 16:57:44 +08:00
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
{
2026-05-18 08:42:33 +08:00
CreateAnswerExplanation();
2026-04-24 16:57:44 +08:00
// 答错:清空队列,重新生成
RegenerateQueue();
// 显示解析和下一题按钮
2026-05-18 08:42:33 +08:00
2026-04-24 16:57:44 +08:00
nextButton.gameObject.SetActive(true);
// 重置索引,确保点击下一题从第一题开始
currentQuestionIndex = -1;
}
}
/// <summary>
/// 延迟下一题
/// </summary>
private IEnumerator DelayNextQuestion()
{
2026-05-18 08:42:33 +08:00
yield return new WaitForSeconds(1f);
2026-04-24 16:57:44 +08:00
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;
}
}
}