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

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;
    }
}

关键修复点说明

  1. 新增蓄力状态标记:添加hasReachedHoldThreshold公开属性,外部代码(如UI控制器)可直接读取该值,实时更新蓄力进度条、完成提示等UI元素。
  2. 阈值触发逻辑优化:仅在首次达到holdTime时更新状态,避免每帧重复执行判断逻辑。
  3. 状态重置统一:将状态重置逻辑抽为ResetState方法,确保所有触发重置的路径都能正确恢复初始状态。
  4. 变量命名与流转优化:将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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:28:22