Fix: each ping does its own closest-check instead of broken global delegate pattern

This commit is contained in:
yangbear
2026-07-12 05:58:22 +08:00
parent 27b64ec49d
commit f4d31f9d69
+22 -67
View File
@@ -50,32 +50,13 @@ public class PingClickHandler : MonoBehaviour
while (true) { if (_outlineMesh != null) _outlineMesh.enabled = !_outlineMesh.enabled; yield return new WaitForSeconds(0.4f); }
}
/// <summary>
/// 全新的点击检测方式:由一个静态方法统一管理,不再依赖碰撞体。
/// 在 Update 里,遍历所有活跃的 PingClickHandler,找到离鼠标最近的那个,只触发它。
/// </summary>
void Update()
{
// 只让 pingIndex 最小的那个实例来做全局检测,避免多个实例重复执行
// 只有正在闪烁的 ping 才参与检测
if (!_isBlinking) return;
// 只有一个实例负责全局判断
var allHandlers = FindObjectsOfType<PingClickHandler>();
bool iAmFirst = true;
foreach (var h in allHandlers)
{
if (!h._isBlinking) continue;
if (h.GetInstanceID() < this.GetInstanceID())
{
iAmFirst = false;
break;
}
}
if (!iAmFirst) return;
if (!Input.GetMouseButtonDown(0)) return;
// 在 UI 上才检测
// 如果点在 UI 上,不处理
if (UnityEngine.EventSystems.EventSystem.current != null &&
UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
return;
@@ -91,36 +72,34 @@ public class PingClickHandler : MonoBehaviour
}
if (activeCamera == null) return;
// 遍历所有正在闪烁的 ping,找到距离鼠标最近的那个
float bestDist = float.MaxValue;
PingClickHandler bestPing = null;
// 计算自己到鼠标的屏幕距离
Vector3 screenPos = activeCamera.WorldToScreenPoint(transform.position);
if (screenPos.z < 0) return; // 在相机背后
Vector2 mousePos = Input.mousePosition;
float myDist = Vector2.Distance(mousePos, new Vector2(screenPos.x, screenPos.y));
// 检查是否有其他正在闪烁的 ping 比我更近
var allHandlers = FindObjectsOfType<PingClickHandler>();
foreach (var h in allHandlers)
{
if (h == this) continue;
if (!h._isBlinking) continue;
if (!h.gameObject.activeInHierarchy) continue;
Vector3 screenPos = activeCamera.WorldToScreenPoint(h.transform.position);
Vector3 otherScreen = activeCamera.WorldToScreenPoint(h.transform.position);
if (otherScreen.z < 0) continue;
// 如果在相机背后,跳过
if (screenPos.z < 0) continue;
float dist = Vector2.Distance(mousePos, new Vector2(screenPos.x, screenPos.y));
if (dist < bestDist)
{
bestDist = dist;
bestPing = h;
}
float otherDist = Vector2.Distance(mousePos, new Vector2(otherScreen.x, otherScreen.y));
if (otherDist < myDist) return; // 别人比我更近,让别人处理
}
// 点击半径阈值:80像素以内算点中(可以根据需要调整)
if (bestPing != null && bestDist < 80f)
// 我是离鼠标最近的闪烁中的 ping
if (myDist < 80f)
{
Debug.Log($"[PingClick] 屏幕坐标命中: {bestPing.name} (距离={bestDist:F1}px)");
bestPing._isBlinking = false;
bestPing.PerformClick();
Debug.Log($"[PingClick] 屏幕坐标命中: {name} (距离={myDist:F1}px)");
_isBlinking = false;
PerformClick();
}
}
@@ -166,38 +145,15 @@ public class PingClickHandler : MonoBehaviour
var sm = FindObjectOfType<StepManager>();
if (sm != null) sm.RecordPingStep(pingIndex, true);
var remainingPings = Object.FindObjectsOfType<PingClickHandler>();
int activePingCount = 0;
foreach (var p in remainingPings)
{
if (p._isBlinking || p._modelShown) activePingCount++;
}
// 自己刚刚隐藏了,所以要减 1 看看还剩几个
// 其实更准确的是检查 collider enabled,但现在我们不用 collider 了
// 直接看有没有剩余的活跃 ping
bool allDone = true;
foreach (var p in Object.FindObjectsOfType<PingClickHandler>())
{
var c = p.GetComponent<Collider>();
// 如果还有没被隐藏的 ping(依然可见),就说明没完
if (p.gameObject.activeInHierarchy && p._modelShown && !p._isBlinking)
{
// 这个 ping 已经完成了第一阶段但还没进入第二阶段
// 不算完成
}
}
// 简单判定:遍历所有的 ping,看看是否还有 collider enabled 的
var pings = Object.FindObjectsOfType<PingClickHandler>();
int remaining = 0;
foreach (var p in pings)
{
var col = p.GetComponent<Collider>();
if (col != null && col.enabled) remaining++;
if (p.gameObject.activeInHierarchy && (p._isBlinking || p._modelShown))
remaining++;
}
if (remaining == 0)
// 自己刚刚 HideSelf 了,如果没有其他活跃的 ping 了
if (remaining <= 1)
{
Debug.Log("[PingClick] 所有的 ping 都已经绑成 chanrao 了!播放完成语音。");
var am = FindObjectOfType<AudioManager>();
@@ -281,7 +237,6 @@ public class PingClickHandler : MonoBehaviour
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; }