Replace OnMouseDown with Physics.RaycastAll in Update for guaranteed click penetration

This commit is contained in:
yangbear
2026-07-12 04:07:20 +08:00
parent 1afc770eef
commit 51fe94b3e1
+26 -28
View File
@@ -21,27 +21,11 @@ public class PingClickHandler : MonoBehaviour
{
col = gameObject.AddComponent<SphereCollider>();
}
// 强行把碰撞体的世界大小固定在一个比较合适的尺寸(比如世界尺寸 0.15)
// 注意:父级如果在很远的层级里存在极端缩放,这里直接算可能还会出问题
// 所以我们加一个更保守的安全保障:无论算出什么比例,绝对物理半径不能低于 0.05,不能高于 5.0
float scale = Mathf.Max(Mathf.Abs(transform.lossyScale.x), Mathf.Abs(transform.lossyScale.y), Mathf.Abs(transform.lossyScale.z), 0.001f);
if (col is SphereCollider sphere)
{
float targetRadius = 0.3f / scale;
// 如果缩放太小,导致计算出的局部半径极大,或者缩放太大导致半径极小,我们要Clamp住它
// 以保证在 Scene/Game 视窗里它至少是个“可以点得到的球”
sphere.radius = Mathf.Clamp(targetRadius, 0.05f, 20f);
Debug.Log($"[PingClick] {name} 设置了碰撞体半径: {sphere.radius} (基于缩放 {scale})");
float scale = Mathf.Max(Mathf.Abs(transform.lossyScale.x), Mathf.Abs(transform.lossyScale.y), Mathf.Abs(transform.lossyScale.z), 0.001f);
sphere.radius = Mathf.Clamp(0.3f / scale, 0.05f, 20f);
}
else if (col is BoxCollider box)
{
float targetSize = 0.6f / scale;
targetSize = Mathf.Clamp(targetSize, 0.1f, 40f);
box.size = new Vector3(targetSize, targetSize, targetSize);
}
col.enabled = true;
CreateOutlineMesh();
@@ -78,21 +62,35 @@ public class PingClickHandler : MonoBehaviour
while (true) { if (_outlineMesh != null) _outlineMesh.enabled = !_outlineMesh.enabled; yield return new WaitForSeconds(0.4f); }
}
void OnMouseDown()
// 弃用 Unity 自带的 OnMouseDown,因为它只能检测最外层第一个碰到的物体,会被前面的隐形物体挡住
void Update()
{
Debug.Log($"[PingClick] 接收到鼠标点击: {name}");
PerformClick();
if (Input.GetMouseButtonDown(0))
{
if (!_isBlinking) return;
foreach (var c in Camera.allCameras)
{
if (!c.enabled) continue;
Ray ray = c.ScreenPointToRay(Input.mousePosition);
// 穿透所有物体!
RaycastHit[] hits = Physics.RaycastAll(ray, 1000f);
foreach (var hit in hits)
{
if (hit.collider != null && hit.collider.gameObject == gameObject)
{
Debug.Log($"[PingClick] Update全穿透射线成功点中: {name}");
PerformClick();
return; // 已经处理点击,退出
}
}
}
}
}
public void PerformClick()
{
if (!_isBlinking)
{
Debug.Log($"[PingClick] {name} 忽略点击,因为 _isBlinking=false");
return;
}
// 不做任何射线遮挡判定!直接穿透触发点击,确保 100% 成功!
if (!_isBlinking) return;
if (!_modelShown)
{