using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ExamFlowManager : MonoBehaviour { private const int StepCount = 7; private readonly int[] _stepScores = { 6, 22, 11, 11, 11, 22, 17 }; private readonly bool[] _answered = new bool[StepCount]; private readonly bool[] _correct = new bool[StepCount]; private readonly int[] _earned = new int[StepCount]; private readonly string[] _feedback = new string[StepCount]; private readonly HashSet _placedPings = new HashSet(); private readonly HashSet _wrappedPings = new HashSet(); private Transform _dialogueBubble; private GameObject _gradeResult; private GameObject _endPanel; private Button _dialogueYesButton; private Button _dialogueBackButton; private Text _gradeContent; private Text _gradeScoreText; private int _currentStep; private bool _examActive; private bool _waitingForPoint2; private bool _waitingForShose; private bool _waitingForWrapClicks; private void Awake() { AutoBind(); } private void Start() { AutoBind(); BindButtons(); EnsureToggleGroups(); HideAllPanels(); } private void Update() { bool shouldRun = GameManager.Instance != null && GameManager.Instance.CurrentMode == ExperimentMode.Exam && GameManager.Instance.CurrentFixationMethod == FixationMethod.LimbFixation && IsExperimentPageVisible(); if (!shouldRun && _examActive) { ResetExamState(false); } } public void BeginExam() { if (GameManager.Instance == null || GameManager.Instance.CurrentMode != ExperimentMode.Exam || GameManager.Instance.CurrentFixationMethod != FixationMethod.LimbFixation || !IsExperimentPageVisible()) { ResetExamState(false); return; } AutoBind(); BindButtons(); EnsureToggleGroups(); ResetExamState(true); _examActive = true; _waitingForPoint2 = true; if (GameManager.Instance != null) { GameManager.Instance.InitExamRecord(StepCount); } ForceHideExamOnlyOutlines(); MoveWomanToExamPoint(); ShowStep(1); Debug.Log("[ExamFlow] 考核模式流程启动"); } public void StopExam() { ResetExamState(false); } public void ShowStep(int stepNumber) { AutoBind(); _currentStep = Mathf.Clamp(stepNumber, 1, StepCount); if (_dialogueBubble == null) return; _dialogueBubble.gameObject.SetActive(true); EnsureStepPanelsDoNotBlockButtons(); for (int i = 0; i < _dialogueBubble.childCount; i++) { Transform child = _dialogueBubble.GetChild(i); if (child.name.StartsWith("step")) { child.gameObject.SetActive(child.name == "step" + _currentStep); } } ApplyStepText(_currentStep); if (_currentStep == 3 || _currentStep == 7) { ResetStepToggles(_currentStep); } Debug.Log("[ExamFlow] 显示 step" + _currentStep); } public void OnObjectClicked(Component clicked) { if (!_examActive || clicked == null) return; if (clicked is Point2ClickHandler) { if (_waitingForPoint2 && clicked.name == "point2") { _waitingForPoint2 = false; RecordStep(1, true, "已按要求完成前置操作起始步骤。"); StartCoroutine(ShowStepDelayed(2, 1f)); } return; } if (clicked is ShoseClickHandler) { if (_waitingForShose || _currentStep <= 2) { _waitingForShose = false; RecordStep(2, true, "已完成下肢固定前置处理。"); StartCoroutine(ShowStepDelayed(3, 1f)); } return; } var ping = clicked as PingClickHandler; if (ping != null) { bool isWrapClick = ping.chanraoObject != null && ping.chanraoObject.activeSelf; if (isWrapClick) { _wrappedPings.Add(ping.name); Debug.Log("[ExamFlow] 系带点击 " + _wrappedPings.Count + "/4: " + ping.name); if (_waitingForWrapClicks && _wrappedPings.Count >= 4) { _waitingForWrapClicks = false; RecordStep(5, true, "已按由远端到近端的顺序完成系带。"); ShowStep(6); } } else { _placedPings.Add(ping.name); Debug.Log("[ExamFlow] 放带点击 " + _placedPings.Count + "/4: " + ping.name); } return; } if (clicked is ChanraoTuibuHandler) { if (!_answered[3]) { RecordStep(4, _placedPings.Count >= 4, _placedPings.Count >= 4 ? "已按要求完成四条绑带摆放。" : "绑带尚未全部摆放完成。"); } _waitingForWrapClicks = true; ShowStep(5); } } private IEnumerator ShowStepDelayed(int stepNumber, float delay) { yield return new WaitForSeconds(delay); ShowStep(stepNumber); } private void OnDialogueYesClicked() { if (!_examActive) { HideDialogue(); return; } switch (_currentStep) { case 1: HideDialogue(); _waitingForPoint2 = true; break; case 2: HideDialogue(); _waitingForShose = true; break; case 3: RecordStep(3, GetSelectedToggleIndex(3) == 1, "正确答案:10cm。"); ShowStep(4); ActivateFirstPing(); break; case 4: HideDialogue(); break; case 5: HideDialogue(); _waitingForWrapClicks = true; break; case 6: RecordStep(6, false, "错误操作:在受伤腿一侧打结。正确做法是在未受伤腿位置打结。"); ShowStep(7); break; case 7: RecordStep(7, GetSelectedToggleIndex(7) == 1, "正确答案:足背。"); ShowGradeResult(); break; default: HideDialogue(); break; } } private void ShowGradeResult() { AutoBind(); BindResultButtons(); BindEndPanelButtons(); HideDialogue(); int totalScore; string gradeContent = BuildGradeContent(out totalScore); if (_gradeResult != null) _gradeResult.SetActive(true); if (_gradeContent != null) _gradeContent.text = gradeContent; if (_gradeScoreText != null) _gradeScoreText.text = totalScore.ToString(); } private string BuildGradeContent(out int total) { total = 0; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("考核结果汇总"); sb.AppendLine(); for (int i = 0; i < StepCount; i++) { total += _earned[i]; bool answered = _answered[i]; bool correct = answered && _correct[i]; sb.AppendFormat("考核点{0}({1}分):{2}", i + 1, _stepScores[i], correct ? "正确" : "错误"); if (!answered) sb.Append("(未完成)"); sb.AppendLine(); sb.AppendLine("题目:" + GetQuestionText(i + 1)); sb.AppendLine("答案:" + GetAnswerText(i + 1)); sb.AppendFormat("得分:{0}/{1}", _earned[i], _stepScores[i]); sb.AppendLine(); if (!string.IsNullOrEmpty(_feedback[i]) && (!correct || i == 5)) { sb.AppendLine("说明:" + _feedback[i]); } sb.AppendLine(); } sb.AppendFormat("最终得分:{0}/100", total); return sb.ToString(); } private void RecordStep(int oneBasedStep, bool isCorrect, string feedback) { int index = oneBasedStep - 1; if (index < 0 || index >= StepCount || _answered[index]) return; _answered[index] = true; _correct[index] = isCorrect; _earned[index] = isCorrect ? _stepScores[index] : 0; _feedback[index] = feedback; if (GameManager.Instance != null) { GameManager.Instance.RecordExamResult(index, _stepScores[index], isCorrect ? 1f : 0f, feedback); } } private void ActivateFirstPing() { GameObject firstPing = FindSceneObject("ping.004"); if (firstPing == null) { foreach (var ping in Resources.FindObjectsOfTypeAll()) { if (ping != null && ping.gameObject.scene.IsValid() && ping.pingIndex == 0) { firstPing = ping.gameObject; break; } } } if (firstPing != null) { firstPing.SetActive(true); var handler = firstPing.GetComponent(); if (handler != null) handler.ResetState(true); } } private void AutoBind() { Transform canvas = FindSceneObject("Canvas")?.transform; if (canvas == null) return; if (_dialogueBubble == null) _dialogueBubble = canvas.Find("DialogueBubble"); if (_gradeResult == null) { Transform t = canvas.Find("GradeResult"); if (t != null) _gradeResult = t.gameObject; } if (_endPanel == null) { Transform t = canvas.Find("EndPanel"); if (t != null) _endPanel = t.gameObject; } if (_dialogueBubble != null) { _dialogueYesButton = _dialogueBubble.Find("BtnYes")?.GetComponent