using UnityEngine; using UnityEngine.UI; using TMPro; /// /// UI 中央调度器:引用所有子面板,绑定 StepManager 事件。 /// 挂在 Canvas GameObject 上。 /// public class UIManager : MonoBehaviour { [Header("管理器引用")] [SerializeField] private StepManager _stepManager; [SerializeField] private InteractionSystem _interactionSystem; [Header("=== 顶部提示栏 ===")] [SerializeField] private GameObject _tipPanel; [SerializeField] private TMP_Text _tipText; [Header("=== 详细操作说明(甲方补充 - 学习模式) ===")] [SerializeField] private GameObject _detailPanel; [SerializeField] private TMP_Text _detailText; [Header("=== 对话气泡 ===")] [SerializeField] private GameObject _dialogueBubble; [SerializeField] private TMP_Text _dialogueText; [Header("=== 画中画视频 ===")] [SerializeField] private VideoController _videoController; [Header("=== 右侧功能按钮 ===")] [SerializeField] private Button _btnFullScreen; [SerializeField] private Button _btnPrevious; [SerializeField] private Button _btnNext; [SerializeField] private Button _btnSwitchMode; [SerializeField] private Button _btnReturn; [SerializeField] private TMP_Text _btnSwitchModeLabel; [Header("=== 底部进度条 ===")] [SerializeField] private Slider _progressBar; [SerializeField] private TMP_Text _progressText; [Header("=== 弹窗 ===")] [SerializeField] private ExamPopup _examPopup; [SerializeField] private ScoreDisplay _scoreDisplay; [Header("=== 底部主菜单图标 ===")] [SerializeField] private Button _btnCPR; [SerializeField] private Button _btnFracture; [SerializeField] private Button _btnSprain; [SerializeField] private Button _btnBleeding; [SerializeField] private Button _btnTransport; [Header("=== 固定方式选择(仅骨折固定) ===")] [SerializeField] private GameObject _fixationPanel; [SerializeField] private Button _btnLimbFixation; [SerializeField] private Button _btnSplintFixation; private void Start() { BindEvents(); BindButtons(); } #region 事件绑定 private void BindEvents() { if (_stepManager == null) return; _stepManager.OnStepChanged.AddListener(OnStepChanged); _stepManager.OnTipChanged.AddListener(UpdateTip); _stepManager.OnDialogueChanged.AddListener(UpdateDialogue); _stepManager.OnDetailedContent.AddListener(UpdateDetailContent); _stepManager.OnExamPopup.AddListener(ShowExamPopup); _stepManager.OnExperimentComplete.AddListener(OnExperimentComplete); _stepManager.OnVideoToggle.AddListener(ToggleVideo); } private void BindButtons() { _btnFullScreen?.onClick.AddListener(ToggleFullScreen); _btnPrevious?.onClick.AddListener(OnPreviousClicked); _btnNext?.onClick.AddListener(OnNextClicked); _btnSwitchMode?.onClick.AddListener(OnSwitchModeClicked); _btnReturn?.onClick.AddListener(OnReturnClicked); _btnLimbFixation?.onClick.AddListener(() => _stepManager?.SwitchFixation(FixationMethod.LimbFixation)); _btnSplintFixation?.onClick.AddListener(() => _stepManager?.SwitchFixation(FixationMethod.SplintFixation)); } #endregion #region UI 更新回调 private void OnStepChanged(int index) { UpdateProgressBar(); UpdateNavigationButtons(); } private void UpdateTip(string text) { if (_tipPanel != null) _tipPanel.SetActive(!string.IsNullOrEmpty(text)); if (_tipText != null) _tipText.text = text; } private void UpdateDialogue(string text) { if (_dialogueBubble != null) _dialogueBubble.SetActive(!string.IsNullOrEmpty(text)); if (_dialogueText != null) _dialogueText.text = text; } private void UpdateDetailContent(string text) { if (_detailPanel != null) _detailPanel.SetActive(!string.IsNullOrEmpty(text)); if (_detailText != null) _detailText.text = text; } private void ToggleVideo(string fileName, bool active) { if (_videoController == null) return; if (active && !string.IsNullOrEmpty(fileName)) _videoController.PlayVideo(fileName); else _videoController.StopVideo(); } private void UpdateProgressBar() { if (_stepManager == null) return; int cur = _stepManager.CurrentStepIndex + 1; int total = _stepManager.TotalSteps; if (_progressBar != null) _progressBar.value = (float)cur / total; if (_progressText != null) _progressText.text = $"{cur}/{total}"; } private void UpdateNavigationButtons() { if (_stepManager == null) return; _btnPrevious.interactable = _stepManager.CurrentStepIndex > 0; bool isLast = _stepManager.CurrentStepIndex >= _stepManager.TotalSteps - 1; if (_btnNext != null) { var label = _btnNext.GetComponentInChildren(); if (label != null) label.text = isLast ? "完成" : "下一步"; } } #endregion #region 考核弹窗 private void ShowExamPopup(StepData step) { if (_examPopup == null) return; _examPopup.Show(step, OnExamAnswer); } private void OnExamAnswer(float proportion, string feedback) { _stepManager?.OnStepInteractionComplete(proportion, feedback); _stepManager?.NextStep(); } #endregion #region 实验完成 private void OnExperimentComplete() { var gm = GameManager.Instance; if (gm == null) return; if (gm.CurrentMode == ExperimentMode.Exam) { _scoreDisplay?.ShowExamScore(); } else { _scoreDisplay?.ShowNotesOnly(); } } #endregion #region 按钮回调 private void ToggleFullScreen() { Screen.fullScreen = !Screen.fullScreen; } private void OnPreviousClicked() { _stepManager?.PreviousStep(); } private void OnNextClicked() { if (_stepManager.Mode == ExperimentMode.Exam) { var step = _stepManager.GetCurrentStep(); if (step != null && step.CompleteType != StepCompleteType.MultipleChoice) _stepManager.OnStepInteractionComplete(1f); } _stepManager.NextStep(); } private void OnSwitchModeClicked() { var newMode = _stepManager.Mode == ExperimentMode.Learn ? ExperimentMode.Exam : ExperimentMode.Learn; _stepManager.SwitchMode(newMode); } private void OnReturnClicked() { UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu"); } #endregion }