Unity3D技术问询:2019.4版本下如何检测鼠标是否点击UI元素?
我之前在Unity 2019.4 LTS项目里也碰到过一模一样的问题——旧的EventSystem.current.IsPointerOverGameObject()调用突然不好使了,点暂停按钮时游戏里的左键逻辑还是会触发,折腾了好一会儿才找到靠谱的替代方案,给你分享两个实用的方法:
方案一:用EventSystem射线检测(最通用)
这个方法是通过手动发射UI射线来判断鼠标是否命中了可交互UI元素,兼容性强,在2019.4及之后的版本都稳定可用。
你可以在InputController里封装一个检测方法,每次处理游戏输入前先调用它:
using UnityEngine; using UnityEngine.EventSystems; public class InputController : MonoBehaviour { private bool IsPointerOverUI() { // 创建PointerEventData,模拟当前鼠标位置的交互事件 PointerEventData eventData = new PointerEventData(EventSystem.current); eventData.position = Input.mousePosition; // 存储射线检测到的UI结果 var results = new RaycastResult[10]; int resultCount = EventSystem.current.RaycastAll(eventData, results); // 如果有命中UI元素,返回true return resultCount > 0; } // 你的输入处理逻辑示例 private void Update() { if (Input.GetMouseButtonDown(0)) { // 先判断是否点击了UI,是则跳过游戏逻辑 if (IsPointerOverUI()) return; // 这里执行你的游戏左键点击逻辑 Debug.Log("触发游戏内左键操作"); } } }
这个方法的好处是不需要修改任何UI元素的代码,直接在输入控制器里统一处理,适合大多数场景。
方案二:通过UI事件标记状态(更精细控制)
如果你的UI有拖拽、长按等复杂交互,或者需要更精准地控制什么时候屏蔽游戏输入,可以维护一个全局状态标记,通过UI的交互事件来更新它:
- 首先创建一个全局的状态管理类(或者直接在InputController里加静态变量):
public static class UIInteractionState { public static bool IsInteractingWithUI { get; set; } }
- 给所有可交互的UI元素(比如Button、Slider、Toggle等)添加一个小脚本,监听PointerDown和PointerUp事件:
using UnityEngine; using UnityEngine.EventSystems; public class UIIntractionMarker : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler { public void OnPointerDown(PointerEventData eventData) { UIInteractionState.IsInteractingWithUI = true; } public void OnPointerUp(PointerEventData eventData) { UIInteractionState.IsInteractingWithUI = false; } public void OnPointerExit(PointerEventData eventData) { // 防止鼠标按住UI后移出,状态没重置 UIInteractionState.IsInteractingWithUI = false; } }
- 然后在InputController里判断这个状态:
private void Update() { if (Input.GetMouseButtonDown(0)) { if (UIInteractionState.IsInteractingWithUI) return; // 执行游戏输入逻辑 } }
这个方案适合需要跟踪UI交互全过程的场景,比如拖拽UI时全程屏蔽游戏输入,体验更流畅。
补充:关于旧方法失效的原因
你提到的EventSystem.current.IsPointerOverGameObject()在2019.4其实并没有完全移除,只是如果你的项目用了新的Input System(而非旧的Input Manager),直接调用无参的重载会失效,这时候需要传入鼠标的pointerId:EventSystem.current.IsPointerOverGameObject(PointerInputModule.kMouseLeftId)。不过这个方法在某些复杂UI层级下偶尔会有检测不准的问题,所以更推荐上面的两种方案。
内容的提问来源于stack exchange,提问作者Neuromante

