You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何检测无Collider组件的2D物体点击?

检测鼠标下方无Collider组件的GameObject方法

因为Unity的Raycast只对带Collider组件的物体生效,要检测无Collider的物体,得换思路,下面是两种实用方案:

方案一:射线遍历检测物体包围盒/网格

遍历场景中所有无Collider的物体,用射线和物体的包围盒、网格做相交判断,适合物体数量不多的场景。

示例代码:

using UnityEngine;
using System.Collections.Generic;

public class MouseOverNoColliderChecker : MonoBehaviour
{
    void Update()
    {
        Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
        List<GameObject> targetObjects = new List<GameObject>();

        // 遍历所有激活的GameObject
        foreach (GameObject obj in GameObject.FindObjectsOfType<GameObject>())
        {
            // 跳过带Collider的物体
            if (obj.GetComponent<Collider>() != null) continue;
            if (!obj.activeInHierarchy) continue;

            // 先通过包围盒快速筛选
            Renderer objRenderer = obj.GetComponent<Renderer>();
            if (objRenderer != null && objRenderer.bounds.IntersectRay(mouseRay))
            {
                // 可选:用网格三角形做精确检测,避免包围盒误判
                MeshFilter meshFilter = obj.GetComponent<MeshFilter>();
                if (meshFilter != null && IsRayHitMesh(mouseRay, meshFilter))
                {
                    targetObjects.Add(obj);
                }
            }
        }

        // 输出检测结果
        if (targetObjects.Count > 0)
        {
            Debug.Log("鼠标下方无Collider的物体:");
            foreach (var target in targetObjects)
            {
                Debug.Log(target.name);
            }
        }
    }

    // 射线与网格三角形相交的精确检测
    bool IsRayHitMesh(Ray ray, MeshFilter meshFilter)
    {
        Mesh mesh = meshFilter.mesh;
        Transform objTrans = meshFilter.transform;

        for (int i = 0; i < mesh.triangles.Length; i += 3)
        {
            Vector3 v0 = objTrans.TransformPoint(mesh.vertices[mesh.triangles[i]]);
            Vector3 v1 = objTrans.TransformPoint(mesh.vertices[mesh.triangles[i + 1]]);
            Vector3 v2 = objTrans.TransformPoint(mesh.vertices[mesh.triangles[i + 2]]);

            if (CheckRayTriangleIntersection(ray, v0, v1, v2))
            {
                return true;
            }
        }
        return false;
    }

    // 射线与三角形相交的基础算法
    bool CheckRayTriangleIntersection(Ray ray, Vector3 v0, Vector3 v1, Vector3 v2)
    {
        Vector3 edge1 = v1 - v0;
        Vector3 edge2 = v2 - v0;
        Vector3 rayCrossEdge2 = Vector3.Cross(ray.direction, edge2);
        float dotValue = Vector3.Dot(edge1, rayCrossEdge2);

        if (dotValue > -Mathf.Epsilon && dotValue < Mathf.Epsilon)
            return false;

        float invDot = 1f / dotValue;
        Vector3 rayToV0 = ray.origin - v0;
        float u = invDot * Vector3.Dot(rayToV0, rayCrossEdge2);

        if (u < 0f || u > 1f)
            return false;

        Vector3 rayToV0CrossEdge1 = Vector3.Cross(rayToV0, edge1);
        float v = invDot * Vector3.Dot(ray.direction, rayToV0CrossEdge1);

        if (v < 0f || u + v > 1f)
            return false;

        float t = invDot * Vector3.Dot(edge2, rayToV0CrossEdge1);
        return t > Mathf.Epsilon;
    }
}

注意:如果场景物体数量多,直接遍历会导致卡顿,建议优化:只检测特定Layer的物体,或者用空间划分(如八叉树)减少遍历范围。

方案二:临时添加Collider再检测

给无Collider的物体临时添加Collider,用Raycast检测后再移除,适合偶尔触发的检测场景。

示例代码:

using UnityEngine;
using System.Collections.Generic;

public class TempColliderMouseCheck : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hitInfo;

            // 存储临时添加的Collider和对应物体
            List<(GameObject obj, Collider tempCol)> tempColliders = new List<(GameObject, Collider)>();

            // 给无Collider的物体加临时MeshCollider
            foreach (GameObject obj in GameObject.FindObjectsOfType<GameObject>())
            {
                if (obj.GetComponent<Collider>() == null && obj.GetComponent<Renderer>() != null)
                {
                    MeshCollider tempCol = obj.AddComponent<MeshCollider>();
                    tempCol.convex = true; // 启用凸包确保射线可检测
                    tempColliders.Add((obj, tempCol));
                }
            }

            // 执行射线检测
            if (Physics.Raycast(mouseRay, out hitInfo))
            {
                // 判断是否是临时加的Collider对应的物体
                var targetEntry = tempColliders.Find(item => item.obj == hitInfo.collider.gameObject);
                if (targetEntry.obj != null)
                {
                    Debug.Log("点击到无Collider的物体:" + targetEntry.obj.name);
                }
            }

            // 清理临时Collider
            foreach (var entry in tempColliders)
            {
                Destroy(entry.tempCol);
            }
        }
    }
}

注意:临时添加Collider有性能开销,频繁调用会卡;MeshCollider的凸包可能和原网格形状有偏差,复杂形状物体可能出现误判。

内容的提问来源于stack exchange,提问作者Black Paint

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:30:43