Unity UI Toolkit与New Input System输入冲突问题求解
解决Unity UI Toolkit与New Input System的输入冲突问题
核心原因说明
你之前用的EventSystem.current.IsPointerOverGameObject()是UGUI专属API,UI Toolkit有独立的事件系统,所以这个判断完全无效——这是你之前尝试失败的关键。下面是几个针对性的有效方案:
方案1:UI按钮事件中拦截鼠标事件传递
直接在UI按钮的指针事件里阻止事件继续向下传递,让New Input System接收不到鼠标左键的输入:
void Start() { VisualElement menuRoot = GetComponent<UIDocument>().rootVisualElement; Button firstPowerUp = menuRoot.Q<Button>("first_power_up"); // 注册指针按下事件,拦截传递 firstPowerUp.RegisterCallback<PointerDownEvent>(evt => { evt.StopPropagation(); // 阻止事件传递给底层输入系统 }); firstPowerUp.clicked += Perform; } void Perform() { Debug.Log("Clicked on power-up!"); }
PointerDownEvent是UI Toolkit的原生事件,在鼠标按下时触发,调用StopPropagation()后,事件不会再传递给New Input System的鼠标动作。
方案2:在移动输入逻辑中判断是否点击了UI元素
在New Input System的鼠标左键动作回调里,检查当前鼠标位置是否有UI元素被点击,只有没点击UI时才执行移动:
// 假设你的鼠标左键输入动作是mouseLeftClick [SerializeField] private InputAction mouseLeftClick; private VisualElement _uiRoot; void Awake() { _uiRoot = GetComponent<UIDocument>().rootVisualElement; mouseLeftClick.performed += OnMouseLeftClick; } void OnEnable() => mouseLeftClick.Enable(); void OnDisable() => mouseLeftClick.Disable(); private void OnMouseLeftClick(InputAction.CallbackContext context) { // 获取当前鼠标屏幕坐标 Vector2 mouseScreenPos = Mouse.current.position.ReadValue(); // 转换为UI根元素的本地坐标 Vector2 uiLocalPos = _uiRoot.WorldToLocal(mouseScreenPos); // 查找该坐标下的UI元素 VisualElement clickedElement = _uiRoot.ElementAt(uiLocalPos); // 如果没有点击到任何UI元素,才执行移动 if (clickedElement == null) { // 这里写你的物体移动逻辑 Debug.Log("执行物体移动"); } }
方案3:用状态标记区分UI输入与游戏输入
通过一个布尔变量标记当前是否在点击UI,移动逻辑根据这个状态决定是否执行:
private bool _isUIPressed = false; [SerializeField] private InputAction mouseLeftClick; void Start() { VisualElement menuRoot = GetComponent<UIDocument>().rootVisualElement; Button firstPowerUp = menuRoot.Q<Button>("first_power_up"); // 按下按钮时标记状态 firstPowerUp.RegisterCallback<PointerDownEvent>(_ => _isUIPressed = true); // 松开按钮时取消标记 firstPowerUp.RegisterCallback<PointerUpEvent>(_ => _isUIPressed = false); // 点击事件正常保留 firstPowerUp.clicked += Perform; mouseLeftClick.performed += OnMouseLeftClick; } void OnEnable() => mouseLeftClick.Enable(); void OnDisable() => mouseLeftClick.Disable(); private void OnMouseLeftClick(InputAction.CallbackContext context) { if (!_isUIPressed) { // 执行物体移动逻辑 Debug.Log("执行物体移动"); } } void Perform() { Debug.Log("Clicked on power-up!"); }
额外注意点
- UI Toolkit的事件系统和Unity传统
EventSystem完全独立,所有UGUI的事件判断API对它都无效,别再用IsPointerOverGameObject()了。 - 如果有多个UI按钮,建议把UI事件拦截的逻辑封装成通用组件,避免重复代码。
内容的提问来源于stack exchange,提问作者Turxan Dünya
相关产品推荐
相关产品推荐

