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

如何让OnGUI窗口阻止鼠标点击穿透至Canvas?

解决OnGUI窗口悬停时阻止Canvas接收鼠标点击的方案

我来帮你搞定这个问题!既然你只能在运行时修改Canvas和输入逻辑,那我们可以结合OnGUI的事件检测和CanvasGroup的射线控制来实现需求,具体步骤和代码如下:

核心思路

  1. 记录OnGUI窗口的实时位置和大小,判断鼠标是否悬停在窗口范围内。
  2. 当鼠标在窗口上时,消耗鼠标事件阻止后续传递,同时禁用Canvas的射线检测,确保Canvas上的UI不会响应点击;鼠标离开时恢复正常。

完整实现代码

using UnityEngine;

public class GuiWindowCanvasBlocker : MonoBehaviour
{
    // 初始窗口位置和大小,可根据需求调整
    private Rect _guiWindowRect = new Rect(100, 100, 250, 180);
    private CanvasGroup _targetCanvasGroup;

    void Start()
    {
        // 运行时找到目标Canvas(如果有多个Canvas,建议通过tag或直接引用指定)
        Canvas targetCanvas = FindObjectOfType<Canvas>();
        if (targetCanvas != null)
        {
            // 动态添加CanvasGroup(如果没有的话),因为只能运行时修改
            _targetCanvasGroup = targetCanvas.GetComponent<CanvasGroup>();
            if (_targetCanvasGroup == null)
            {
                _targetCanvasGroup = targetCanvas.gameObject.AddComponent<CanvasGroup>();
            }
            // 默认允许Canvas接收射线检测
            _targetCanvasGroup.blocksRaycasts = true;
        }
    }

    void OnGUI()
    {
        // 绘制OnGUI窗口,并保存其实时Rect(窗口拖动后位置会更新)
        _guiWindowRect = GUI.Window(0, _guiWindowRect, DrawWindowContent, "悬浮拦截窗口");

        // 检测鼠标是否在OnGUI窗口范围内
        bool isMouseOverWindow = _guiWindowRect.Contains(Event.current.mousePosition);

        if (isMouseOverWindow)
        {
            // 消耗当前鼠标事件(点击、抬起等),阻止EventSystem处理
            if (Event.current.type is EventType.MouseDown or EventType.MouseUp or EventType.MouseDrag)
            {
                Event.current.Use();
            }
            // 禁用Canvas的射线检测,双重保障
            if (_targetCanvasGroup != null)
            {
                _targetCanvasGroup.blocksRaycasts = false;
            }
        }
        else
        {
            // 鼠标离开窗口,恢复Canvas的射线检测
            if (_targetCanvasGroup != null)
            {
                _targetCanvasGroup.blocksRaycasts = true;
            }
        }
    }

    // OnGUI窗口的内容绘制函数
    void DrawWindowContent(int windowID)
    {
        GUI.Label(new Rect(20, 40, 210, 30), "鼠标悬停在此处时,Canvas将无法接收点击");
        // 允许拖动窗口(可选,不需要可以删除)
        GUI.DragWindow(new Rect(0, 0, float.MaxValue, 20));
    }
}

关键细节说明

  • CanvasGroup的作用:通过blocksRaycasts属性可以快速启用/禁用整个Canvas的射线检测,这是运行时修改Canvas输入响应最便捷的方式。
  • Event.current.Use():这个方法会消耗当前的Unity事件,让后续的事件处理(比如UGUI的EventSystem)无法接收到该事件,避免出现漏网的点击。
  • 窗口位置更新:GUI.Window的返回值会记录窗口的实时位置(包括拖动后的位置),所以我们能准确判断鼠标是否在窗口内。

把这个脚本挂载到任意GameObject上,运行游戏后,当鼠标悬停在OnGUI窗口上时,Canvas上的按钮、输入框等UI就不会响应点击了,完全符合你的需求!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:57:39