Files
VFSUnity/Assets/Scripts/UI/PageController.cs
T

495 lines
20 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 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; }
// 绑定首页按钮
if (_btnStart != null) { _btnStart.onClick.AddListener(OnStartClicked); Debug.Log("PageController: _btnStart 绑定成功"); }
else Debug.LogError("PageController: _btnStart 未赋值!");
if (_btnExit != null) { _btnExit.onClick.AddListener(OnExitClicked); Debug.Log("PageController: _btnExit 绑定成功"); }
else Debug.LogError("PageController: _btnExit 未赋值!");
if (_btnBack != null) { _btnBack.onClick.AddListener(OnModeBackClicked); Debug.Log("PageController: _btnBack 绑定成功"); }
else Debug.LogError("PageController: _btnBack 未赋值!");
if (_btnPracticeMode != null) { _btnPracticeMode.onClick.AddListener(() => OnModeSelected(ExperimentMode.Learn)); Debug.Log("PageController: _btnPracticeMode 绑定成功"); }
else Debug.LogError("PageController: _btnPracticeMode 未赋值!");
if (_btnExamMode != null) { _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.AddListener(OnFixationBackClicked); Debug.Log("PageController: _btnFixationBack 绑定成功"); }
else Debug.LogError("PageController: _btnFixationBack 未找到!");
if (_btnLimbFixation != null) { _btnLimbFixation.onClick.AddListener(() => OnFixationSelected(FixationMethod.LimbFixation)); Debug.Log("PageController: _btnLimbFixation 绑定成功"); }
else Debug.LogError("PageController: _btnLimbFixation 未赋值!");
if (_btnSplintFixation != null) { _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.AddListener(OnExperimentBackClicked); Debug.Log("PageController: _btnExperimentBack 绑定成功"); }
else Debug.LogError("PageController: _btnExperimentBack 未找到!");
if (_modeDescText != null) { _modeDescText.text = _practiceModeDesc + "\n\n" + _examModeDesc; }
ShowPage(Page.Home);
Debug.Log("=== PageController 初始化完成 ===");
}
#if UNITY_EDITOR
private void OnValidate()
{
if (Application.isPlaying) return;
UnityEditor.EditorApplication.delayCall += () =>
{
if (this == null) return;
if (Application.isPlaying) return;
switch (_editorPreview)
{
case EditorPreviewPage.None: break;
case EditorPreviewPage.Home: ShowPageEditMode(Page.Home); break;
case EditorPreviewPage.ModeSelect: ShowPageEditMode(Page.ModeSelect); break;
case EditorPreviewPage.Fixation: ShowPageEditMode(Page.Fixation); break;
case EditorPreviewPage.Experiment: ShowPageEditMode(Page.Experiment); break;
}
_editorPreview = EditorPreviewPage.None;
};
}
private void ShowPageEditMode(Page 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 (_uiManager != null) _uiManager.enabled = (page == Page.Experiment);
if (page == Page.Home) FindObjectOfType<AudioManager>()?.PlayHomeBg();
if (_uiManager != null)
_uiManager.enabled = (page == Page.Experiment);
if (page == Page.Home) FindObjectOfType<AudioManager>()?.PlayHomeBg(); // 背景音乐: 首页播 homeBg, 选固定方式时停, 实验启动时播 experimentBg
if (page == Page.Home) FindObjectOfType<AudioManager>()?.PlayHomeBg();
Debug.Log($"PageController(编辑器预览): 切换到 [{page}]");
}
#endif
#region 页面切换
private void ShowPage(Page page)
{
Debug.Log($"PageController: 页面切换 [{_currentPage}] → [{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 (_uiManager != null) _uiManager.enabled = (page == Page.Experiment);
if (page == Page.Home) FindObjectOfType<AudioManager>()?.PlayHomeBg();
}
/// <summary>
/// 隐藏所有页面,用于播放片头动画时清空 UI
/// </summary>
private void HideAllPages()
{
Debug.Log("PageController: [HideAllPages] 隐藏所有 UI 面板");
if (_homePagePanel != null) _homePagePanel.SetActive(false);
if (_modeSelectPanel != null) _modeSelectPanel.SetActive(false);
if (_fixationPanel != null) _fixationPanel.SetActive(false);
if (_experimentPanel != null) _experimentPanel.SetActive(false);
var tipPanel = GameObject.Find("TipPanel");
if (tipPanel != null) tipPanel.SetActive(false);
var dialogue = GameObject.Find("DialogueBubble");
if (dialogue != null) dialogue.SetActive(false);
}
#endregion
#region 按钮回调
private void OnStartClicked()
{
Debug.Log("PageController: [BtnStart] 点击 -> 切换到 ModeSelect");
ShowPage(Page.ModeSelect);
}
private void OnExitClicked()
{
Debug.Log("PageController: [BtnExit] 点击 -> 退出应用");
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
private void OnModeBackClicked()
{
Debug.Log("PageController: [BtnBack(Mode)] 点击 -> 返回 Home");
ShowPage(Page.Home);
}
private void OnModeSelected(ExperimentMode mode)
{
Debug.Log($"PageController: [ModeSelected] 点击 -> 模式 [{mode}] -> 切换到 Fixation");
_selectedMode = mode;
ShowPage(Page.Fixation);
}
private void OnFixationBackClicked()
{
Debug.Log("PageController: [BtnFixationBack] 点击 -> 返回 ModeSelect");
if (_modeDescText != null)
{
_modeDescText.text = _practiceModeDesc + "\n\n" + _examModeDesc;
}
ShowPage(Page.ModeSelect);
}
private void OnExperimentBackClicked()
{
Debug.Log("PageController: [BtnExperimentBack] 点击 -> 返回 Fixation");
ShowPage(Page.Fixation);
}
private void OnFixationSelected(FixationMethod method)
{
Debug.Log($"PageController: [FixationSelected] 点击 -> 固定方式 [{method}]");
var gm = GameManager.Instance;
if (gm == null)
{
Debug.LogError("PageController: GameManager.Instance 为空!");
return;
}
gm.CurrentMode = _selectedMode;
gm.CurrentFixationMethod = method;
Debug.Log($"PageController: GameManager 已设置 Mode=[{gm.CurrentMode}] Fixation=[{gm.CurrentFixationMethod}]");
// 隐藏所有UI面板,准备播放片头动画
FindObjectOfType<AudioManager>()?.StopBgMusic();
FindObjectOfType<AudioManager>()?.StopBgMusic();
HideAllPages();
// 找到 OpeningFlowController 播放片头动画
var openingFlow = FindObjectOfType<OpeningFlowController>();
if (openingFlow != null)
{
Debug.Log("PageController: 开始播放片头动画,ExperimentPanel 将在动画结束后显示");
openingFlow.PlayOpeningFlow(() =>
{
Debug.Log("PageController: 片头动画完成,显示 ExperimentPanel");
ActivateExperimentObjects();
var smW = FindObjectOfType<StepManager>(); if (smW != null) smW.InitWomanSteps(); ShowPage(Page.Experiment);
var stepManager = FindObjectOfType<StepManager>();
if (stepManager != null)
{
}
else
{
Debug.LogWarning("PageController: 未找到 StepManager,实验步骤不会自动初始化");
}
});
}
else
{
Debug.LogWarning("PageController: 未找到 OpeningFlowController,直接显示 ExperimentPanel");
ShowPage(Page.Experiment);
var stepManager = FindObjectOfType<StepManager>();
if (stepManager != null)
{
}
}
}
/// <summary>
/// 激活实验场景物件(medicalBox等),在动画完成后调用
/// </summary>
private void ActivateExperimentObjects()
{
Debug.Log("PageController: [ActivateExperimentObjects] 显示实验物件");
// 强制确保所有 ping/chanrao/chanraotuibu 隐藏
var miClean = GameObject.Find("manInjury");
if (miClean != null)
{
foreach (Transform child in miClean.transform)
{
if (child.name.Contains("ping") || child.name.Contains("chanrao"))
{
child.gameObject.SetActive(false);
Debug.Log("PageController: 强制隐藏 " + child.name);
}
}
}
FindObjectOfType<AudioManager>()?.PlayExperimentBg();
FindObjectOfType<AudioManager>()?.PlayExperimentBg();
var allObjects = FindObjectsOfType<GameObject>(true);
foreach (var go in allObjects)
{
if (go.name == "medicalBox") { go.SetActive(true); Debug.Log("PageController: medicalBox 已显示"); break; }
}
// 隐藏所有的 point1, 2, 3,不要让它们显示出来
var touchArray = GameObject.Find("touchArray");
if (touchArray != null)
{
foreach (Transform child in touchArray.transform)
{
child.gameObject.SetActive(false);
}
}
// 把 woman 直接放到 point1 的位置
var woman = GameObject.Find("woman");
var point1 = GameObject.Find("womanPointArray/point1");
if (woman != null && point1 != null)
{
woman.transform.position = point1.transform.position;
woman.transform.rotation = point1.transform.rotation;
}
// 启动语音、等待及切换摄像机并激活鞋子的流程
StartCoroutine(StartInitialVoiceAndCameraRoutine());
var tipPanel = GameObject.Find("TipPanel");
if (tipPanel != null) tipPanel.SetActive(true);
var dialogue = GameObject.Find("DialogueBubble");
if (dialogue != null) dialogue.SetActive(true);
}
public void ReturnToHome()
{
Debug.Log("PageController: [ReturnToHome] 返回首页并重置场景");
HideShose();
var man = GameObject.Find("man");
if (man != null) man.SetActive(true);
var man2 = GameObject.Find("man2");
if (man2 != null) man2.SetActive(true);
var woman = GameObject.Find("woman");
if (woman != null) woman.SetActive(false);
var manInjury = GameObject.Find("manInjury");
if (manInjury != null) manInjury.SetActive(false);
var medicalBox = GameObject.Find("medicalBox");
if (medicalBox != null) medicalBox.SetActive(false);
// 隐藏所有 ping/chanrao/chanraotuibu
var mi = GameObject.Find("manInjury");
if (mi != null) {
foreach (Transform child in mi.transform) {
if (child.name.Contains("ping") || child.name.Contains("chanrao"))
child.gameObject.SetActive(false);
}
}
// 用名字找主摄像机(Camera.main 在禁用后返回 null
var mainGo = GameObject.Find("Main Camera");
if (mainGo != null) { var c = mainGo.GetComponent<Camera>(); if (c != null) c.enabled = true; }
var cam2Go = GameObject.Find("camera2");
if (cam2Go != null) { var c = cam2Go.GetComponent<Camera>(); if (c != null) c.enabled = false; }
var cam3Go = GameObject.Find("camera3");
if (cam3Go != null) { var c = cam3Go.GetComponent<Camera>(); if (c != null) c.enabled = false; }
var manAnim = man != null ? man.GetComponent<Animator>() : null;
if (manAnim != null) { manAnim.SetBool("IsStart", false); manAnim.SetBool("IsFull", false); manAnim.Play("manIdle", 0, 0f); }
// 重置 woman 动画
if (woman != null)
{
var wAnim = woman.GetComponent<Animator>();
if (wAnim != null)
{
wAnim.SetBool("isCrouch", false);
wAnim.Play("Idle", 0, 0f); // 假设其默认闲置动画为 Idle 或类似名称
}
}
// 重置 manInjury 动画
if (mi != null)
{
var mAnim = mi.GetComponent<Animator>();
if (mAnim != null)
{
mAnim.SetBool("CheckFoot", false);
mAnim.Play("manInjury", 0, 0f); // 默认动画
}
// 重置所有的 Handler 状态
foreach (var handler in mi.GetComponentsInChildren<PingClickHandler>(true)) handler.ResetState();
foreach (var handler in mi.GetComponentsInChildren<ChanraoTuibuHandler>(true)) handler.ResetState();
}
// 找到 Shose 重置点击状态
var shose = GameObject.Find("Shose");
if (shose == null)
{
var allTransforms = Resources.FindObjectsOfTypeAll<Transform>();
foreach(var t in allTransforms) { if (t.parent == null && t.name == "Shose") { shose = t.gameObject; break; } }
}
if (shose != null)
{
var h = shose.GetComponent<ShoseClickHandler>();
if (h != null) h.ResetState();
}
ShowPage(Page.Home);
}
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 = GameObject.Find("Shose");
if (shose == null)
{
// 如果被禁用了,找它的最顶层引用
var allTransforms = Resources.FindObjectsOfTypeAll<Transform>();
foreach(var t in allTransforms) { if (t.parent == null && t.name == "Shose") { shose = t.gameObject; break; } }
}
if (shose != null)
{
var h = shose.GetComponent<ShoseClickHandler>();
if (h == null) h = shose.AddComponent<ShoseClickHandler>();
h.targetPoint = GameObject.Find("ShosePoint")?.transform;
if (h.nextObject == null)
{
var chanraotuibu = GameObject.Find("chanraotuibu");
if (chanraotuibu == null)
{
var mi = GameObject.Find("manInjury");
if (mi != null) chanraotuibu = mi.transform.Find("chanraotuibu")?.gameObject;
}
h.nextObject = chanraotuibu;
}
shose.SetActive(true);
Debug.Log("PageController: 开场动画结束,Shose 已立刻激活");
}
// 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} 秒以切换摄像机并激活鞋子");
// --- 开场动画结束,开始显示 TipPanel,直到切换到 camera2 再由切换逻辑隐藏 ---
var tipPanel = GameObject.Find("TipPanel");
if (tipPanel == null)
{
var allTips = Resources.FindObjectsOfTypeAll<Transform>();
foreach(var t in allTips) { if (t.name == "TipPanel") { tipPanel = t.gameObject; break; } }
}
if (tipPanel != null) tipPanel.SetActive(true);
// ---------------------------------------------------------------------
yield return new WaitForSeconds(waitTime);
// 2. 切换到 camera3 (注意原逻辑是切到 camera3,如果说是要在这里隐藏TipPanel)
if (tipPanel != null) tipPanel.SetActive(false);
if (am != null) am.SwitchToCamera3();
}
private void HideShose()
{
var shose = GameObject.Find("Shose");
if (shose != null)
{
shose.SetActive(false);
}
}
#endregion
}