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

Unity新输入系统触发多次事件致UI闪烁问题求助

解决Unity新输入系统按键按住时UI闪烁问题

问题根源

你的代码中,RollupTriggered在按键按住期间一直为true,UnitController的Update每帧都会执行ShowHideHUD,导致UI状态被反复切换,从而出现闪烁。

解决方案一:修改触发标志为一次性读取

修改InputHandler中的RollupTriggered属性,使其在被读取后自动重置,确保每次按键仅触发一次UI切换:

public class InputHandler : MonoBehaviour
{
    [SerializeField] private InputActionAsset inputControls;
    [SerializeField] private string actionMapName = "Unit";
    [SerializeField] private string rollup = "Rollup";

    private InputAction rollupAction;
    private bool _rollupTriggered;

    // 读取后自动重置标志位
    public bool RollupTriggered 
    { 
        get 
        { 
            bool temp = _rollupTriggered;
            _rollupTriggered = false;
            return temp;
        } 
        private set => _rollupTriggered = value; 
    }

    public static InputHandler Instance { get; private set; }

    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
        
        rollupAction = inputControls.FindActionMap(actionMapName).Find(rollup);
        RegisterInputActions();
    }

    void RegisterInputActions()
    {
        // 仅在按键按下时设置触发标志
        rollupAction.performed += context => _rollupTriggered = true;
        // 取消canceled事件绑定,无需维持状态
    }

    private void OnEnable()
    {
        rollupAction.Enable();
    }

    private void OnDisable()
    {
        rollupAction.Disable();
    }
}

UnitController代码无需修改,现在每次读取RollupTriggered后标志会自动重置,UI只会切换一次。

解决方案二:使用事件订阅直接触发切换

通过事件机制,避免每帧检查状态,仅在按键触发时执行UI切换:

1. 修改InputHandler添加事件

public class InputHandler : MonoBehaviour
{
    [SerializeField] private InputActionAsset inputControls;
    [SerializeField] private string actionMapName = "Unit";
    [SerializeField] private string rollup = "Rollup";

    private InputAction rollupAction;
    // 定义触发事件
    public event Action OnRollupTriggered;

    public static InputHandler Instance { get; private set; }

    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
        
        rollupAction = inputControls.FindActionMap(actionMapName).Find(rollup);
        RegisterInputActions();
    }

    void RegisterInputActions()
    {
        rollupAction.performed += context => OnRollupTriggered?.Invoke();
    }

    private void OnEnable()
    {
        rollupAction.Enable();
    }

    private void OnDisable()
    {
        rollupAction.Disable();
    }
}

2. 修改UnitController订阅事件

public class UnitController : MonoBehaviour
{
    private InputHandler inputHandler;
    public GameObject hudPanel;

    void Awake()
    {
        inputHandler = InputHandler.Instance;
        // 订阅事件
        inputHandler.OnRollupTriggered += ToggleHUD;
    }

    void OnDestroy()
    {
        // 取消订阅避免内存泄漏
        inputHandler.OnRollupTriggered -= ToggleHUD;
    }

    // 直接切换UI状态
    void ToggleHUD()
    {
        hudPanel.SetActive(!hudPanel.activeSelf);
    }

    // 可以移除Update中的ShowHideHUD调用
}

解决方案三:使用WasPerformedThisFrame方法

利用输入系统的WasPerformedThisFrame()方法,仅在触发事件的帧执行切换:

1. 修改InputHandler添加检查方法

public class InputHandler : MonoBehaviour
{
    [SerializeField] private InputActionAsset inputControls;
    [SerializeField] private string actionMapName = "Unit";
    [SerializeField] private string rollup = "Rollup";

    private InputAction rollupAction;

    public static InputHandler Instance { get; private set; }

    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
        
        rollupAction = inputControls.FindActionMap(actionMapName).Find(rollup);
    }

    // 对外提供检查方法
    public bool IsRollupPerformedThisFrame()
    {
        return rollupAction.WasPerformedThisFrame();
    }

    private void OnEnable()
    {
        rollupAction.Enable();
    }

    private void OnDisable()
    {
        rollupAction.Disable();
    }
}

2. 修改UnitController的Update方法

public class UnitController : MonoBehaviour
{
    private InputHandler inputHandler;
    public GameObject hudPanel;

    void Awake()
    {
        inputHandler = InputHandler.Instance;
    }

    void Update()
    {
        if (inputHandler.IsRollupPerformedThisFrame())
        {
            hudPanel.SetActive(!hudPanel.activeSelf);
        }
    }
}

关键补充:配置Input Action的交互方式

无论使用哪种方案,都需要确保你的Rollup Action不会在按住期间重复触发:

  1. 打开你的Input Control资源文件
  2. 找到Rollup Action,在Interactions列表中添加Press交互
  3. 将Press Type设置为Press Only(按下瞬间触发一次)或Release Only(释放瞬间触发一次);如果需要点击(按下+释放)才触发,选择Tap交互

这样就能彻底避免按住按键时的重复触发问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:14:58