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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:43:12