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

Unity如何检测UIVertex绘制的UI线条的点击事件

Unity UGUI自定义线条点击检测实现方案

你当前采用连续四边形拼接的方式绘制宽线条,默认Graphic组件的矩形射线检测只能命中整个UI的包围盒,无法精确匹配线条形状,以下是三种经过生产环境验证的可行方案,按推荐优先级排序:


方案1:实现ICanvasRaycastFilter自定义精确命中(最推荐,性能最优)

这个方案完全贴合UGUI事件系统逻辑,不需要额外组件,性能开销极低。

  • 绘制线条时不要仅往VertexHelper传顶点,同步保存所有线段的基础数据:每两个相邻采样点组成一个线段段,记录段的起点、终点本地坐标,以及绘制时使用的thickness值。
  • 给挂载自定义线条脚本的Graphic组件实现ICanvasRaycastFilter接口,重写IsRaycastLocationValid方法,在方法内把点击的屏幕坐标转成UI本地坐标,逐段判断点是否在线条的厚度范围内。
  • 命中判断逻辑:计算点击位置到线段的垂直距离,若距离小于等于线条半厚,且点在线段两端的投影区间内,就判定为命中。

核心判断代码参考:

// 绘制时同步存储的线段结构
private struct LineSegment
{
    public Vector2 startLocalPos;
    public Vector2 endLocalPos;
}
private readonly List<LineSegment> _cachedSegments = new List<LineSegment>();

public bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
    // 将点击屏幕坐标转换为UI物体的本地坐标
    if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
        rectTransform, screenPoint, eventCamera, out Vector2 localHitPos))
        return false;

    float hitThreshold = thickness * 0.5f;
    foreach (var seg in _cachedSegments)
    {
        Vector2 segDir = seg.endLocalPos - seg.startLocalPos;
        float segLength = segDir.magnitude;
        segDir.Normalize();
        
        Vector2 startToHit = localHitPos - seg.startLocalPos;
        float projection = Vector2.Dot(startToHit, segDir);
        // 投影超出线段首尾范围,跳过该段
        if (projection < 0 || projection > segLength) continue;
        // 计算点到线段的垂直距离
        float verticalDistance = Mathf.Abs(Vector2.Cross(segDir, startToHit));
        if (verticalDistance <= hitThreshold)
        {
            return true;
        }
    }
    return false;
}

方案2:挂载碰撞体适配物理射线检测(无需手写命中逻辑)

如果不想自己实现几何判断逻辑,可以用碰撞体匹配线条形状:

  • 每次顶点重建完成后,逐段生成对应尺寸的BoxCollider2D:每个Box的长度对应当前段两个采样点的距离,宽度对应线条thickness,位置放在线段中点,旋转角度和绘制顶点时计算的angle一致,挂载在线条物体的子节点上。
  • 给线条物体挂载Physics2DRaycaster组件,就能正常响应UGUI的点击事件,不需要自己写坐标转换逻辑。
  • 缺点是线段段数过多时(比如超过1000段),碰撞体的运行时开销会明显高于方案1。

方案3:利用alpha阈值命中(实现最快,内存开销高)

适合线条不常更新、总长度较短的场景:

  • 给自定义Graphic组件指定一张全不透明的单像素Sprite作为主纹理,绘制顶点时把所有顶点的UV对齐到这张Sprite的不透明区域。
  • 给组件设置alphaHitTestMinimumThreshold = 0.5f,UGUI射线检测时会自动采样纹理对应位置的alpha值,只有不透明区域会判定命中。
  • 缺点是需要开启组件的read/write纹理权限,长线条需要的纹理分辨率高,内存占用大,频繁重绘时性能差。

注意:不要直接使用默认的Graphic射线检测,默认逻辑只会判断点击点是否落在RectTransform的矩形包围盒内,线条外的大量空白区域都会被误判为命中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 03:33:33