Files
VFSUnity/Assets/Scripts/UI/PageController.cs
T
2026-07-12 20:34:49 +08:00

516 lines
19 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 UnityEngine;
using UnityEngine.UI;
public class PageController : MonoBehaviour
{
[Header("=== 三个主页面 ===")]
[SerializeField] private GameObject _homePagePanel;
[SerializeField] private GameObject _modeSelectPanel;
[SerializeField] private GameObject _fixationPanel;
[Header("=== 实验页面 ===")]
[SerializeField] private GameObject _experimentPanel;
[SerializeField] private Button _btnExperimentBack;
[Header("=== 实验内 UI(由 UIManager 管理)===")]
[SerializeField] private UIManager _uiManager;
[Header("=== 首页控件 ===")]
[SerializeField] private Button _btnStart;
[SerializeField] private Button _btnExit;
[Header("=== 模式选择页控件 ===")]
[SerializeField] private Button _btnBack;
[SerializeField] private Button _btnPracticeMode;
[SerializeField] private Button _btnExamMode;
[SerializeField] private Text _modeDescText;
[Header("=== 固定方式选择页控件 ===")]
[SerializeField] private Button _btnFixationBack;
[SerializeField] private Button _btnLimbFixation;
[SerializeField] private Button _btnSplintFixation;
[Header("=== 模式说明文案 ===")]
[SerializeField] [TextArea(2, 4)] private string _practiceModeDesc =
"模拟练习模式:不限时长,可反复练习。系统不评分,帮助您熟悉实验流程和操作步骤。";
[SerializeField] [TextArea(2, 4)] private string _examModeDesc =
"考核评估模式:限定时间,完成后系统自动评分,并提供详细反馈报告。";
[Header("=== 编辑器预览(仅 Editor 模式有效)===")]
[SerializeField] private EditorPreviewPage _editorPreview = EditorPreviewPage.None;
public enum Page { Home, ModeSelect, Fixation, Experiment }
public enum EditorPreviewPage { None, Home, ModeSelect, Fixation, Experiment }
private Page _currentPage = Page.Home;
private ExperimentMode _selectedMode = ExperimentMode.Learn;
private int _lastReturnHomeFrame = -1;
private void Start()
{
Debug.Log("=== PageController 初始化开始 ===");
// 一开始就隐藏鞋子,以免在主页或开场动画时穿帮
HideShose();
// 关掉多余AudioListener(只留Main Camera的)
var cam2 = GameObject.Find("camera2"); if (cam2 != null) { var al = cam2.GetComponent<AudioListener>(); if (al != null) al.enabled = false; }
var cam3 = GameObject.Find("camera3"); if (cam3 != null) { var al = cam3.GetComponent<AudioListener>(); if (al != null) al.enabled = false; }
AutoAssignButtonsByName();
// 绑定首页按钮
if (_btnStart != null) { _btnStart.onClick.RemoveAllListeners(); _btnStart.onClick.AddListener(OnStartClicked); Debug.Log("PageController: _btnStart 绑定成功"); }
else Debug.LogError("PageController: _btnStart 未赋值!");
if (_btnExit != null) { _btnExit.onClick.RemoveAllListeners(); _btnExit.onClick.AddListener(OnExitClicked); Debug.Log("PageController: _btnExit 绑定成功"); }
else Debug.LogError("PageController: _btnExit 未赋值!");
if (_btnBack != null) { _btnBack.onClick.RemoveAllListeners(); _btnBack.onClick.AddListener(OnModeBackClicked); Debug.Log("PageController: _btnBack 绑定成功"); }
else Debug.LogError("PageController: _btnBack 未赋值!");
if (_btnPracticeMode != null) { _btnPracticeMode.onClick.RemoveAllListeners(); _btnPracticeMode.onClick.AddListener(() => OnModeSelected(ExperimentMode.Learn)); Debug.Log("PageController: _btnPracticeMode 绑定成功"); }
else Debug.LogError("PageController: _btnPracticeMode 未赋值!");
if (_btnExamMode != null) { _btnExamMode.onClick.RemoveAllListeners(); _btnExamMode.onClick.AddListener(() => OnModeSelected(ExperimentMode.Exam)); Debug.Log("PageController: _btnExamMode 绑定成功"); }
else Debug.LogError("PageController: _btnExamMode 未赋值!");
if (_btnFixationBack == null && _fixationPanel != null) { var fb = _fixationPanel.transform.Find("BtnBack"); if (fb != null) { _btnFixationBack = fb.GetComponent<Button>(); Debug.Log("PageController: 自动绑定 FixationPanel/BtnBack"); } }
if (_btnFixationBack != null) { _btnFixationBack.onClick.RemoveAllListeners(); _btnFixationBack.onClick.AddListener(OnFixationBackClicked); Debug.Log("PageController: _btnFixationBack 绑定成功"); }
else Debug.LogError("PageController: _btnFixationBack 未找到!");
if (_btnLimbFixation != null) { _btnLimbFixation.onClick.RemoveAllListeners(); _btnLimbFixation.onClick.AddListener(() => OnFixationSelected(FixationMethod.LimbFixation)); Debug.Log("PageController: _btnLimbFixation 绑定成功"); }
else Debug.LogError("PageController: _btnLimbFixation 未赋值!");
if (_btnSplintFixation != null) { _btnSplintFixation.onClick.RemoveAllListeners(); _btnSplintFixation.onClick.AddListener(() => OnFixationSelected(FixationMethod.SplintFixation)); Debug.Log("PageController: _btnSplintFixation 绑定成功"); }
else Debug.LogError("PageController: _btnSplintFixation 未赋值!");
if (_btnExperimentBack == null && _experimentPanel != null) { var eb = _experimentPanel.transform.Find("Navbar/BtnBack"); if (eb != null) { _btnExperimentBack = eb.GetComponent<Button>(); Debug.Log("PageController: 自动绑定 ExperimentPanel/Navbar/BtnBack"); } }
if (_btnExperimentBack != null) { _btnExperimentBack.onClick.RemoveAllListeners(); _btnExperimentBack.onClick.AddListener(OnExperimentBackClicked); Debug.Log("PageController: _btnExperimentBack 绑定成功"); }
else Debug.LogError("PageController: _btnExperimentBack 未找到!");
ShowPage(Page.Home);
Debug.Log("=== PageController 初始化完成 ===");
}
private void AutoAssignButtonsByName()
{
_btnStart = FindChildButton(_homePagePanel, "BtnStart", _btnStart);
_btnExit = FindChildButton(_homePagePanel, "BtnExit", _btnExit);
_btnBack = FindChildButton(_modeSelectPanel, "BtnBack", _btnBack);
_btnPracticeMode = FindChildButton(_modeSelectPanel, "BtnPracticeMode", _btnPracticeMode);
_btnExamMode = FindChildButton(_modeSelectPanel, "BtnExamMode", _btnExamMode);
_btnFixationBack = FindChildButton(_fixationPanel, "BtnBack", _btnFixationBack);
_btnLimbFixation = FindChildButton(_fixationPanel, "BtnLimbFixation", _btnLimbFixation);
_btnSplintFixation = FindChildButton(_fixationPanel, "BtnSplintFixation", _btnSplintFixation);
}
private Button FindChildButton(GameObject parent, string buttonName, Button fallback)
{
if (parent == null) return fallback;
var buttons = parent.GetComponentsInChildren<Button>(true);
foreach (var button in buttons)
{
if (button != null && button.name == buttonName)
return button;
}
return fallback;
}
private void Update()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
if (_editorPreview != EditorPreviewPage.None)
{
Page targetPage = (Page)((int)_editorPreview - 1);
ShowPage(targetPage);
}
}
#endif
}
private void ShowPage(Page page)
{
_currentPage = page;
if (_homePagePanel != null) _homePagePanel.SetActive(page == Page.Home);
if (_modeSelectPanel != null) _modeSelectPanel.SetActive(page == Page.ModeSelect);
if (_fixationPanel != null) _fixationPanel.SetActive(page == Page.Fixation);
if (_experimentPanel != null) _experimentPanel.SetActive(page == Page.Experiment);
if (page == Page.ModeSelect && _modeDescText != null)
_modeDescText.text = "";
var audioManager = FindObjectOfType<AudioManager>();
if (audioManager != null)
{
if (page == Page.Experiment) audioManager.PlayExperimentBg();
else audioManager.PlayHomeBg();
}
Debug.Log($"PageController: 页面切换 -> [{page}]");
}
#region 按钮回调
private void OnStartClicked()
{
ShowPage(Page.ModeSelect);
}
private void OnExitClicked()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
private void OnModeBackClicked()
{
ShowPage(Page.Home);
}
private void OnModeSelected(ExperimentMode mode)
{
_selectedMode = mode;
if (_modeDescText != null)
_modeDescText.text = (mode == ExperimentMode.Learn) ? _practiceModeDesc : _examModeDesc;
GameManager.Instance.CurrentMode = mode;
GameManager.Instance.CurrentExperimentType = ExperimentType.FractureFixation;
if (mode == ExperimentMode.Learn)
{
var examFlow = FindObjectOfType<ExamFlowManager>();
if (examFlow != null) examFlow.StopExam();
}
ShowPage(Page.Fixation);
}
private void OnFixationBackClicked()
{
ShowPage(Page.ModeSelect);
}
private void OnFixationSelected(FixationMethod method)
{
GameManager.Instance.CurrentFixationMethod = method;
var openingFlow = FindObjectOfType<OpeningFlowController>();
if (openingFlow != null)
{
ShowPage(Page.Experiment);
openingFlow.PlayOpeningFlow(() =>
{
if (_uiManager != null)
{
_uiManager.gameObject.SetActive(true);
}
var stepManager = FindObjectOfType<StepManager>();
if (stepManager != null)
{
stepManager.InitializeFromGameManager();
}
StartCoroutine(StartInitialVoiceAndCameraRoutine());
});
}
else
{
ShowPage(Page.Experiment);
if (_uiManager != null) _uiManager.gameObject.SetActive(true);
var stepManager = FindObjectOfType<StepManager>();
if (stepManager != null) stepManager.InitializeFromGameManager();
StartCoroutine(StartInitialVoiceAndCameraRoutine());
}
}
private void StartExamFlowIfNeeded()
{
if (GameManager.Instance == null) return;
if (GameManager.Instance.CurrentMode != ExperimentMode.Exam) return;
if (GameManager.Instance.CurrentFixationMethod != FixationMethod.LimbFixation) return;
var examFlow = FindObjectOfType<ExamFlowManager>();
if (examFlow != null) examFlow.BeginExam();
}
private void OnExperimentBackClicked()
{
ReturnToHome();
}
public void ReturnToHome()
{
if (_lastReturnHomeFrame == Time.frameCount)
{
Debug.Log("PageController: 返回首页已在本帧执行,跳过重复调用");
return;
}
_lastReturnHomeFrame = Time.frameCount;
Debug.Log("PageController: 返回首页,开始完整复位流程");
StopAllCoroutines();
ActionHistory.Clear();
if (_uiManager != null)
{
_uiManager.HideVideo();
_uiManager.HideEndPanel();
}
HideCanvasPanel("VideoPanel");
HideCanvasPanel("EndPanel");
HideCanvasPanel("DialogueBubble");
HideCanvasPanel("GradeResult");
HideCanvasPanel("TipPanel");
// --- 核心修复:退出时彻底清理并隐藏所有交互物体 ---
foreach (var handler in GetSceneObjectsOfType<PingClickHandler>())
{
handler.ResetState(false);
handler.ForceHideOutline();
handler.gameObject.SetActive(false);
Debug.Log($"PageController: 已隐藏 Ping {handler.name}");
}
foreach (var handler in GetSceneObjectsOfType<ChanraoTuibuHandler>())
{
handler.ResetState(false);
handler.ForceHideOutline();
handler.gameObject.SetActive(false);
Debug.Log($"PageController: 已隐藏 ChanraoTuibu {handler.name}");
}
HideSceneObjectsByNamePrefix("chanrao");
// 找到 Shose 重置并彻底隐藏
var shose = FindSceneObject("Shose");
if (shose != null)
{
var h = shose.GetComponent<ShoseClickHandler>();
if (h != null)
{
h.ResetState(false);
h.ForceHideOutline();
}
// 关键:返回主页时,必须禁用点击组件,并隐藏物体
if (h != null) h.enabled = false;
shose.SetActive(false);
Debug.Log("PageController: 已隐藏 Shose");
}
// 把 touchArray 里的点也关掉
var touchArray = GameObject.Find("touchArray");
if (touchArray != null)
{
foreach (Transform t in touchArray.transform)
{
var point2Handler = t.GetComponent<Point2ClickHandler>();
if (point2Handler != null) point2Handler.ResetState(false);
t.gameObject.SetActive(false);
}
}
var woman = GameObject.Find("woman");
if (woman != null)
{
var anim = woman.GetComponent<Animator>();
if (anim != null)
{
anim.SetBool("IsCheck", false);
anim.SetBool("isCrouch", false);
}
}
var manInjury = GameObject.Find("manInjury");
if (manInjury != null)
{
var anim = manInjury.GetComponent<Animator>();
if (anim != null) anim.SetBool("CheckFoot", false);
}
var audioManager = FindObjectOfType<AudioManager>();
if (audioManager != null)
{
audioManager.StopVoice();
audioManager.StopSfx();
audioManager.ResetCamerasToHome();
}
// ------------------------------------------------
ShowPage(Page.Home);
Debug.Log("PageController: 返回首页复位完成");
}
private void HideCanvasPanel(string panelName)
{
var panel = FindSceneObject(panelName);
if (panel != null) panel.SetActive(false);
}
private GameObject FindSceneObject(string objectName)
{
var found = GameObject.Find(objectName);
if (found != null) return found;
foreach (var t in Resources.FindObjectsOfTypeAll<Transform>())
{
if (t == null || !t.gameObject.scene.IsValid()) continue;
if (t.name == objectName) return t.gameObject;
}
return null;
}
private T[] GetSceneObjectsOfType<T>() where T : Component
{
var all = Resources.FindObjectsOfTypeAll<T>();
var list = new System.Collections.Generic.List<T>();
foreach (var item in all)
{
if (item == null || !item.gameObject.scene.IsValid()) continue;
list.Add(item);
}
return list.ToArray();
}
private void HideSceneObjectsByNamePrefix(string prefix)
{
foreach (var t in Resources.FindObjectsOfTypeAll<Transform>())
{
if (t == null || !t.gameObject.scene.IsValid()) continue;
if (!t.name.StartsWith(prefix, System.StringComparison.OrdinalIgnoreCase)) continue;
t.gameObject.SetActive(false);
Debug.Log($"PageController: 已隐藏残留对象 {t.name}");
}
}
private System.Collections.IEnumerator StartInitialVoiceAndCameraRoutine()
{
float waitTime = 1f; // 默认等1秒
var am = FindObjectOfType<AudioManager>();
// 隐藏视频面板
var allT = Resources.FindObjectsOfTypeAll<Transform>();
foreach (var t in allT)
{
if (t.name == "VideoPanel" && t.parent != null && t.parent.name == "Canvas")
{
t.gameObject.SetActive(false);
}
}
// 找鞋子
var shose = FindSceneObject("Shose");
var point2 = GameObject.Find("touchArray/point2");
if (point2 == null)
{
var touchArray = GameObject.Find("touchArray");
if (touchArray != null)
{
var p2 = touchArray.transform.Find("point2");
if (p2 != null) point2 = p2.gameObject;
}
}
if (shose != null)
{
var h = shose.GetComponent<ShoseClickHandler>();
if (h == null) h = shose.AddComponent<ShoseClickHandler>();
h.targetPoint = GameObject.Find("ShosePoint")?.transform;
var ping004 = FindFirstPingStepObject();
h.nextObject = ping004;
// 鞋子出现,但默认不开组件(不可点击)
h.enabled = false;
shose.SetActive(true);
}
if (point2 != null)
{
var oldHandler = point2.GetComponent<TouchPositionHandler>();
if (oldHandler != null) Destroy(oldHandler);
var h2 = point2.GetComponent<Point2ClickHandler>();
if (h2 == null) h2 = point2.AddComponent<Point2ClickHandler>();
if (h2.nextObject == null) h2.nextObject = shose;
point2.SetActive(false);
}
// 1. 强制播放第一句语音
if (am != null)
{
#if UNITY_EDITOR
var autoClip = UnityEditor.AssetDatabase.LoadAssetAtPath<AudioClip>("Assets/Audio/people/周围环境安全,我是救护志愿者,我可以帮助您吗.mp3");
if (autoClip != null)
{
am.PlayVoice(autoClip);
waitTime = autoClip.length + 1f;
}
#endif
}
Debug.Log($"PageController: 开始等待 {waitTime} 秒以切换摄像机并激活鞋子");
var tipPanel = GameObject.Find("TipPanel");
if (tipPanel == null)
{
foreach(var t in allT) { if (t.name == "TipPanel") { tipPanel = t.gameObject; break; } }
}
if (tipPanel != null) tipPanel.SetActive(true);
yield return new WaitForSeconds(waitTime);
if (tipPanel != null) tipPanel.SetActive(false);
if (am != null) am.SwitchToCamera3();
if (point2 != null)
{
point2.SetActive(true);
Debug.Log("PageController: 镜头切换到camera3point2 已显示");
}
StartExamFlowIfNeeded();
}
private void HideShose()
{
var shose = FindSceneObject("Shose");
if (shose != null)
{
shose.SetActive(false);
}
}
private GameObject FindFirstPingStepObject()
{
foreach (var ping in GetSceneObjectsOfType<PingClickHandler>())
{
if (ping != null && ping.name == "ping.004") return ping.gameObject;
}
foreach (var ping in GetSceneObjectsOfType<PingClickHandler>())
{
if (ping != null && ping.pingIndex == 0) return ping.gameObject;
}
return null;
}
#endregion
}