Unity InputSystem 实现同一按键单击、双击、长按执行不同逻辑

最近学习了一下Unity InputSystem。该系统可用于实现、管理复杂的操作逻辑,上限很高。但由于它有一定的学习成本,导致一些和我一样的小白一入门时不得要领。之前卡住我的一个需求就是通过InputSystem 实现同一按键单击、双击、长按执行不同逻辑。例如点击单位执行攻击、双击单位选中所有同类单位、长按单位查看信息。现在想到了相对合理的方式,在此记录并分享。

InputSystem的官方示例提供了4种使用方法,即官方示例“Simple Demo”中提到的4种:

  1. SimpleDemo_UsingState
  2. SimpleDemo_UsingActions
  3. SimpleDemo_UsingActionAsset
  4. SimpleDemo_UsingPlayerInput

其中后两种是我认为的官方推荐的正式用法,我使用的是第三种,即使用了ActionAsset但没有使用PlayerInput的实现方式。

我的测试目标是在单击、双击、长按时在Unity控制台打出不同的log,且一次操作不会出现两次执行log。ActionAsset配置如图:
Input Action Asset配置截图
这里有三点注意事项:

  1. 虽然我们关注的操作有3种(单击、双击、长按),但由于是同个按键,所以应设为一个Action,即截图中的唯一的Action:“Tap”。
  2. 虽然我们关注的操作有3种(单击、双击、长按),但显然双击与单击的操作是有特殊关系的,实际的逻辑应该是单击后等待片刻若无第二次点击才执行单击的逻辑。所以这里我们在Interactions中只添加了“Hold”和“Multi Tap”这两种。其他设置保持默认。
  3. “Hold”和“Multi Tap”在图示Interactions列表中的顺序是影响其执行逻辑的,建议保持图示顺序。

测试代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem.Interactions;

public class TictactoeControl : MonoBehaviour
{
    private TictactoeAction InputActions;
    private void Awake()
    {
        InputActions = new TictactoeAction();
        InputActions.TestMap.Tap.started += ctx =>
        {
            Debug.Log("操作开始");
        };
        InputActions.TestMap.Tap.performed += ctx =>
        {
            if (ctx.interaction is MultiTapInteraction)
            {
                Debug.Log("执行双击逻辑");
            }
            else if (ctx.interaction is HoldInteraction)
            {
                Debug.Log("执行长按逻辑");
            }
            else
            {
                //列表中只有MultiTapInteraction和HoldInteraction对应的两种Interaction。
                //故不会走到这个else里。
            }
        };
        InputActions.TestMap.Tap.canceled += ctx =>
        {
            if (ctx.interaction is MultiTapInteraction)
            {
                Debug.Log("执行点击逻辑");
            }
        };
    }
    void Start()
    {
        
    }
    void Update()
    {

    }
    public void OnEnable()
    {
        InputActions.Enable();
    }
    public void OnDisable()
    {
        InputActions.Disable();
    }
}

我贴了测试脚本的完整代码,我们主要关注Awake()方法中的内容。

当我们设置的“Tap”Action执行时,会调用InputActions.TestMap.Tap.performed,这里要根据它执行时是通过哪个Interaction执行的(Hold 或 MultiTap)。区分后分别执行对应的逻辑即可。

当“Tap”Action取消时,会调用InputActions.TestMap.Tap.canceled,我们在此处判断一下是否是 MultiTap的取消,若是,则执行单击的逻辑。若之前Interactions列表的顺序和图示不一致,则此处执行单击逻辑的时机也会不一致。可能出现单击后不执行却在长按的时候执行的情况。

测试结果如图:
测试结果
我在图示这次测试时先长按了一次,松手后进行了双击,最后进行了一次单击。可以看到三种操作分别独立地执行了,没有出现缺失或是混淆单击、双击的问题。(每次操作出现多次“操作开始”是因为我们配置了不止一种Interaction,在它们之间切换时会执行多次InputActions.TestMap.Tap.started。这个特性当前需求下可以忽略,也可利用起来实现其他功能。)

我使用的这种方式很可能不是最合理的甚至可能是多次一举的,欢迎指正、讨论。如果我发现了新的相关技巧,也会在此更新。

====================================================
2022.03.21更新
上文提到的InputSystem的几种回调(started、performed、canceled)在部分机型(华为折叠屏某款)、模拟器(网易mumu)会失效,原因不明。可使用每帧读取操作状态的方式实现同等功能。

例如:

InputActions.TestMap.Tap.ReadValue<float>();

点击、长按等Button类型的操作要读float类型的值,值为 1f 表示“有操作”,0f 表示“无操作”。
(我实际上很不理解这里为什么不是读bool值,所以怀疑这种每帧读值的方案不是标准方案。)

  • 20
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值