Unity新输入系统自定义交互问题:无法检测按钮按住阈值达成
问题排查与修复方案
你的自定义交互核心逻辑框架是对的,但缺少蓄力阈值达成时的状态通知机制,同时部分状态管理不够严谨,导致无法触发UI更新等后续逻辑。以下是修复后的代码和关键说明:
修复后的完整代码
using UnityEngine.InputSystem; using UnityEditor; using UnityEngine; #if UNITY_EDITOR [InitializeOnLoad] #endif public class HoldAndReleaseInteraction : IInputInteraction { // 按钮触发的最小输入值 public float pressPoint = 0.5f; // 触发蓄力所需的按住时间阈值 public float holdTime = 1.0f; private float pressStartTime; private bool isHolding; // 新增:标记是否已达成蓄力阈值 public bool hasReachedHoldThreshold { get; private set; } static HoldAndReleaseInteraction() { InputSystem.RegisterInteraction<HoldAndReleaseInteraction>(); } public void Process(ref InputInteractionContext context) { if (context.ControlIsActuated(pressPoint)) { if (!isHolding) { isHolding = true; pressStartTime = Time.time; hasReachedHoldThreshold = false; context.Started(); } // 仅在首次达到阈值时更新状态,避免重复判断 if (!hasReachedHoldThreshold && Time.time - pressStartTime >= holdTime) { hasReachedHoldThreshold = true; // 此处可扩展自定义事件,直接通知外部UI更新 } } else if (isHolding) { if (hasReachedHoldThreshold) { context.Performed(); } else { context.Canceled(); } ResetState(); } } public void Reset() { ResetState(); } private void ResetState() { isHolding = false; hasReachedHoldThreshold = false; } }
关键修复点说明
- 新增蓄力状态标记:添加
hasReachedHoldThreshold公开属性,外部代码(如UI控制器)可直接读取该值,实时更新蓄力进度条、完成提示等UI元素。 - 阈值触发逻辑优化:仅在首次达到
holdTime时更新状态,避免每帧重复执行判断逻辑。 - 状态重置统一:将状态重置逻辑抽为
ResetState方法,确保所有触发重置的路径都能正确恢复初始状态。 - 变量命名与流转优化:将
pressTime改为pressStartTime,语义更清晰;每次按住开始时强制重置阈值状态,避免残留旧数据。
外部UI更新示例
在UI控制脚本中,可通过读取交互状态或绑定Action回调实现UI更新:
public class ChargeAttackUI : MonoBehaviour { public InputAction chargeAttackAction; private HoldAndReleaseInteraction _interaction; void Awake() { // 获取自定义交互实例 _interaction = chargeAttackAction.interactions[0] as HoldAndReleaseInteraction; // 绑定开始蓄力的回调,初始化UI chargeAttackAction.started += ctx => { // progressBar.fillAmount = 0; // chargeCompleteText.gameObject.SetActive(false); }; } void Update() { if (_interaction != null && _interaction.isHolding) { // 计算实时蓄力进度 float chargeProgress = Mathf.Clamp01((Time.time - _interaction.pressStartTime) / _interaction.holdTime); // 更新进度条 // progressBar.fillAmount = chargeProgress; // 达到阈值时显示完成提示 if (_interaction.hasReachedHoldThreshold) { // chargeCompleteText.gameObject.SetActive(true); } } } void OnEnable() => chargeAttackAction.Enable(); void OnDisable() => chargeAttackAction.Disable(); }
额外注意事项
- 确保在Input Action的设置界面中,已将
HoldAndReleaseInteraction添加到对应Action的Interactions列表内。 - 若需更灵活的事件通知,可在
HoldAndReleaseInteraction中添加UnityEvent字段,在阈值达成时Invoke,外部直接绑定事件即可,无需每帧检测。
内容的提问来源于stack exchange,提问作者C.G.
相关产品推荐
相关产品推荐

