鼠标移入屏蔽穿透UI

本文介绍了一个Unity中用于检测用户输入是否覆盖UI元素的实用脚本。该脚本提供了三种方法来判断触摸或鼠标指针是否位于UI对象之上,包括通过EventSystem、屏幕坐标和特定画布组件。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class ShieldUIOver
{

    public static ShieldUIOver Instance = new ShieldUIOver();

    public ShieldUIOver()
    { }

   /// <summary>
   /// 传入手指ID
   /// </summary>
   /// <param name="fingerID"></param>
   /// <returns></returns>
    public bool IsPointerOverUIObject(int fingerID)
    {
        return EventSystem.current.IsPointerOverGameObject(fingerID);
    }


    /// <summary>
    ///相机有Physics Raycaster组件 通过EventSystem  可以检测到UI,3D物体
    ///没有Physics Raycaster组件 通过EventSystem 只可以检测到UI
    /// 如果Physics Raycaster组件 可以考虑选择是否要过滤3D物体
    /// </summary>
    /// <param name="screenPosition"></param>
    /// <returns></returns>
    public bool IsPointerOverUIObject(Vector2 screenPosition)
    {
        //实例化点击事件
        PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
        //将点击位置的屏幕坐标赋值给点击事件
        eventDataCurrentPosition.position = new Vector2(screenPosition.x, screenPosition.y);

        List<RaycastResult> results = new List<RaycastResult>();


        //向点击处发射射线
        EventSystem.current.RaycastAll(eventDataCurrentPosition, results);

        //TODO: 下面是检测到UI后屏蔽向下传递的事件,只检测UI
        //for (int i=results.Count-1;i>=0; i-- )
        //{
        //    Debug.LogError(results[i].gameObject.name);
        //     if (results[i].gameObject.layer==LayerMask.NameToLayer("Default"))
        //     {
        //        results.RemoveAt(i);
        //     }
        //}
        //Debug.Log(results.Count);
        return results.Count > 0;
    }

    /// <summary>
    /// 通过画布上的 GraphicRaycaster 组件发射射线
    /// 只会检测到UI,不会检测到3D物体
    /// </summary>
    /// <param name="canvas"></param>
    /// <param name="screenPosition"></param>
    /// <returns></returns>
    public bool IsPointerOverUIObject(Canvas canvas, Vector2 screenPosition)
    {
        //实例化点击事件
        PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
        //将点击位置的屏幕坐标赋值给点击事件
        eventDataCurrentPosition.position = screenPosition;
        //获取画布上的 GraphicRaycaster 组件
        GraphicRaycaster uiRaycaster = canvas.gameObject.GetComponent<GraphicRaycaster>();

        List<RaycastResult> results = new List<RaycastResult>();
        // GraphicRaycaster 发射射线
        uiRaycaster.Raycast(eventDataCurrentPosition, results);

        return results.Count > 0;
    }
}




测试脚本
public class TestEvent : MonoBehaviour {

// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {
    //EventSystem 传递坐标
    if (ShieldUIOver.Instance.IsPointerOverUIObject(Input.mousePosition))
    {
        Debug.Log("方法二: 点击在UI 上");
    }

    //画布组件,传递坐标
    if (ShieldUIOver.Instance.IsPointerOverUIObject(GetComponent<Canvas>(), Input.mousePosition))
    {
        Debug.Log("方法三: 点击在UI 上");
    }
}
在Unity中实现鼠标悬停UI显示文字的功能时,如果遇到UI穿透导致鼠标可以与3D物体交互的问题,可以通过以下方法解决交互冲突: 1. **使用 `EventTrigger` 或 `OnPointerEnter`/`OnPointerExit` 事件** Unity的UI系统提供了 `EventTrigger` 组件,可以用来监听鼠标悬停事件。通过在UI对象上添加该组件并绑定 `OnPointerEnter` 和 `OnPointerExit` 事件,可以在鼠标进入或离开UI时触发显示或隐藏文字的操作。同时,这些事件可以确保UI拦截鼠标输入,避免穿透到3D物体上[^3]。 2. **启用 `Canvas` 的 `Raycast Target` 属性** 在UI元素的 `Image` 或 `Text` 组件中,确保启用了 `Raycast Target` 选项。这样,UI对象会成为射线检测的目标,从而阻止射线穿透到3D场景中。这是防止UI穿透的基本设置之一[^1]。 3. **使用 `GraphicRaycaster` 控制UI的射线检测行为** `Canvas` 上的 `GraphicRaycaster` 组件负责处理UI的射线检测。通过脚本动态启用或禁用该组件,可以控制UI是否响应鼠标事件。例如,在显示提示文字时启用 `GraphicRaycaster`,在隐藏文字时禁用它,从而防止UI穿透。 4. **调整 `Canvas` 的渲染模式** 如果UI是3D场景中的一部分,建议将 `Canvas` 的渲染模式设置为 `World Space`,而不是 `Screen Space - Overlay`。这样可以更精确地控制UI的位置和交互逻辑,同时避免UI始终位于摄像机前方的问题[^2]。 5. **使用 `Physics.Raycast` 进行手动检测** 在某些复杂场景中,可能需要手动控制射线检测逻辑。例如,在鼠标悬停UI时,暂时禁用对3D物体的射线检测,或者优先检测UI对象。通过在代码中控制射线检测的顺序,可以确保UI交互优先于3D物体的交互。 6. **结合 `CanvasGroup` 控制交互状态** 使用 `CanvasGroup` 组件可以动态调整UI的透明度和交互状态。例如,在悬停UI时,将 `CanvasGroup.blocksRaycasts` 设置为 `true`,确保UI拦截鼠标事件;在不需要交互时设置为 `false`,允许射线穿透[^3]。 ### 示例代码 以下是一个简单的脚本示例,展示如何在鼠标悬停UI时显示文字并阻止UI穿透: ```csharp using UnityEngine; using UnityEngine.UI; public class TooltipHandler : MonoBehaviour { [SerializeField] private Text tooltipText; private CanvasGroup canvasGroup; void Start() { canvasGroup = GetComponent<CanvasGroup>(); tooltipText.gameObject.SetActive(false); } public void OnPointerEnter() { tooltipText.gameObject.SetActive(true); canvasGroup.blocksRaycasts = true; // 阻止射线穿透 } public void OnPointerExit() { tooltipText.gameObject.SetActive(false); canvasGroup.blocksRaycasts = false; // 允许射线穿透 } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tianyongheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值