using UnityEngine; public class PingClickHandler : MonoBehaviour { public GameObject chanraoObject, nextPing; public int pingIndex; private MeshRenderer _modelRenderer, _outlineMesh; private bool _modelShown; private bool _isBlinking; public bool CanBeClicked() { return _isBlinking; } void OnEnable() { _modelRenderer = GetComponent(); if (_modelRenderer == null) _modelRenderer = GetComponentInChildren(); foreach (var r in GetComponentsInChildren(true)) r.enabled = false; // 确保碰撞体是打开的 var col = GetComponent(); if (col == null) { var sphere = gameObject.AddComponent(); sphere.radius = 0.5f; // 可以适当增加,保证能点到 col = sphere; } else if (col is BoxCollider bc) { // 如果是之前的 BoxCollider,把它改大一点,确保能点到 bc.size = new Vector3(Mathf.Max(bc.size.x, 0.8f), Mathf.Max(bc.size.y, 0.8f), Mathf.Max(bc.size.z, 0.8f)); } else if (col is SphereCollider sc) { sc.radius = Mathf.Max(sc.radius, 0.5f); } col.enabled = true; CreateOutlineMesh(); _modelShown = false; _isBlinking = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } void CreateOutlineMesh() { if (_outlineMesh != null) return; var mf = GetComponent(); if (mf == null) mf = GetComponentInChildren(); if (mf == null || mf.sharedMesh == null) return; var shader = Shader.Find("Custom/OutlineUnlit"); if (shader == null) 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)); 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; } System.Collections.IEnumerator BlinkOutline() { if (_outlineMesh != null) _outlineMesh.enabled = true; yield return new WaitForSeconds(0.4f); while (true) { if (_outlineMesh != null) _outlineMesh.enabled = !_outlineMesh.enabled; yield return new WaitForSeconds(0.4f); } } void OnMouseDown() { PerformClick(); } public void PerformClick() { if (!_isBlinking) return; // 防止重复点击 foreach (var c in Object.FindObjectsOfType()) { if (!c.enabled) continue; foreach (var h in Physics.RaycastAll(c.ScreenPointToRay(Input.mousePosition))) if (h.collider?.transform.parent?.name == "touchArray") return; } if (!_modelShown) { _modelShown = true; _isBlinking = false; ActionHistory.Push(ActionHistory.ActionType.PingFirst, this); 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) // 此时第一阶段结束,激活 chanraotuibu var chanraotuibu = GameObject.Find("chanraotuibu"); if (chanraotuibu == null) { var mi = GameObject.Find("manInjury"); if (mi != null) { var t = mi.transform.Find("chanraotuibu"); if (t != null) chanraotuibu = t.gameObject; } } if (chanraotuibu != null) chanraotuibu.SetActive(true); Debug.Log($"[PingClick] {name} 是最后一个 ping 模型,现已激活 chanraotuibu"); } if (nextPing != null) Debug.Log($"[PingClick] {name} 模型显示, 激活 {nextPing.name}"); else Debug.Log($"[PingClick] {name} 模型显示, 激活下一个"); var sm = FindObjectOfType(); if (sm != null) sm.RecordPingStep(pingIndex, false); } else { if (chanraoObject != null) { chanraoObject.SetActive(true); Debug.Log($"[PingClick] {name} → {chanraoObject.name}"); } HideSelf(); ActionHistory.Push(ActionHistory.ActionType.PingSecond, this); 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) { // In phase 2, finished pings have their collider disabled and _isBlinking set to false. var col = p.GetComponent(); if (col != null && col.enabled) 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 } // 隐藏视频面板 var uiMgr = FindObjectOfType(); if (uiMgr != null) { uiMgr.HideVideo(); } } } } public void ReEnableBorder() { // 关键:在第二阶段被激活时,先检查我们是否已经被完成了 // 只有 _modelShown 为 true,并且没有被最终隐藏时,才能被激活 if (!_modelShown) return; // 如果模型已经被替换成 chanrao 并且隐藏了自己,就不应该再被激活 var col = GetComponent(); if (chanraoObject != null && chanraoObject.activeSelf) { if (col != null) col.enabled = false; return; } _isBlinking = true; // 【关键修复点】:确保即使在第二次激活时,碰撞体也被打开,且如果有的话,保证能被点到。 if (col != null) col.enabled = true; if (_outlineMesh != null) { _outlineMesh.enabled = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } } public void DisableBorder() { _isBlinking = false; if (_outlineMesh != null) _outlineMesh.enabled = false; StopAllCoroutines(); } public void UndoSecondClick() { if (chanraoObject != null) chanraoObject.SetActive(false); ShowSelf(); _modelShown = true; _isBlinking = true; if (_outlineMesh != null) _outlineMesh.enabled = true; StopAllCoroutines(); StartCoroutine(BlinkOutline()); } public void UndoShow() { _modelShown = false; _isBlinking = false; StopAllCoroutines(); if (chanraoObject != null) chanraoObject.SetActive(false); foreach (var r in GetComponentsInChildren(true)) r.enabled = false; var col = GetComponent(); if (col != null) col.enabled = false; gameObject.SetActive(false); } private void HideSelf() { foreach (var r in GetComponentsInChildren(true)) r.enabled = false; var col = GetComponent(); if (col != null) col.enabled = false; _isBlinking = false; StopAllCoroutines(); } private void ShowSelf() { foreach (var r in GetComponentsInChildren(true)) r.enabled = true; if (_outlineMesh != null) _outlineMesh.enabled = false; var col = GetComponent(); if (col != null) col.enabled = true; } public void ResetState() { _modelShown = false; var col = GetComponent(); if (col != null) col.enabled = true; _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()); } }