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不会在按住期间重复触发:
- 打开你的Input Control资源文件
- 找到
RollupAction,在Interactions列表中添加Press交互 - 将
Press Type设置为Press Only(按下瞬间触发一次)或Release Only(释放瞬间触发一次);如果需要点击(按下+释放)才触发,选择Tap交互
这样就能彻底避免按住按键时的重复触发问题。
内容的提问来源于stack exchange,提问作者MuppetDance
相关产品推荐
相关产品推荐

