fix: resolve Next/Previous step and UI skipping bugs

This commit is contained in:
yangbear
2026-07-08 09:38:42 +08:00
parent 2018c6813e
commit a33435a827
9 changed files with 553 additions and 83 deletions
@@ -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);
+144 -24
View File
@@ -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<TouchPositionHandler>();
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<ShoseClickHandler>();
foreach (var h in shoses)
{
if (h.gameObject.activeInHierarchy && h.CanBeClicked())
{
Debug.LogError($"====== StepManager: 模拟点击了 {h.name} ======");
h.PerformClick();
return true;
}
}
var chanraos = Object.FindObjectsOfType<ChanraoTuibuHandler>();
foreach (var h in chanraos)
{
if (h.gameObject.activeInHierarchy && h.CanBeClicked())
{
Debug.LogError($"====== StepManager: 模拟点击了 {h.name} ======");
h.PerformClick();
return true;
}
}
var pings = Object.FindObjectsOfType<PingClickHandler>();
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<PingClickHandler>();
if (h != null) h.UndoShow();
if (h != null)
{
// 撤销它对下一个目标的影响
if (h.nextPing != null)
{
h.nextPing.SetActive(false);
}
else
{
// 如果是最后一个,撤销它唤醒的所有其他边框
var allPings = Object.FindObjectsOfType<PingClickHandler>();
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<PingClickHandler>(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步进已初始化");
}
@@ -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<Collider>() == null) gameObject.AddComponent<SphereCollider>().radius = 0.5f;
foreach (var r in GetComponentsInChildren<Renderer>(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<MeshFilter>();
if (mf == null) mf = GetComponentInChildren<MeshFilter>();
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<SkinnedMeshRenderer>();
if (smr == null) smr = GetComponentInChildren<SkinnedMeshRenderer>();
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<MeshFilter>().sharedMesh = mf.sharedMesh;
go.AddComponent<MeshFilter>().sharedMesh = mesh;
_outlineMesh = go.AddComponent<MeshRenderer>();
_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<MeshRenderer>(); if (mr != null) mr.enabled = true;
foreach (var r in GetComponentsInChildren<Renderer>(true)) r.enabled = true; // 显示模型
foreach (var r in GetComponentsInChildren<Renderer>(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<MeshRenderer>(); if (mr != null) mr.enabled = false;
var smr = GetComponent<SkinnedMeshRenderer>(); if (smr != null) smr.enabled = false;
foreach (var r in GetComponentsInChildren<Renderer>(true)) { if (_outlineMesh != null && r == _outlineMesh) continue; r.enabled = false; }
if (_outlineMesh != null) _outlineMesh.enabled = true;
StopAllCoroutines();
StartCoroutine(BlinkOutline());
}
}
+1 -1
View File
@@ -2,5 +2,5 @@ using UnityEngine;
public static class OutlineConfig
{
public static float Width = 0.15f;
public static float Width = 2.0f;
}
+67 -4
View File
@@ -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<Collider>() == null) gameObject.AddComponent<SphereCollider>().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<MeshFilter>().sharedMesh = mf.sharedMesh;
_outlineMesh = go.AddComponent<MeshRenderer>();
_outlineMesh.material = mat;
@@ -47,6 +52,11 @@ public class PingClickHandler : MonoBehaviour
}
void OnMouseDown()
{
PerformClick();
}
public void PerformClick()
{
foreach (var c in Object.FindObjectsOfType<Camera>())
{
@@ -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<Renderer>(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<PingClickHandler>();
foreach (var p in allPings)
{
p.ReEnableBorder();
}
Debug.Log($"[PingClick] {name} 是最后一个 ping,所有边框已重新激活!");
}
Debug.Log($"[PingClick] {name} 模型显示, 激活 {nextPing?.name}");
var sm = FindObjectOfType<StepManager>();
if (sm != null) sm.RecordPingStep(pingIndex, false);
@@ -73,10 +95,51 @@ public class PingClickHandler : MonoBehaviour
gameObject.SetActive(false);
var sm = FindObjectOfType<StepManager>();
if (sm != null) sm.RecordPingStep(pingIndex, true);
// 判断是否是真正的最后一步:检查所有的 PingClickHandler,看是否还有 activeInHierarchy 的。
// 注意当前 gameObject 刚刚被 SetActive(false),所以 FindObjectsOfType 获取不到当前的对象了。
var remainingPings = Object.FindObjectsOfType<PingClickHandler>();
int activePingCount = 0;
foreach (var p in remainingPings)
{
if (p.gameObject.activeInHierarchy) activePingCount++;
}
if (activePingCount == 0)
{
Debug.Log("[PingClick] 所有的 ping 都已经绑成 chanrao 了!播放完成语音。");
var am = FindObjectOfType<AudioManager>();
if (am != null)
{
#if UNITY_EDITOR
var finishClip = UnityEditor.AssetDatabase.LoadAssetAtPath<AudioClip>("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<Renderer>(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<Renderer>(true)) { if (_outlineMesh != null && r == _outlineMesh) continue; r.enabled = false; }
if (_outlineMesh != null) _outlineMesh.enabled = true;
StopAllCoroutines();
StartCoroutine(BlinkOutline());
}
}
+110 -6
View File
@@ -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<SphereCollider>());
var col = GetComponent<BoxCollider>();
if (col == null) col = gameObject.AddComponent<BoxCollider>();
// 按 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<Collider>() == null) gameObject.AddComponent<SphereCollider>().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<MeshFilter>().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<Animator>();
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<Animator>();
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<AudioManager>();
if (am != null)
{
#if UNITY_EDITOR
var fractureClip = UnityEditor.AssetDatabase.LoadAssetAtPath<AudioClip>("Assets/Audio/people/伤员左大腿疑似骨折,无伤口.mp3");
if (fractureClip != null) am.PlayVoice(fractureClip);
#endif
}
}
// 切换到摄像机3
var audioManager = FindObjectOfType<AudioManager>();
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");
}
}
}
@@ -16,7 +16,6 @@ public class TouchPositionHandler : MonoBehaviour
private void Start()
{
_meshRenderer = GetComponent<MeshRenderer>();
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);
+129 -13
View File
@@ -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<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; }
@@ -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<AudioManager>();
if (am != null) {
#if UNITY_EDITOR
var autoClip = UnityEditor.AssetDatabase.LoadAssetAtPath<AudioClip>("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<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 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(false);
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} 秒以切换摄像机并激活鞋子");
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
}
+27 -20
View File
@@ -105,7 +105,7 @@ public class UIManager : MonoBehaviour
var btn = btnFS.GetComponent<Button>();
if (btn != null)
{
btn.onClick.AddListener(ToggleFullScreen);
btn.onClick.RemoveListener(ToggleFullScreen); btn.onClick.AddListener(ToggleFullScreen);
Debug.Log("UIManager: Navbar/FullScreen 绑定成功 -> ToggleFullScreen");
}
}
@@ -118,7 +118,7 @@ public class UIManager : MonoBehaviour
var btn = btnPrev.GetComponent<Button>();
if (btn != null)
{
btn.onClick.AddListener(OnPreviousClicked);
btn.onClick.RemoveListener(OnPreviousClicked); btn.onClick.AddListener(OnPreviousClicked);
Debug.Log("UIManager: Navbar/Previous 绑定成功 -> OnPreviousClicked");
}
}
@@ -131,7 +131,7 @@ public class UIManager : MonoBehaviour
var btn = btnNext.GetComponent<Button>();
if (btn != null)
{
btn.onClick.AddListener(OnNextClicked);
btn.onClick.RemoveListener(OnNextClicked); btn.onClick.AddListener(OnNextClicked);
Debug.Log("UIManager: Navbar/Next 绑定成功 -> OnNextClicked");
}
}
@@ -144,7 +144,7 @@ public class UIManager : MonoBehaviour
var btn = btnMode.GetComponent<Button>();
if (btn != null)
{
btn.onClick.AddListener(OnSwitchModeClicked);
btn.onClick.RemoveListener(OnSwitchModeClicked); btn.onClick.AddListener(OnSwitchModeClicked);
Debug.Log("UIManager: Navbar/PracticeMode 绑定成功 -> OnSwitchModeClicked");
}
}
@@ -157,7 +157,7 @@ public class UIManager : MonoBehaviour
var btn = btnBack.GetComponent<Button>();
if (btn != null)
{
btn.onClick.AddListener(OnReturnClicked);
btn.onClick.RemoveListener(OnReturnClicked); btn.onClick.AddListener(OnReturnClicked);
Debug.Log("UIManager: Navbar/BtnBack 绑定成功 -> OnReturnClicked");
}
}
@@ -186,11 +186,11 @@ public class UIManager : MonoBehaviour
private void BindButtons()
{
if (_btnFullScreen != null) { _btnFullScreen.onClick.AddListener(ToggleFullScreen); Debug.Log("UIManager: _btnFullScreen 绑定成功"); }
if (_btnPrevious != null) { _btnPrevious.onClick.AddListener(OnPreviousClicked); Debug.Log("UIManager: _btnPrevious 绑定成功"); }
if (_btnNext != null) { _btnNext.onClick.AddListener(OnNextClicked); Debug.Log("UIManager: _btnNext 绑定成功"); }
if (_btnSwitchMode != null) { _btnSwitchMode.onClick.AddListener(OnSwitchModeClicked); Debug.Log("UIManager: _btnSwitchMode 绑定成功"); }
if (_btnReturn != null) { _btnReturn.onClick.AddListener(OnReturnClicked); Debug.Log("UIManager: _btnReturn 绑定成功"); }
if (_btnFullScreen != null) { _btnFullScreen.onClick.RemoveListener(ToggleFullScreen); _btnFullScreen.onClick.AddListener(ToggleFullScreen); Debug.Log("UIManager: _btnFullScreen 绑定成功"); }
if (_btnPrevious != null) { _btnPrevious.onClick.RemoveListener(OnPreviousClicked); _btnPrevious.onClick.AddListener(OnPreviousClicked); Debug.Log("UIManager: _btnPrevious 绑定成功"); }
if (_btnNext != null) { _btnNext.onClick.RemoveListener(OnNextClicked); _btnNext.onClick.AddListener(OnNextClicked); Debug.Log("UIManager: _btnNext 绑定成功"); }
if (_btnSwitchMode != null) { _btnSwitchMode.onClick.RemoveListener(OnSwitchModeClicked); _btnSwitchMode.onClick.AddListener(OnSwitchModeClicked); Debug.Log("UIManager: _btnSwitchMode 绑定成功"); }
if (_btnReturn != null) { _btnReturn.onClick.RemoveListener(OnReturnClicked); _btnReturn.onClick.AddListener(OnReturnClicked); Debug.Log("UIManager: _btnReturn 绑定成功"); }
// 注意: _btnLimbFixation/_btnSplintFixation 不再在这里绑定 SwitchFixation
// 固定方式选择由 PageController 的 OnFixationSelected 统一处理,避免双重触发污染 StepManager 状态。
@@ -247,12 +247,12 @@ public class UIManager : MonoBehaviour
private void UpdateNavigationButtons()
{
if (_stepManager == null) return;
if (_btnPrevious != null) _btnPrevious.interactable = _stepManager.CurrentStepIndex > 0;
if (_btnPrevious != null) _btnPrevious.interactable = true;
if (_btnNext != null)
{
var label = _btnNext.GetComponentInChildren<Text>();
bool isLast = _stepManager.CurrentStepIndex >= _stepManager.TotalSteps - 1;
if (label != null) label.text = isLast ? "完成" : "下一步";
if (label != null) label.text = "下一步";
}
}
@@ -299,15 +299,15 @@ public class UIManager : MonoBehaviour
Debug.Log($"UIManager: [ToggleFullScreen] 全屏 = {Screen.fullScreen}");
}
private void OnPreviousClicked()
{
Debug.Log("UIManager: [OnPreviousClicked] -> 上一步");
_stepManager?.PreviousStep();
}
private void OnNextClicked()
{
Debug.Log("UIManager: [OnNextClicked] -> 下一步");
Debug.LogError("====== UIManager: 点击了【下一步】按钮! ======");
if (_stepManager == null)
{
_stepManager = FindObjectOfType<StepManager>();
Debug.LogError($"====== UIManager: 重新寻找 StepManager 结果: {_stepManager != null} ======");
}
if (_stepManager != null && _stepManager.Mode == ExperimentMode.Exam)
{
var step = _stepManager.GetCurrentStep();
@@ -317,6 +317,13 @@ public class UIManager : MonoBehaviour
_stepManager?.NextStep();
}
private void OnPreviousClicked()
{
Debug.LogError("====== UIManager: 点击了【上一步】按钮! ======");
if (_stepManager == null) _stepManager = FindObjectOfType<StepManager>();
_stepManager?.PreviousStep();
}
private void OnSwitchModeClicked()
{
if (_stepManager == null) return;