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

如何检测鼠标光标与含Image组件的UI容器GameObject的交集?

解决方案:基于EventSystem射线检测实现容器级悬停判断

刚好之前做UI的时候碰到过类似的需求,不用给每个Image单独挂脚本,用Unity的EventSystem做射线检测就能轻松解决,给你整理了两种实现方式,都只需要一个脚本:

核心思路

利用EventSystem的UI射线检测功能,获取鼠标当前位置下所有被命中的UI元素,然后遍历这些元素,检查它们是否是目标容器的子对象(且带有Image组件)。只要有任意一个符合条件,就判定鼠标悬停在容器的Image上。

代码实现(基础版)

这个脚本可以挂载在任意GameObject上(比如Canvas、专门的UI管理对象),只需要指定目标容器即可:

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;

public class ContainerHoverChecker : MonoBehaviour
{
    [Tooltip("需要检测的UI容器对象")]
    public GameObject targetContainer;
    private PointerEventData _pointerEventData;
    private List<RaycastResult> _raycastResults = new List<RaycastResult>();

    private void Update()
    {
        // 确保EventSystem和目标容器存在
        if (EventSystem.current == null || targetContainer == null)
            return;

        // 初始化鼠标位置的PointerEventData
        _pointerEventData = new PointerEventData(EventSystem.current);
        _pointerEventData.position = Input.mousePosition;

        // 清空之前的检测结果,执行射线检测
        _raycastResults.Clear();
        EventSystem.current.RaycastAll(_pointerEventData, _raycastResults);

        bool isHovering = false;
        foreach (var result in _raycastResults)
        {
            // 检查命中对象是否是容器的子对象,且带有Image组件
            if (result.gameObject.transform.IsChildOf(targetContainer.transform) 
                && result.gameObject.TryGetComponent(out Image _))
            {
                isHovering = true;
                break; // 命中一个符合条件的就可以停止遍历
            }
        }

        // 这里替换成你的悬停逻辑
        if (isHovering)
        {
            Debug.Log("鼠标悬停在容器的Image上啦");
            // 比如高亮容器、显示提示等操作
        }
        else
        {
            Debug.Log("鼠标不在容器的Image范围内");
        }
    }
}

优化版(减少GC开销)

如果你的项目对性能要求较高,RaycastAll每次会生成新的列表,可能产生GC。可以改用RaycastAllNonAlloc,预先分配数组来避免这个问题:

using UnityEngine;
using UnityEngine.EventSystems;

public class ContainerHoverChecker : MonoBehaviour
{
    [Tooltip("需要检测的UI容器对象")]
    public GameObject targetContainer;
    private PointerEventData _pointerEventData;
    // 预先分配数组,长度根据你的UI数量调整,足够容纳可能的命中结果即可
    private RaycastResult[] _raycastResults = new RaycastResult[15];

    private void Update()
    {
        if (EventSystem.current == null || targetContainer == null)
            return;

        _pointerEventData = new PointerEventData(EventSystem.current);
        _pointerEventData.position = Input.mousePosition;

        // 获取射线检测结果的数量,不会分配新数组
        int hitCount = EventSystem.current.RaycastAllNonAlloc(_pointerEventData, _raycastResults);
        bool isHovering = false;

        for (int i = 0; i < hitCount; i++)
        {
            var result = _raycastResults[i];
            if (result.gameObject.transform.IsChildOf(targetContainer.transform) 
                && result.gameObject.TryGetComponent(out Image _))
            {
                isHovering = true;
                break;
            }
        }

        // 悬停逻辑同上
        if (isHovering)
        {
            Debug.Log("鼠标悬停在容器的Image上");
        }
    }
}

注意事项

  • 确保容器内的Image组件的raycastTarget属性为true,否则射线检测不会命中这些Image。如果某些Image不需要响应点击,但需要检测悬停,保持raycastTarget=true即可,不影响其他逻辑。
  • 如果不需要限制只检测Image,只需要删除判断条件里的&& result.gameObject.TryGetComponent(out Image _),这样容器内所有UI元素都会被纳入检测范围。
  • 这个脚本不需要挂载在目标容器上,放在任意管理对象上都可以,非常灵活。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:39:23