From a33435a8275e88b02ad87cf09ad674182689928e Mon Sep 17 00:00:00 2001 From: yangbear Date: Wed, 8 Jul 2026 09:38:42 +0800 Subject: [PATCH] fix: resolve Next/Previous step and UI skipping bugs --- .../Animation/OpeningFlowController.cs | 10 +- Assets/Scripts/Core/StepManager.cs | 168 +++++++++++++++--- .../Interaction/ChanraoTuibuHandler.cs | 54 +++++- Assets/Scripts/Interaction/OutlineConfig.cs | 2 +- .../Scripts/Interaction/PingClickHandler.cs | 71 +++++++- .../Scripts/Interaction/ShoseClickHandler.cs | 116 +++++++++++- .../Interaction/TouchPositionHandler.cs | 26 ++- Assets/Scripts/UI/PageController.cs | 142 +++++++++++++-- Assets/Scripts/UI/UIManager.cs | 47 ++--- 9 files changed, 553 insertions(+), 83 deletions(-) diff --git a/Assets/Scripts/Animation/OpeningFlowController.cs b/Assets/Scripts/Animation/OpeningFlowController.cs index 5218621..25a4d51 100644 --- a/Assets/Scripts/Animation/OpeningFlowController.cs +++ b/Assets/Scripts/Animation/OpeningFlowController.cs @@ -61,6 +61,10 @@ public class OpeningFlowController : MonoBehaviour if (_womanObject == null) _womanObject = GameObject.Find("woman"); if (_manInjuryObject == null) _manInjuryObject = GameObject.Find("manInjury"); + // 确保开场时隐藏 Shose + var shose = GameObject.Find("Shose"); + if (shose != null) shose.SetActive(false); + if (_blackScreenPanel == null) _blackScreenPanel = GameObject.Find("BlackScreenPanel"); if (_blackScreenPanel == null) @@ -90,6 +94,10 @@ public class OpeningFlowController : MonoBehaviour { Debug.Log($"[OpeningFlow] PlayOpeningFlow() 被调用, enable={_enableOpeningFlow}"); + // 再次确保开场隐藏鞋子 + var shose = GameObject.Find("Shose"); + if (shose != null) shose.SetActive(false); + if (!_enableOpeningFlow) { Debug.Log("[OpeningFlow] 开场动画已禁用,直接跳过"); @@ -136,9 +144,9 @@ public class OpeningFlowController : MonoBehaviour // Step 3: 摔倒 + manCall 音效 Debug.Log("[OpeningFlow] Step3: manfull 开始"); + if (AudioManager.I != null) AudioManager.I.PlayManCallSfx(); if (_manAnimator != null) { _manAnimator.Play("manfull", 0, 0f); } yield return new WaitForSeconds(2.1f); - if (AudioManager.I != null) AudioManager.I.PlayManCallSfx(); Debug.Log("[OpeningFlow] manfull 播放完成, 停留 2s"); yield return new WaitForSeconds(2f); diff --git a/Assets/Scripts/Core/StepManager.cs b/Assets/Scripts/Core/StepManager.cs index c550d1a..0218bf2 100644 --- a/Assets/Scripts/Core/StepManager.cs +++ b/Assets/Scripts/Core/StepManager.cs @@ -124,12 +124,98 @@ public class StepManager : MonoBehaviour public void NextStep() { - // Woman 自由步进优先 - if (_pingObjects != null && _pingObjects.Length > 0 && _pingStepIndex < _pingMaxStep) { PingStepNext(); return; } - if (_womanObject != null && _womanPositions != null) { WomanStepNext(); return; } - if (_activeSteps == null) return; - if (_currentStepIndex >= _activeSteps.Length - 1) { CompleteExperiment(); return; } - GoToStep(_currentStepIndex + 1); + Debug.LogError("====== StepManager: 接收到 NextStep 指令! ======"); + + // 首先尝试是否存在可以点击的 3D 物品,如果有,优先执行 3D 交互 + if (TryClickActiveHandler()) + { + Debug.Log("====== StepManager: 成功模拟 3D 物品点击,不进行常规的 NextStep 流程 ======"); + return; + } + + Debug.Log("====== StepManager: 未找到 3D 物品,执行常规 NextStep 流程 ======"); + + if (_activeSteps != null && _currentStepIndex < _activeSteps.Length - 1) + { + GoToStep(_currentStepIndex + 1); + } + else if (_activeSteps != null && _currentStepIndex == _activeSteps.Length - 1) + { + CompleteExperiment(); + } + } + + public void TryInteractCurrent3DStep() + { + Debug.Log("====== StepManager: 接收到 3D 自动交互指令 ======"); + if (TryClickActiveHandler()) return; + Debug.Log("====== StepManager: 当前没有可自动交互的 3D 物品 ======"); + } + + private bool TryClickActiveHandler() + { + var touches = Object.FindObjectsOfType(); + System.Array.Sort(touches, (a, b) => string.Compare(a.name, b.name)); + foreach (var t in touches) + { + if (t.gameObject.activeInHierarchy && t.CanBeClicked()) + { + Debug.LogError($"====== StepManager: 模拟点击了 {t.name}! ======"); + t.PerformClick(); + return true; + } + } + + var shoses = Object.FindObjectsOfType(); + foreach (var h in shoses) + { + if (h.gameObject.activeInHierarchy && h.CanBeClicked()) + { + Debug.LogError($"====== StepManager: 模拟点击了 {h.name}! ======"); + h.PerformClick(); + return true; + } + } + + var chanraos = Object.FindObjectsOfType(); + foreach (var h in chanraos) + { + if (h.gameObject.activeInHierarchy && h.CanBeClicked()) + { + Debug.LogError($"====== StepManager: 模拟点击了 {h.name}! ======"); + h.PerformClick(); + return true; + } + } + + var pings = Object.FindObjectsOfType(); + System.Array.Sort(pings, (a, b) => string.Compare(b.name, a.name)); + foreach (var p in pings) + { + if (p.gameObject.activeInHierarchy && p.CanBeClicked()) + { + Debug.LogError($"====== StepManager: 模拟点击了 {p.name}! ======"); + p.PerformClick(); + return true; + } + } + return false; + } + + private bool TryUndoActiveHandler() + { + if (_pingStepIndex > 0 && _pingStepIndex <= _pingMaxStep) + { + if (_pingObjects == null) InitPingSteps(); + PingStepPrevious(); + return true; + } + if (_womanStepIndex > 0 && _womanStepIndex <= _womanMaxStep && _pingStepIndex == 0) + { + WomanStepPrevious(); + return true; + } + return false; } private void PingStepPrevious() @@ -151,15 +237,33 @@ public class StepManager : MonoBehaviour } else { - // Undo first click: hide current ping, show previous ping (if any) + // Undo first click: reset current ping to blink state, and hide the next ping it spawned if (_pingObjects != null && idx < _pingObjects.Length && _pingObjects[idx] != null) { var h = _pingObjects[idx].GetComponent(); - if (h != null) h.UndoShow(); + if (h != null) + { + // 撤销它对下一个目标的影响 + if (h.nextPing != null) + { + h.nextPing.SetActive(false); + } + else + { + // 如果是最后一个,撤销它唤醒的所有其他边框 + var allPings = Object.FindObjectsOfType(); + foreach (var p in allPings) + { + if (p.gameObject != h.gameObject) + { + p.gameObject.SetActive(false); + } + } + } + // 重置自己到初始状态 + h.ResetState(); + } } - // If going back to start, show ping.004 - if (idx == 0 && _pingObjects != null && _pingObjects.Length > 0 && _pingObjects[0] != null) - _pingObjects[0].SetActive(true); } _pingStepIndex--; Debug.Log($"StepManager: Ping撤销 -> {_pingStepIndex}"); @@ -215,12 +319,23 @@ public class StepManager : MonoBehaviour public void PreviousStep() { - // Woman 自由步进优先 - if (_pingObjects != null && _pingObjects.Length > 0 && _pingStepIndex > 0) { PingStepPrevious(); return; } - if (_womanObject != null && _womanPositions != null) { WomanStepPrevious(); return; } - if (_activeSteps == null) return; - if (_currentStepIndex <= 0) return; - GoToStep(_currentStepIndex - 1); + Debug.LogError("====== StepManager: 接收到 PreviousStep 指令! ======"); + + // 如果尝试撤销 3D 交互成功,就不再回退 UI + if (TryUndoActiveHandler()) + { + Debug.Log("====== StepManager: 成功撤销 3D 交互,不进行常规的 PreviousStep 流程 ======"); + return; + } + + if (_currentStepIndex > 0) + { + GoToStep(_currentStepIndex - 1); + } + else + { + Debug.LogWarning("====== StepManager: 已经是第一步,无法后退 ======"); + } } public StepData GetCurrentStep() @@ -290,15 +405,20 @@ public class StepManager : MonoBehaviour if (mi == null) return; _pingObjects = new GameObject[4]; _chanraoObjects = new GameObject[4]; - for (int i = 1; i <= 4; i++) + + var pings = Object.FindObjectsOfType(true); + foreach (var p in pings) { - string pn = "ping." + i.ToString("D3"); - string cn = "chanrao." + i.ToString("D3"); - var pt = mi.transform.Find(pn); - var ct = mi.transform.Find(cn); - if (pt != null) _pingObjects[i-1] = pt.gameObject; - if (ct != null) _chanraoObjects[i-1] = ct.gameObject; + if (p.pingIndex >= 0 && p.pingIndex < 4) + { + _pingObjects[p.pingIndex] = p.gameObject; + if (p.chanraoObject != null) + { + _chanraoObjects[p.pingIndex] = p.chanraoObject; + } + } } + _pingStepIndex = 0; Debug.Log("StepManager: Ping步进已初始化"); } diff --git a/Assets/Scripts/Interaction/ChanraoTuibuHandler.cs b/Assets/Scripts/Interaction/ChanraoTuibuHandler.cs index 509b98e..10cf541 100644 --- a/Assets/Scripts/Interaction/ChanraoTuibuHandler.cs +++ b/Assets/Scripts/Interaction/ChanraoTuibuHandler.cs @@ -4,11 +4,15 @@ public class ChanraoTuibuHandler : MonoBehaviour { public GameObject nextObject; private MeshRenderer _outlineMesh; + private bool _isBlinking; + + public bool CanBeClicked() { return _isBlinking; } void OnEnable() { if (GetComponent() == null) gameObject.AddComponent().radius = 0.5f; foreach (var r in GetComponentsInChildren(true)) r.enabled = false; CreateOutlineMesh(); + _isBlinking = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); Debug.Log($"[ChanraoTuibu] OnEnable outline={_outlineMesh!=null}"); @@ -19,17 +23,28 @@ public class ChanraoTuibuHandler : MonoBehaviour if (_outlineMesh != null) return; var mf = GetComponent(); if (mf == null) mf = GetComponentInChildren(); - if (mf == null || mf.sharedMesh == null) { Debug.LogWarning("[ChanraoTuibu] 无MeshFilter"); return; } + Mesh mesh = null; + if (mf != null && mf.sharedMesh != null) + { + mesh = mf.sharedMesh; + } + else + { + var smr = GetComponent(); + if (smr == null) smr = GetComponentInChildren(); + if (smr != null && smr.sharedMesh != null) + mesh = smr.sharedMesh; + } + if (mesh == null) { Debug.LogWarning("[ChanraoTuibu] 无Mesh数据"); return; } var shader = Shader.Find("Custom/OutlineUnlit"); if (shader == null) { Debug.LogWarning("[ChanraoTuibu] Shader缺失"); return; } var mat = new Material(shader); mat.SetColor("_OutlineColor", new Color(0.2f, 0.5f, 1f, 1f)); mat.SetColor("_MainColor", new Color(0, 0, 0, 0)); - float s = transform.lossyScale.magnitude / Mathf.Sqrt(3); - mat.SetFloat("_OutlineWidth", s > 0.001f ? OutlineConfig.Width / s : OutlineConfig.Width); + mat.SetFloat("_OutlineWidth", OutlineConfig.Width); var go = new GameObject("Outline"); go.transform.SetParent(transform, false); - go.AddComponent().sharedMesh = mf.sharedMesh; + go.AddComponent().sharedMesh = mesh; _outlineMesh = go.AddComponent(); _outlineMesh.material = mat; } @@ -42,13 +57,42 @@ public class ChanraoTuibuHandler : MonoBehaviour } void OnMouseDown() + { + PerformClick(); + } + + public void PerformClick() { Debug.Log($"[ChanraoTuibu] {name} 被点击"); + _isBlinking = false; StopAllCoroutines(); if (_outlineMesh != null) _outlineMesh.enabled = false; var mr = GetComponent(); if (mr != null) mr.enabled = true; - foreach (var r in GetComponentsInChildren(true)) r.enabled = true; // 显示模型 + foreach (var r in GetComponentsInChildren(true)) { if (_outlineMesh != null && r == _outlineMesh) continue; r.enabled = true; } // 显示模型 + + // 如果由于意外 nextObject 丢失了,手动把它指向 ping.004 + if (nextObject == null) + { + var mi = GameObject.Find("manInjury"); + if (mi != null) + { + var p004 = mi.transform.Find("ping.004"); + if (p004 != null) nextObject = p004.gameObject; + } + } + // 激活下一个(ping.004) if (nextObject != null) { nextObject.SetActive(true); Debug.Log($"[ChanraoTuibu] → {nextObject.name}"); } + else Debug.LogError("[ChanraoTuibu] 致命错误:nextObject 依然是 null!找不到 ping.004"); + } + + public void ResetState() + { + var mr = GetComponent(); if (mr != null) mr.enabled = false; + var smr = GetComponent(); if (smr != null) smr.enabled = false; + foreach (var r in GetComponentsInChildren(true)) { if (_outlineMesh != null && r == _outlineMesh) continue; r.enabled = false; } + if (_outlineMesh != null) _outlineMesh.enabled = true; + StopAllCoroutines(); + StartCoroutine(BlinkOutline()); } } diff --git a/Assets/Scripts/Interaction/OutlineConfig.cs b/Assets/Scripts/Interaction/OutlineConfig.cs index 47604a1..152c78c 100644 --- a/Assets/Scripts/Interaction/OutlineConfig.cs +++ b/Assets/Scripts/Interaction/OutlineConfig.cs @@ -2,5 +2,5 @@ using UnityEngine; public static class OutlineConfig { - public static float Width = 0.15f; + public static float Width = 2.0f; } diff --git a/Assets/Scripts/Interaction/PingClickHandler.cs b/Assets/Scripts/Interaction/PingClickHandler.cs index fe90c2d..7917cfb 100644 --- a/Assets/Scripts/Interaction/PingClickHandler.cs +++ b/Assets/Scripts/Interaction/PingClickHandler.cs @@ -6,6 +6,9 @@ public class PingClickHandler : MonoBehaviour public int pingIndex; private MeshRenderer _modelRenderer, _outlineMesh; private bool _modelShown; + private bool _isBlinking; + + public bool CanBeClicked() { return _isBlinking; } void OnEnable() { @@ -15,6 +18,7 @@ public class PingClickHandler : MonoBehaviour if (GetComponent() == null) gameObject.AddComponent().radius = 0.5f; CreateOutlineMesh(); _modelShown = false; + _isBlinking = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } @@ -30,10 +34,11 @@ public class PingClickHandler : MonoBehaviour var mat = new Material(shader); mat.SetColor("_OutlineColor", new Color(0.2f, 0.5f, 1f, 1f)); mat.SetColor("_MainColor", new Color(0, 0, 0, 0)); - float s = transform.lossyScale.magnitude / Mathf.Sqrt(3); - mat.SetFloat("_OutlineWidth", s > 0.001f ? OutlineConfig.Width / s : OutlineConfig.Width); + mat.SetFloat("_OutlineWidth", OutlineConfig.Width); var go = new GameObject("Outline"); go.transform.SetParent(transform, false); + // 稍微往上偏移一点点,防止边框插进地里 + go.transform.position += Vector3.up * 0.05f; go.AddComponent().sharedMesh = mf.sharedMesh; _outlineMesh = go.AddComponent(); _outlineMesh.material = mat; @@ -47,6 +52,11 @@ public class PingClickHandler : MonoBehaviour } void OnMouseDown() + { + PerformClick(); + } + + public void PerformClick() { foreach (var c in Object.FindObjectsOfType()) { @@ -58,11 +68,23 @@ public class PingClickHandler : MonoBehaviour if (!_modelShown) { _modelShown = true; + _isBlinking = false; StopAllCoroutines(); if (_modelRenderer != null) _modelRenderer.enabled = true; foreach (var r in GetComponentsInChildren(true)) r.enabled = true; if (_outlineMesh != null) _outlineMesh.enabled = false; if (nextPing != null) nextPing.SetActive(true); + else + { + // 如果 nextPing 是 null,说明我是最后一个 ping(也就是 ping.001) + // 此时所有的 ping 都已经显示了模型,进入阶段二:重新点亮所有的 ping 边框 + var allPings = Object.FindObjectsOfType(); + foreach (var p in allPings) + { + p.ReEnableBorder(); + } + Debug.Log($"[PingClick] {name} 是最后一个 ping,所有边框已重新激活!"); + } Debug.Log($"[PingClick] {name} 模型显示, 激活 {nextPing?.name}"); var sm = FindObjectOfType(); if (sm != null) sm.RecordPingStep(pingIndex, false); @@ -73,10 +95,51 @@ public class PingClickHandler : MonoBehaviour gameObject.SetActive(false); var sm = FindObjectOfType(); if (sm != null) sm.RecordPingStep(pingIndex, true); + + // 判断是否是真正的最后一步:检查所有的 PingClickHandler,看是否还有 activeInHierarchy 的。 + // 注意当前 gameObject 刚刚被 SetActive(false),所以 FindObjectsOfType 获取不到当前的对象了。 + var remainingPings = Object.FindObjectsOfType(); + int activePingCount = 0; + foreach (var p in remainingPings) + { + if (p.gameObject.activeInHierarchy) activePingCount++; + } + + if (activePingCount == 0) + { + Debug.Log("[PingClick] 所有的 ping 都已经绑成 chanrao 了!播放完成语音。"); + var am = FindObjectOfType(); + if (am != null) + { +#if UNITY_EDITOR + var finishClip = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/people/伤员一切正常,包扎完毕.mp3"); + if (finishClip != null) am.PlayVoice(finishClip); +#endif + } + } } } - public void ReEnableBorder() { if (_outlineMesh != null) { _outlineMesh.enabled = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } } - public void UndoSecondClick() {} + public void ReEnableBorder() { _isBlinking = true; if (_outlineMesh != null) { _outlineMesh.enabled = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } } + public void UndoSecondClick() + { + gameObject.SetActive(true); + _modelShown = true; + if (_modelRenderer != null) _modelRenderer.enabled = true; + foreach (var r in GetComponentsInChildren(true)) r.enabled = true; + if (_outlineMesh != null) _outlineMesh.enabled = false; + } public void UndoShow() { gameObject.SetActive(false); } + + public void ResetState() + { + _modelShown = false; + _isBlinking = true; + if (_modelRenderer != null) _modelRenderer.enabled = false; + // 隐藏自身模型 + foreach (var r in GetComponentsInChildren(true)) { if (_outlineMesh != null && r == _outlineMesh) continue; r.enabled = false; } + if (_outlineMesh != null) _outlineMesh.enabled = true; + StopAllCoroutines(); + StartCoroutine(BlinkOutline()); + } } diff --git a/Assets/Scripts/Interaction/ShoseClickHandler.cs b/Assets/Scripts/Interaction/ShoseClickHandler.cs index 2017caa..31a974d 100644 --- a/Assets/Scripts/Interaction/ShoseClickHandler.cs +++ b/Assets/Scripts/Interaction/ShoseClickHandler.cs @@ -6,6 +6,12 @@ public class ShoseClickHandler : MonoBehaviour public Transform targetPoint; private MeshRenderer _outlineMesh; private bool _clicked; + + public bool CanBeClicked() { return !_clicked; } + + private Vector3 _initialPosition; + private Quaternion _initialRotation; + private bool _hasRecordedInitialTransform = false; void OnEnable() { @@ -17,12 +23,20 @@ public class ShoseClickHandler : MonoBehaviour Destroy(GetComponent()); var col = GetComponent(); if (col == null) col = gameObject.AddComponent(); - // 按 localScale 缩放 collider 匹配模型实际大小 - col.center = Vector3.Scale(mb.center, transform.localScale); - col.size = Vector3.Scale(mb.size, transform.localScale) * 1.2f; + // Unity 的 BoxCollider.size 处于本地坐标空间,会自动乘上 localScale,这里不能重复缩放 + col.center = mb.center; + col.size = mb.size * 1.2f; col.enabled = true; } else { if (GetComponent() == null) gameObject.AddComponent().radius = 0.3f; } + + if (!_hasRecordedInitialTransform) + { + _initialPosition = transform.position; + _initialRotation = transform.rotation; + _hasRecordedInitialTransform = true; + } + CreateOutlineMesh(); StopAllCoroutines(); StartCoroutine(BlinkOutline()); @@ -40,9 +54,7 @@ public class ShoseClickHandler : MonoBehaviour var mat = new Material(shader); mat.SetColor("_OutlineColor", new Color(0.2f, 0.5f, 1f, 1f)); mat.SetColor("_MainColor", new Color(0, 0, 0, 0)); - // 描边宽度补偿 scale - float s = transform.lossyScale.magnitude / Mathf.Sqrt(3); - mat.SetFloat("_OutlineWidth", s > 0.001f ? OutlineConfig.Width / s : OutlineConfig.Width); + mat.SetFloat("_OutlineWidth", OutlineConfig.Width); var go = new GameObject("Outline"); go.transform.SetParent(transform, false); go.AddComponent().sharedMesh = mf.sharedMesh; @@ -58,6 +70,11 @@ public class ShoseClickHandler : MonoBehaviour } void OnMouseDown() + { + PerformClick(); + } + + public void PerformClick() { if (_clicked) return; _clicked = true; @@ -66,5 +83,92 @@ public class ShoseClickHandler : MonoBehaviour if (_outlineMesh != null) _outlineMesh.enabled = false; if (targetPoint != null) { transform.position = targetPoint.position; transform.rotation = targetPoint.rotation; } if (nextObject != null) nextObject.SetActive(true); + + var woman = GameObject.Find("woman"); + if (woman != null) + { + var anim = woman.GetComponent(); + if (anim != null) + { + anim.SetBool("isCrouch", true); + anim.CrossFade("womanCrouch", 0.1f); + } + + // 移动 woman 到 point3 + var point3 = GameObject.Find("womanPointArray/point3"); + if (point3 != null) + { + woman.transform.position = point3.transform.position; + woman.transform.rotation = point3.transform.rotation; + } + } + + var manInjury = GameObject.Find("manInjury"); + if (manInjury != null) + { + var anim = manInjury.GetComponent(); + if (anim != null) + { + anim.SetBool("CheckFoot", true); + anim.CrossFade("manInjuryFoot", 0.1f); + + // 启动协程,在动画播放完后将 CheckFoot 重置为 false + StartCoroutine(ResetCheckFoot(anim)); + } + } + + // 隐藏 point3 的边框 (touchArray/point3) + var touchArray = GameObject.Find("touchArray"); + if (touchArray != null) + { + var touchPoint3 = touchArray.transform.Find("point3"); + if (touchPoint3 != null) + { + touchPoint3.gameObject.SetActive(false); + } + + // 点击鞋子时播放原本挂在 point1 上的那段语音(伤员左大腿疑似骨折) + var am = FindObjectOfType(); + if (am != null) + { +#if UNITY_EDITOR + var fractureClip = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/people/伤员左大腿疑似骨折,无伤口.mp3"); + if (fractureClip != null) am.PlayVoice(fractureClip); +#endif + } + } + + // 切换到摄像机3 + var audioManager = FindObjectOfType(); + if (audioManager != null) + { + audioManager.SwitchToCamera3(); + } + } + + public void ResetState() + { + _clicked = false; + if (_outlineMesh != null) _outlineMesh.enabled = true; + + if (_hasRecordedInitialTransform) + { + transform.position = _initialPosition; + transform.rotation = _initialRotation; + } + + StopAllCoroutines(); + StartCoroutine(BlinkOutline()); + } + + private System.Collections.IEnumerator ResetCheckFoot(Animator anim) + { + // 等待约 3.5 秒(根据实际检查脚动画长度),将 CheckFoot 设回 false + yield return new WaitForSeconds(3.5f); + if (anim != null) + { + anim.SetBool("CheckFoot", false); + Debug.Log("[ShoseClick] CheckFoot 已被重置为 false"); + } } } diff --git a/Assets/Scripts/Interaction/TouchPositionHandler.cs b/Assets/Scripts/Interaction/TouchPositionHandler.cs index 62c68c2..abe4f12 100644 --- a/Assets/Scripts/Interaction/TouchPositionHandler.cs +++ b/Assets/Scripts/Interaction/TouchPositionHandler.cs @@ -16,7 +16,6 @@ public class TouchPositionHandler : MonoBehaviour private void Start() { _meshRenderer = GetComponent(); - StartCoroutine(BlinkMesh()); } private void OnEnable() @@ -32,19 +31,29 @@ public class TouchPositionHandler : MonoBehaviour var c = mat.GetColor("_MainColor"); c.a = 0f; mat.SetColor("_MainColor", c); + + // 同步赋值统一的描边宽度,否则可能会太细导致看不见闪动 + if (mat.HasProperty("_OutlineWidth")) + { + mat.SetFloat("_OutlineWidth", OutlineConfig.Width); + } } } - StopAllCoroutines(); - StartCoroutine(BlinkMesh()); } private System.Collections.IEnumerator BlinkMesh() { - while (true) - { - if (_meshRenderer != null) _meshRenderer.enabled = !_meshRenderer.enabled; - yield return new WaitForSeconds(0.4f); - } + yield break; + } + + public bool CanBeClicked() + { + return gameObject.activeInHierarchy && _meshRenderer != null && _meshRenderer.enabled; + } + + public void PerformClick() + { + OnMouseDown(); } private void OnMouseDown() @@ -92,7 +101,6 @@ public class TouchPositionHandler : MonoBehaviour } } - StopAllCoroutines(); if (_meshRenderer != null) _meshRenderer.enabled = false; gameObject.SetActive(false); diff --git a/Assets/Scripts/UI/PageController.cs b/Assets/Scripts/UI/PageController.cs index 1e54dfc..0bb117f 100644 --- a/Assets/Scripts/UI/PageController.cs +++ b/Assets/Scripts/UI/PageController.cs @@ -49,6 +49,9 @@ public class PageController : MonoBehaviour { Debug.Log("=== PageController 初始化开始 ==="); + // 一开始就隐藏鞋子,以免在主页或开场动画时穿帮 + HideShose(); + // 关掉多余AudioListener(只留Main Camera的) var cam2 = GameObject.Find("camera2"); if (cam2 != null) { var al = cam2.GetComponent(); if (al != null) al.enabled = false; } var cam3 = GameObject.Find("camera3"); if (cam3 != null) { var al = cam3.GetComponent(); if (al != null) al.enabled = false; } @@ -294,17 +297,27 @@ public class PageController : MonoBehaviour if (go.name == "medicalBox") { go.SetActive(true); Debug.Log("PageController: medicalBox 已显示"); break; } } - var touch = GameObject.Find("touchArray"); - if (touch != null && touch.transform.childCount > 0) { touch.transform.GetChild(0).gameObject.SetActive(true); Debug.Log("PageController: touchArray/point1 已显示"); - - // 自动播放第一段 woman 语音 - var am = FindObjectOfType(); - if (am != null) { -#if UNITY_EDITOR - var autoClip = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/people/周围环境安全,我是救护志愿者,我可以帮助您吗.mp3"); - if (autoClip != null) am.PlayVoice(autoClip); -#endif - } } + // 隐藏所有的 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); @@ -316,6 +329,8 @@ public class PageController : MonoBehaviour { Debug.Log("PageController: [ReturnToHome] 返回首页并重置场景"); + HideShose(); + var man = GameObject.Find("man"); if (man != null) man.SetActive(true); var man2 = GameObject.Find("man2"); @@ -341,16 +356,117 @@ public class PageController : MonoBehaviour if (mainGo != null) { var c = mainGo.GetComponent(); if (c != null) c.enabled = true; } var cam2Go = GameObject.Find("camera2"); if (cam2Go != null) { var c = cam2Go.GetComponent(); if (c != null) c.enabled = false; } + var cam3Go = GameObject.Find("camera3"); + if (cam3Go != null) { var c = cam3Go.GetComponent(); if (c != null) c.enabled = false; } var manAnim = man != null ? man.GetComponent() : 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(); + if (wAnim != null) + { + wAnim.SetBool("isCrouch", false); + wAnim.Play("Idle", 0, 0f); // 假设其默认闲置动画为 Idle 或类似名称 + } + } + + // 重置 manInjury 动画 + if (mi != null) + { + var mAnim = mi.GetComponent(); + if (mAnim != null) + { + mAnim.SetBool("CheckFoot", false); + mAnim.Play("manInjury", 0, 0f); // 默认动画 + } + + // 重置所有的 Handler 状态 + foreach (var handler in mi.GetComponentsInChildren(true)) handler.ResetState(); + foreach (var handler in mi.GetComponentsInChildren(true)) handler.ResetState(); + } + + // 找到 Shose 重置点击状态 + var shose = GameObject.Find("Shose"); + if (shose == null) + { + var allTransforms = Resources.FindObjectsOfTypeAll(); + foreach(var t in allTransforms) { if (t.parent == null && t.name == "Shose") { shose = t.gameObject; break; } } + } + if (shose != null) + { + var h = shose.GetComponent(); + if (h != null) h.ResetState(); + } + ShowPage(Page.Home); } + private System.Collections.IEnumerator StartInitialVoiceAndCameraRoutine() + { + float waitTime = 1f; // 默认等1秒 + var am = FindObjectOfType(); + + // 实验刚开始,立刻激活鞋子,不等语音播完 + var shose = GameObject.Find("Shose"); + if (shose == null) + { + // 如果被禁用了,找它的最顶层引用 + var allTransforms = Resources.FindObjectsOfTypeAll(); + foreach(var t in allTransforms) { if (t.parent == null && t.name == "Shose") { shose = t.gameObject; break; } } + } + if (shose != null) + { + var h = shose.GetComponent(); + if (h == null) h = shose.AddComponent(); + 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(false); + shose.SetActive(true); + Debug.Log("PageController: 开场动画结束,Shose 已立刻激活"); + } + + // 1. 强制播放第一句语音:“周围环境安全,我是救护志愿者,我可以帮助您吗” + if (am != null) + { +#if UNITY_EDITOR + var autoClip = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Audio/people/周围环境安全,我是救护志愿者,我可以帮助您吗.mp3"); + if (autoClip != null) + { + am.PlayVoice(autoClip); + waitTime = autoClip.length + 1f; + } +#endif + } + + Debug.Log($"PageController: 开始等待 {waitTime} 秒以切换摄像机并激活鞋子"); + yield return new WaitForSeconds(waitTime); + + // 2. 切换到 camera3 + if (am != null) am.SwitchToCamera3(); + } + + private void HideShose() + { + var shose = GameObject.Find("Shose"); + if (shose != null) + { + shose.SetActive(false); + } + } + #endregion } - - diff --git a/Assets/Scripts/UI/UIManager.cs b/Assets/Scripts/UI/UIManager.cs index 57d8d32..a70addc 100644 --- a/Assets/Scripts/UI/UIManager.cs +++ b/Assets/Scripts/UI/UIManager.cs @@ -105,7 +105,7 @@ public class UIManager : MonoBehaviour var btn = btnFS.GetComponent