Unity VR:XR Interaction Toolkit 输入系统(Input System):获取手柄的输入

文章目录

  • 📕教程说明
  • 📕Input System 和 XR Input Subsystem(推荐 Input System)
  • 📕Input Action Asset
    • ⭐Actions Maps
    • ⭐Actions
    • ⭐Action Properties
      • 🔍Action Type (Value, Button, Pass through)
    • ⭐Binding Properties
      • 🔍Path
      • 🔍Control Scheme
      • 🔍Interactions
      • 🔍Processors
    • ⭐总结
  • 📕如何使用 Input System
    • ⭐XR Interaction Toolkit 现有脚本调用 Input System 的原理
      • 🔍Input Action Manager 脚本
      • 🔍XR Controller (Action-based) 脚本
    • ⭐在自己的脚本中引用 Input System 中的动作
      • 🔍直接引用 Input Action
      • 🔍引用 InputActionReference(推荐)
      • 🔍引用 InputActionProperty(推荐)
      • 🔍引用 InputActionMap
      • 🔍引用 Input Action Asset(推荐)
    • ⭐将动作与动作触发时执行的方法进行关联
      • 🔍方法一:将执行的方法绑定到 performed 委托上(推荐)
      • 🔍方法二:通过 action.triggered 判断是否触发
    • ⭐获取输入的值(ReadValue\<T>)
    • ⭐在 Input Action Asset 中添加自定义的动作输入映射
  • 📕总结

输入系统是 VR 应用中非常重要的一部分。我们通常需要获取 VR 手柄上某个按键的输入,然后将其作用到应用中,比如按下手柄的 Grip 键进行抓取。在我的其他 Unity XR Interaction Toolkit 的开发教程里,已经有介绍如何去获取手柄的输入。那么这篇教程我将做一个总结,将相关的重点集中在一个教程里。


📕教程说明

使用的 Unity 版本: 2021.3.5

使用的 VR 头显: Oculus Quest 2

教程使用的 XR Interaction Toolkit 版本:2.3.2(此教程尽量考虑了向上兼容,如果有过期的地方,欢迎大家指出)

OpenXR+XR Interaction Toolkit 的环境配置可以参考这篇教程:Unity VR 开发教程 OpenXR+XR Interaction Toolkit (一) 安装和配置


📕Input System 和 XR Input Subsystem(推荐 Input System)

在 XR Interaction Toolkit 中,有两种接收输入的方式。一种是 Action-based,另一种是 Device-based,它们分别对应两种不同的输入系统,Action-based 使用的是 Unity 中的 InputSystem,Device-based 使用的是 Unity 中的 XR Input Subsystem,区别可以参考我的这篇文章:Unity XR Interaction Toolkit 组件解析(一)Action-based 和 Device-based 的区别
现在,XR Interaction Toolkit 官方推荐使用的是基于 Action-based 的 Input System。因此,我的系列教程中使用的也都是 Input System。

Input System 是 Unity 提供的一套更方便,拓展性更高的用于检测键盘,手柄,鼠标,摇杆等设备输入的系统。它将输入设备和动作逻辑互相分离,通过配置映射来处理输入信息。也就是说,我们可以在 Input System 中定义一个动作,这个动作可以是一至多个输入操作的映射,也可以说这个动作能够绑定一至多个设备输入的操作。在 Unity 中,我们只需要提前配置好动作和输入的映射关系,无需写代码来判断设备输入,只需把重心放在逻辑处理上,也就是检测到输入后要做的事情。举个例子,我要在按下手柄 Grip 键的时候触发抓取,那么我可以在 Input System 的配置文件中定义“抓取”这个动作,将“按下手柄 Grip 键”这个输入操作与“抓取”动作进行绑定,此时动作和输入就成了映射关系。然后在代码中我们不需要监听“按下手柄 Grip 键”什么时候触发,只需要编写按下手柄 Grip 键后触发的抓取逻辑,将其与我们定义的动作关联。这样,Input System 会自动帮我们监听“按下手柄 Grip 键”的输入操作,如果触发了,则说明与输入操作绑定的动作触发了,这时候程序就会执行我们编写的抓取逻辑。

使用这种方式的好处是:

  1. 我们在代码中关心的是定义的动作触发后需要执行什么样的方法,而不用关心设备的输入是否触发,设备的输入由 Input System 自动监听。
  2. 以后我如果想把需求改为“按下手柄 Trigger 键进行抓取”,那么我只需要在配置文件里将“按下手柄 Trigger 键”的输入操作与“抓取”动作绑定,形成映射关系,删除原来“按下手柄 Grip 键”的绑定,而代码不需要做任何改变。因为在代码中我们是将与输入绑定的动作与触发的逻辑方法进行了关联,此时抓取需要做的事情关联的仍然是“抓取”这个动作,只不过我们在配置文件中将与“抓取”动作绑定的输入操作改为了“按下手柄 Trigger 键”。因此,我们在代码中关心的是动作的触发,在配置文件中关心的是动作与什么样的输入绑定,而监听输入完全交给了 Input System 本身,不用我们自己编写监听输入相关的代码,这大大提高了可拓展性。
    在这里插入图片描述

以上便是 Input System 输入系统的使用思路。如果看到这里还有点懵,不用担心,接下来我会演示具体的操作。


📕Input Action Asset

Input Action Asset 是 Input System 中的配置文件。当我们导入了 XR Interaction Toolkit 的 Starter Assets 后,可以在下图中的这个路径(我的 XRI 版本是 2.3.2)看到这个资源文件:

在这里插入图片描述

在这里插入图片描述

名字叫做 XRI Default Input Actions,它是 XR Interaction Toolkit 官方为我们准备的一个 Input Action Asset 配置文件,里面已经配置了常用的动作与输入的映射关系。我们可以双击这个文件,看看它长什么样:

在这里插入图片描述

跳出的页面从左往右可以分为三个区域:Action Maps,Actions 和 Action Properties。

⭐Actions Maps

在这里插入图片描述

里面的每一行相当于一个动作输入映射集,称为 Input Action Map。

⭐Actions

在这里插入图片描述

里面的每一行相当于当前输入映射集里定义的动作输入映射。最左边为绿色的代表动作(Action),每个动作可以添加下一个层级,也就是最左边是蓝色的这些东西,它们代表该动作绑定的输入操作。如上图所示,比如 Select 是一个动作,这个动作绑定了 gripPressed [LeftHand XR Controller] 和 indexPressed [LeftHand MetaAimHand] 两个输入操作。

⭐Action Properties

在这里插入图片描述

这个相当于某一个动作的属性面板,选中 Actions 下的某一个动作就能看到最右边的这个 Action Properties 面板。用的比较多的是 Action Type,可以看到它有三种类型:Value,Button,Pass through

在这里插入图片描述

🔍Action Type (Value, Button, Pass through)

Value 是一个值,可以代表连续的状态变化。比如说手柄 Grip 键按下的程度,没按的时候值为 0;逐渐按下最终按到底,值会逐渐增大到 1。再比如手柄摇杆推动的程度,也是需要用 Value 作为 Action Type。

Button 就是表示按钮或者按键触发的一次性动作。只有“按下”和“没按下”两种状态。

Pass through 和 Value 类似。它们的区别按官方的说法是如果动作绑定了多个输入,Value 会切换到最主要的那一个输入,也就是当某一个输入的值大于当前正在驱动动作的那一个输入,值更大的那个输入会接管驱动动作的权利。而 Passthrough 面对多个输入时,只会让最近发生的那个输入驱动动作。这种一个动作绑定多个输入,由输入驱动动作的情况可能会在一个 PC 游戏连接了多个游戏手柄的时候发生,因为需要确保哪一个游戏手柄拥有主要控制权。而在 VR 开发中也许不是很常见,在日常开发中,Value 和 Button 用的比较多。

⭐Binding Properties

官方文档:https://docs.unity3d.com/Packages/com.unity.inputsystem@1.4/manual/ActionBindings.htmll

在这里插入图片描述

我们回到 Actions 这一列,每个动作下绑定的东西(最左边为蓝色图标)叫做 Binding,也就是与动作形成映射关系的输入操作。以 XRI LeftHand Interaction 下的 Select 动作为例(上图所示),先看一下 Select 动作的 Action Properties 面板:

在这里插入图片描述

可以看出这是一个 Button 类型,表示某个按钮是否被按下。然后点击 Select 动作下的 gripPressed [LeftHand XR Controller],可以看到最右边的面板变成了下图所示的样子:

在这里插入图片描述

从上到下分为 Path,Use in control scheme,Interactions 和 Processors

🔍Path

Path 用一个路径代表具体的输入操作,上图中表示的是“按下左手柄的 Grip 键”这一个输入操作,也就是说 Select 动作与 “按下左手柄的 Grip 键”这一输入进行了绑定。点开这个按钮可以看到系统内置了一些常用的输入设备,这一块会在后面的实战过程中再次讲解。

在这里插入图片描述

🔍Control Scheme

Path 参数的下方有一个 Use in control scheme,然后有一些选项可以勾选:

在这里插入图片描述

Control Scheme 只是为了给输入的 Binding 进行分组分类,图中的三个选项是 XRI 为我们预置的分类。我们可以看到整个 Input Action Asset 面板左上角的 All Control Schemes,然后点开它:

在这里插入图片描述
它相当于一个过滤器。当选中了 All Control Schemes(所有类别)时,XRI LeftHand Locomotion 下的 Actions 这一列如下图所示:

在这里插入图片描述
但是如果我将 Control Schemes 改成 Continous Move,Actions 这一列就会发生变化:

在这里插入图片描述

可以看到此时就只有 Move 动作下显示了 Binding(Primary2DAxis [LeftHand XR Controller]),而其他的 Binding 被过滤掉了。我们可以看一下 Primary2DAxis [LeftHand XR Controller] 的 Binding Properties 面板:

在这里插入图片描述
因为 Use in control scheme 下的 Continuous Move 被勾选了,所以这个 Binding 属于 Continuous Move 这个类别。而 XRI LeftHand Locomotion 下其他动作的 Binding 勾选了其他的 Control Scheme 类别,所以当我们的 Input Action Asset 面板的 Control Scheme 过滤器选择了 Continous Move,当前 Input Action Map 下属于 Continous Move 类别的 Binding 会显示在 Actions 面板中,而其他类别的 Binding 会被过滤掉。

当然,我们也可以自定义 Control Scheme 类别:

在这里插入图片描述

在这里插入图片描述

🔍Interactions

Interactions 对输入的方式进行了更详细的规范。

在这里插入图片描述

点击 Interactions 右侧的“+”号,可以看到系统为我们提供了几个输入方式。如果你想要详细了解它们的区别,可以参考官方文档:https://docs.unity3d.com/Packages/com.unity.inputsystem@1.4/manual/Interactions.html
在这里插入图片描述

这里需要注意的是,如果动作的 Action Type 选择了 Value,然后 Control Type 选择了 Delta/Dpad/Stick/Vector2 中的其中一个,Binding Properties 下的 Interactions 会多出一个 Sector 选项。举个例子,我们找到 XRI LeftHand Locomotion 下的 Teleport Select Activate 动作和与其绑定的 Primary2DAxis [LeftHand XR Controller],如下图所示:

在这里插入图片描述

先看一下 Teleport Select Activate 动作的 Action Properties 面板:

在这里插入图片描述

与之前举例的 Select 动作不同的是,Select 动作的 Action Type 是 Button,而 Teleport Select Activate动作的 Action Type 是 Value,并且 Control Type 是 Vector2,也就是说接收的输入是一个二维向量。

然后查看 Primary2DAxis [LeftHand XR Controller] 的 Binding Properties 面板:

在这里插入图片描述

在这里插入图片描述

可以看到这个输入 Binding 已经添加了一个名叫 Sector 的 Interaction,而这个 Sector 选项也是新增的。Sector 是扇区的意思,手柄摇杆的相关功能经常要用到 Sector 这个 Interaction。因为摇杆是在一个圆形范围内运动,我们可以将其想象为 x-y 坐标系下的一个圆心在原点,半径为 1 的圆:

在这里插入图片描述
在 Primary2DAxis [LeftHand XR Controller] 中, Sector 的 Direction 为 North,那么对应的就是摇杆向前推动的输入。我们可以想象成摇杆向下图红色区域推动时会触发这个输入操作:

在这里插入图片描述
在 VR 中向前推动手柄摇杆触发传送的操作比较常见,因此 Teleport Select Activate 这个动作经常用于激活传送。因为 Teleport Select Activate 动作本身的 Action Type 是 Value,Control Type 是 Vector2,它的类型是一个二维向量,该动作绑定的输入操作 Primary2DAxis [LeftHand XR Controller] 接收的是手柄摇杆的输入,用一个二维向量表示,但是接收的是摇杆各个方向的输入,所以要对输入的方向做个限制,只有摇杆向前方的一小段扇区推动才能生效。于是需要在 Binding Properties 中的 Interactions 添加 Sector 类型,将 Direction 改为 North。

🔍Processors

Processors 处理器可以对接收的输入数据进行处理,返回一个新的数据。
举个例子,我们找到 XRI LeftHand Locomotion 下的 Move 动作,查看它绑定的输入的 Binding Properties 面板:

在这里插入图片描述
在这里插入图片描述

可以看到它的 Processors 添加了一个 Stick DeadZone,它有一个最小值和最大值,因为这个 Binding 接收的是一个来自摇杆的 Vector2 类型的二维向量数据,当向量的大小(magnitude)小于 Min 值时,会将结果视为(0,0),当向量的大小大于 Max 值时,会将向量的大小归一化为 1【比如(1,1)(1,-1)等】。

除此之外,还有其他类型的 Processor 可以选择,当动作 Action 的 Action Type 不同时,供选择的 Processor 也有所不同:

在这里插入图片描述

每个 Processor 的作用可以参考官方文档:https://docs.unity3d.com/Packages/com.unity.inputsystem@1.4/manual/Processors.html

在这里插入图片描述

⭐总结

总结一下 Input System 的结构。首先需要一个 Input Action Asset 配置文件,里面包含了 Action Maps 动作输入映射集,每一个映射集包含了 Actions 动作,每个动作绑定一至多个 Binding 输入。根据我们前面介绍的,我们只会在配置文件中配置动作和输入的映射关系,而在代码中,我们需要引用 Action 动作。因此,我们需要记住 Input Action Asset => Action Map => Action 的结构,这对我们后续的代码实战有帮助。


📕如何使用 Input System

当我们在 Input Action Asset 配置文件中配置了动作与输入的映射关系后,我们可以在脚本中访问 Input Action Asset 中配置的动作。一种使用场景是在代码中编写接收到输入后执行的方法,然后将其与 Input System 中相应的动作关联,这样才能访问我们的配置文件,当系统监听到输入时,视为与其绑定的动作触发,从而触发我们编写的方法。另一种使用场景是获取输入的值,比如按下手柄 Grip 键来驱动手部动画,需要根据 Grip 键按下的程度来驱动动画的切换。

⭐XR Interaction Toolkit 现有脚本调用 Input System 的原理

🔍Input Action Manager 脚本

当我们在场景中添加 XR Origin(VR) 这个物体的时候,XR Origin 物体上会自动添加一个 Input Action Manager 脚本,相当于输入动作的管理者:

在这里插入图片描述

可以看到 XRI 提供的 Input Action Asset(名字叫做 XRI Default Input Actions)被自动添加到了脚本的 Action Assets 中。

因为 Input System 中的 Actions 动作默认是关闭的,也就是系统默认不会监听我们配置的输入,需要手动 Enable 这些 Action 才会开始监听。而 Input Action Manager 脚本可以帮我们激活添加到 Action Assets 中的动作,所以 XRI Default Input Actions 配置文件中的所有动作会被 Input Action Manager 激活,那么系统也会开始监听这些动作所绑定的输入

我们可以打开 Input Action Manager 脚本:

在这里插入图片描述

在这里插入图片描述

可以看到在 OnEnable 的时候,脚本调用 EnableInput 方法,调用存储的 Input Action Asset 的 Enable 方法,因此 Input Action Asset 中的所有 Action 都会被激活,所有 Action 绑定的输入会被系统监听。

所以,后续我们如果在脚本中引用一个动作,如果该动作所属的 Input Action Asset 被添加到了 Input Action Manager 中,我们是不需要手动在脚本中激活该动作的。

🔍XR Controller (Action-based) 脚本

在 XR Origin 下的 LeftHand Controller 和 RightHand Controller 物体上挂载了 XR Controller(Action-based) 脚本。它能将 Input Action Asset 中设定的动作与 VR 中的交互关联起来,以左手为例:

在这里插入图片描述

可以看到在 Reference 中引用了 XRI Default Input Actions 中配置的一些动作,类型为 Input Action Reference。这个脚本通常要和交互功能结合在一起,才能在监听到设备输入的时候触发交互的功能。VR 中的交互由两部分组成:发起交互的对象(Interactor)和可被交互的对象(Interactable)。我们以抓取功能为例,Interactor 相当于虚拟的双手,对应着手柄,Interactable 就是可以被抓取的物品。在 Unity 中,我们需要给手部添加 XR Direct Interactor 脚本,给物品添加 XR Grab Interactable 脚本(具体的使用方法可以参考这篇教程:Unity VR 开发教程 OpenXR+XR Interaction Toolkit (六)手与物品交互(触摸、抓取)),这样抓取交互的条件就满足了,接下来需要解决的是手柄输入触发抓取的问题。假设按下手柄的 Grip 键触发抓取,刚好我们 XR Controller 脚本中的 Select Action 引用的 Reference 是 Select 动作:

在这里插入图片描述
在这里插入图片描述

Select 动作绑定的就是“按下手柄 Grip 键”的输入操作,因此当系统监听到“按下手柄 Grip 键”的输入操作后,便会触发 XR Controller 的 Select Action。而 在拥有 Interactor 和 Interactable 相关脚本的条件下,Select 动作的发生就会让物体被抓取到手上。这就是 XR Interaction Toolkit 现有脚本调用 Input System 的一个例子。


⭐在自己的脚本中引用 Input System 中的动作

有时候,我们需要在自己的脚本中引用 Input System 中的动作,然后编写这个动作触发后执行的方法。回想一下 Input System 的结构:Input Action Asset => Action Map => Action,我们需要获取 Action 相关的类。在 Input System 中,Action 所属的类叫做 Input Action,首先我们要导入 UnityEngine.InputSystem 命名空间:

using UnityEngine.InputSystem;

然后有以下几种方法在代码中获取它,后续我们也要得到 InputAction 类的变量,对它进行操作

🔍直接引用 Input Action

我们可以直接引用 Input Action 类:

public InputAction testAction;

这样我们的 Inspector 面板会多出这个东西:

在这里插入图片描述
但是这里需要我们在 Inspector 面板中配置 Action 绑定的输入操作,无法直接引用 Input Action Asset 配置文件中已经配置好的动作输入映射。所以不推荐大家直接在脚本中引用 InputAction。

在这里插入图片描述

在这里插入图片描述

🔍引用 InputActionReference(推荐)

public InputActionReference testActionReference;

这个 InputActionReference 类能够访问 Input Action Asset 中 Input Action Map 里的 Input Action
此时 Inspector 面板如下:

在这里插入图片描述

我们可以选择一个 InputActionReference:

在这里插入图片描述
这些就是我们在 Input Action Asset 配置文件里配置的动作。

有了 InputActionReference 类的引用,我们可以通过

testActionReference.action

得到 InputAction 类的变量。

🔍引用 InputActionProperty(推荐)

public InputActionProperty testActionProperty;

此时 Inspector 面板如下图所示:

在这里插入图片描述
InputActionProperty 既能够引用 Input Action Asset 中的动作配置,也能够在面板中定义动作和输入的映射关系。

如果我们勾选了 Use Reference,可以在面板中给 Reference 变量赋值,选择配置文件中配置好的动作。

在这里插入图片描述

如果没有勾选 Use Reference,我们也可以像直接引用 InputAction 后看到的面板那样,在 Inspector 面板中配置动作和输入的映射。

在这里插入图片描述

不过还是推荐大家统一在 Input Action Asset 配置文件中配置动作和输入的映射关系,这样便于管理。

和 InputActionReference 一样,我们可以通过:

testActionProperty.action

得到 InputAction 类的变量。

🔍引用 InputActionMap

public InputActionMap testActionMap;

因为 InputAction 的上一层级是 InputActionMap,所以我们也能通过 InputActionMap 来获取 InputAction

此时 Inpsector 面板如图所示:

在这里插入图片描述

这里我们就只能在 Inspector 面板中配置动作和输入的映射。和之前直接引用 InputAction 不同,如果直接引用 InputAction,相当于我们定义了一个动作,然后在面板中配置这个动作绑定的输入;如果引用 InputActionMap,因为 Action Map 是一组动作输入映射集,所以我们能在面板中定义一组动作,然后为每一个动作配置绑定的输入。

接下来我们可以在代码中通过:

InputAction[] actions = testActionMap.actions.ToArray(); 

获取一组 InputAction 变量。

但是引用 InputActionMap 同样也不能访问 Input Action Asset,所以也不推荐这种用法。

🔍引用 Input Action Asset(推荐)

public InputActionAsset testActionAsset;

这时候 Inspector 面板如下:

在这里插入图片描述

然后我们可以用 XRI Default Input Actions 文件进行赋值:

在这里插入图片描述

结合 Input System 的结构,我们可以根据一个 Input Action Asset 找到其中一个 Input Action Map,然后在这个 Input Action Map 中找到一个 Input Action。所以代码可以这么写:

 InputAction select = testActionAsset.FindActionMap("XRI LeftHand Interaction").FindAction("Select");

这样就能够准确地找到我们想要的动作。虽然 InputActionAsset 类有一个 FindAction 方法:

InputAction select = testActionAsset.FindAction("Select");

但是如果不同的 Input Action Map 含有相同名字的 Input Action,这个 InputActionAsset 下的 FindAction 方法会返回已经激活的 Action 中,第一个被找到的 Action。因此还是推荐先用 FindActionMap 找到具体的 Action Map,再用 FindAction 找到具体的 Action。

引用 Input Action Asset 的好处是:之前不管是引用 InputActionReference 还是 InputActionProperty,都需要手动将具体的 Action 赋值到 Inspector 面板中。如果你喜欢用纯代码的方式找到具体的 Action,可以尝试引用 Input Action Asset,然后用 FindActionMap 和 FindAction 方法找到具体的 Input Action

⭐将动作与动作触发时执行的方法进行关联

能够得到 InputAction 类的变量后,相当于连接了 Input System 和我们的脚本。接下来只剩下编写动作触发时需要执行的方法,将其与动作进行关联。这种情况适用于 Action Type 为 Button 的动作,因为只有“动作触发”和“动作没触发”两种状态,当输入发生,比如某个按键按下的时候,触发动作,执行相应的行为。

现在假设我们有一个需求:按下左手柄 Grip 键的时候在控制台输出一句话。
我这里选择引用 InputActionReference 的方式。

🔍方法一:将执行的方法绑定到 performed 委托上(推荐)

using UnityEngine;
using UnityEngine.InputSystem;

public class XRInputTest : MonoBehaviour
{
    public InputActionReference testActionReference;
    //public InputActionProperty testActionProperty;
    //public InputActionMap testActionMap;
    //public InputActionAsset testActionAsset;

    private InputAction testAction;
    void Start()
    {
        testAction = testActionReference.action;
        testAction.performed += ActivateBehavior;
    }

    private void ActivateBehavior(InputAction.CallbackContext context)
    {
        print("执行方法");
    }
}

我们需要将动作触发时执行的方法绑定到 InputAction 类的 performed 委托中:

testAction.performed += ActivateBehavior;

performed 委托会在动作触发完成后调用,它是一个
Action<InputAction.CallbackContext> 类型的委托,所以绑定的方法需要将 InputAction.CallbackContext 作为方法参数

因为我的需求是监听“按下手柄 Grip 键”的操作,这与 XRI Default Input Actions 配置文件中的 XRI LeftHand Interaction (Action Map)下的 Select 动作(Action)相匹配。所以我们在 Inspector 面板中进行赋值:

在这里插入图片描述
运行程序,当我们按下左手柄 Grip 键的时候,如果在控制台能看到输出,说明我们成功了。

在这里插入图片描述

🔍方法二:通过 action.triggered 判断是否触发

我们也可以这样写代码:

using UnityEngine;
using UnityEngine.InputSystem;

public class XRInputTest : MonoBehaviour
{
    public InputActionReference testActionReference;
    //public InputActionProperty testActionProperty;
    //public InputActionMap testActionMap;
    //public InputActionAsset testActionAsset;

    private InputAction testAction;
    void Start()
    {
        testAction = testActionReference.action;
    }
    private void Update()
    {
        if (testAction.triggered)
        {
            print("执行方法");
        }
    }

}

testAction.triggered 是一个 bool 变量,当动作触发时,返回 true,这时候可以执行动作触发时做的事情。但是这种写法将要过时,还是推荐大家使用第一种方法。

⭐获取输入的值(ReadValue<T>)

这种情况一般适用于 Action Type 为 Value 或者 Pass through 的动作。以获取按下左手柄 Grip 键的程度为例,我想获取按下左手柄 Grip 键对应的值,可以这么做:

using UnityEngine;
using UnityEngine.InputSystem;

public class XRInputTest : MonoBehaviour
{
    public InputActionReference leftGripActionValueReference;
    private InputAction leftGripActionValue;
    void Start()
    {
        leftGripActionValue = leftGripActionValueReference.action;
    }
    private void Update()
    {
        GetGripValue();
    }
    private void GetGripValue()
    {
        float value = leftGripActionValue.ReadValue<float>();
        print($"value:{value}");
    }   
}

通过 InputAction 类下的 ReadValue<T> 方法获取输入的值,Grip 键按下的程度可以用一个 float 类型的数来表示。

在 XRI Default Input Actions 配置文件中,XRI LeftHand Interaction (Action Map)下的 Select Value 动作(Action)能获取按下左手柄 Grip 键对应的值,该动作的 Action Type 为 Value

在这里插入图片描述

在这里插入图片描述

⭐在 Input Action Asset 中添加自定义的动作输入映射

接下来我将演示如何在 在 Input Action Asset 中添加自定义的动作输入映射。

我使用的是 Quest 2,那么就来演示一下按下左手柄 X 键时控制台输出一句话。

首先打开 XRI Defalut Input Actions 文件,我们直接在官方为我们准备的 Input Action Asset 里操作。因为配置文件中默认没有“按下左手柄 X 键”相关的动作,所以我们需要手动添加自定义的动作。我选择在 XRI LeftHand Interaction 这个 Action Map 中添加一个新的动作,将它命名为 PrimaryButton。

在这里插入图片描述
确保右侧面板的 Action Properties 中的 Action Type 为 Button,因为我们检测的是按键是否被按下。

在这里插入图片描述
接着点击动作下方的这个 Binding,点击右侧面板的 Path,选择 XR Controller:

在这里插入图片描述

选择 XR Controller (LeftHand):

在这里插入图片描述

选择 Optional Controls:

在这里插入图片描述

选择 primaryButton,这个 primaryButton 对应左手柄的 X 键或者右手柄的 A 键;而 secondaryButton 对应 左手柄的 Y 键或者右手柄的 B 键。大家也可以自行尝试 Optional Controls 里的其他选项,基本涵盖了手柄的所有输入。

在这里插入图片描述

最后别忘了点击面板上方的 Save Asset 进行保存:

在这里插入图片描述

然后编写相关代码:

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

public class XRInputTest : MonoBehaviour
{
    public InputActionReference testActionReference;    
    private InputAction testAction;

    void Start()
    {
        testAction = testActionReference.action;

        testAction.performed += ActivateBehavior; 
    }


    private void ActivateBehavior(InputAction.CallbackContext context)
    {
        print("执行方法");
    }    
}

在 Inspector 面板中赋值:

在这里插入图片描述

现在运行程序,当我按下左手柄的 X 键时,控制台就会输出一段语句:

在这里插入图片描述


📕总结

XR Interaction Toolkit 推荐使用 Unity 的 Input System 来接收设备的输入。它将输入设备和动作逻辑互相分离,通过配置映射来处理输入信息。我们只需要提前配置好动作和输入的映射关系,在代码中把重心放在逻辑处理上,也就是检测到输入后要做的事情,将其与配置的动作相关联。而设备输入的监听交给了系统本身。当监听到设备输入时,视为触发了输入所绑定的动作,便会触发动作发生后需要做的事情。

总的来说使用起来分为这几个阶段:编辑配置文件,关联脚本与配置文件中的动作,编写接收到输入时执行的逻辑

Input System 需要有一个 Input Action Asset 配置文件,Input Action Asset 可以存储多个 Input Action Map,每一个 Action Map 相当于一组动作输入映射集,每一个 Action Map 存储的动作(Input Action)能够绑定一至多个输入操作。

配置好动作和输入的映射关系后,我们需要在脚本中获取 InputAction 类的变量,才能访问配置文件中对应的动作。然后可以将动作触发时执行的方法绑定到 InputAction 类的委托上,这样就能在接收到设备输入时执行相应的逻辑;或者使用 InputAction 类的 ReadValue<T> 方法获取输入的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/82638.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Error creating bean with name ‘esUtils‘ defined in file

报错异常&#xff1a; 背景&#xff1a; esUtils在common服务中、启动media服务时候、报这个异常、后排查esUtils在启动时候发生异常引起的、在相关bean中加入try{}catch{}即可解决问题 String[] split url.split(","); HttpHost[] httpHosts new HttpHost[split.…

字符设备驱动实例(PWM和RTC)

目录 五、PWM 六、RTC 五、PWM PWM(Pulse Width Modulation&#xff0c;脉宽调制器)&#xff0c;顾名思义就是一个输出脉冲宽度可以调整的硬件器件&#xff0c;其实它不仅脉冲宽度可调&#xff0c;频率也可以调整。它的核心部件是一个硬件定时器&#xff0c;其工作原理可以用…

微信小程序:函数节流与函数防抖

目录 问题引入&#xff1a; 定义 解决方案&#xff1a;函数节流 一、案例举例 1.页面展示 2.search.wxml标签展示 3.search.js展示 4.结果展示 二、函数节流解决问题 1.函数 2.实例应用 三、函数防抖解决问题 1.函数 2.原理 3.应用场景 4.应用实例 总结 问题引入…

华为云零代码新手教学-体验通过Astro Zero快速搭建微信小程序

您将会学到 您将学会如何基于Astro零代码能力&#xff0c;DIY开发&#xff0c;完成问卷、投票、信息收集、流程处理等工作&#xff0c;还能够在线筛选、分析数据。实现一站式快速开发个性化应用&#xff0c;体验轻松拖拽开发的乐趣。 您需要什么 环境准备 注册华为云账号、实…

unity之Input.GetKeyDown与Input.GetKey区别

文章目录 Input.GetKeyDown与Input.GetKey区别 Input.GetKeyDown与Input.GetKey区别 Input.GetKey 和 Input.GetKeyDown 是 Unity 中用于检测按键状态的两个不同函数。它们之间的区别在于何时触发。 Input.GetKey(KeyCode key): 这个函数会在用户按住指定的键时触发&#xff0…

深度学习|自监督学习、MAE学习策略、消融实验

前言&#xff1a;最近在阅读论文&#xff0c;发现太多机器学习的知识不懂&#xff0c;把最近看的一篇论文有关的知识点汇总了一下。 自监督学习、MAE学习策略、消融实验 自监督学习MAE学习策略消融实验 自监督学习 Pretrain-Finetune&#xff08;预训练精调&#xff09;模式&…

Jmeter生成可视化的HTML测试报告

Jmeter也是可以生成测试报告的。 性能测试工具Jmeter由于其体积小、使用方便、学习成本低等原因&#xff0c;在现在的性能测试过程中&#xff0c;使用率越来越高&#xff0c;但其本身也有一定的缺点&#xff0c;比如提供的测试结果可视化做的很一般。 不过从3.0版本开始&…

初阶c语言:实战项目三子棋

前言 大家已经和博主学习有一段时间了&#xff0c;今天讲一个有趣的实战项目——三子棋 目录 前言 制作菜单 构建游戏选择框架 实现游戏功能 模块化编程 初始化棋盘 打印棋盘 玩家下棋 电脑下棋 时间戳&#xff1a;推荐一篇 C语言生成随机数的方法_c语言随机数_杯浅…

数据库结构差异对比工具

简介 前几年写了一个数据库对比工具&#xff0c;但是由于实现方式的原因&#xff0c;数据库支持有限&#xff0c;所以重新设计了一下&#xff0c;便于支持多种数据库&#xff0c;并且更新了UI。 新版地址&#xff1a;https://gitee.com/xgpxg/db-diff 旧版地址&#xff1a;h…

ARM 配置晶振频率

文章目录 前言串口乱码问题定位内核修改晶振频率uboot 修改晶振频率番外篇 前言 上篇文章《ARM DIY 硬件调试》介绍了 DIY ARM 板的基础硬件焊接&#xff0c;包括电源、SOC、SD 卡座等&#xff0c;板子已经可以跑起来了。 但是发现串口乱码&#xff0c;今天就来解决串口乱码问…

OpenCV图片校正

OpenCV图片校正 背景几种校正方法1.傅里叶变换 霍夫变换 直线 角度 旋转3.四点透视 角度 旋转4.检测矩形轮廓 角度 旋转参考 背景 遇到偏的图片想要校正成水平或者垂直的。 几种校正方法 对于倾斜的图片通过矫正可以得到水平的图片。一般有如下几种基于opencv的组合方…

【前端】vscode javascript 代码片段失效问题解决

1. 文件--首选项--用户代码片段-vue.json : 添加 // { // // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and // // description. Add comma separated ids of the languages where the snippet is app…

C语言:分支语句和循环语句(超详解)

目录 ​编辑 什么是语句&#xff1f; 分支语句&#xff08;选择结构&#xff09; if语句&#xff1a; 应该注意的是&#xff1a; switch语句&#xff1a; 运用练习&#xff1a; 循环语句 while循环&#xff1a; for循环&#xff1a; break和continue在for循环中&…

Linux(入门篇)

Linux&#xff08;入门篇&#xff09; Linux概述Linux是什么Linux的诞生Linux和Unix的渊源GNU/LinuxLinux的发行版Linux VS Windows Linux概述 Linux是什么 Linux是一个操作系统(OS) Linux的诞生 作者&#xff1a;李纳斯托瓦兹&#xff08;git也是他开发的&#x1f602;&am…

Excel/PowerPoint柱状图条形图负值设置补色

原始数据&#xff1a; 列1系列 1类别 14.3类别 2-2.5类别 33.5类别 44.5 默认作图 解决方案 1、选中柱子&#xff0c;双击&#xff0c;按如下顺序操作 2、这时候颜色会由一个变成两个 3、对第二个颜色进行设置&#xff0c;即为负值的颜色 条形图的设置方法相同

Unity C# 引用池 ReferencePool

Unity C# 引用池 ReferencePool 1.目的 对于多次创建的数据使用new 关键字是十分消耗性能的&#xff0c;使用完成后由GC去自动释放&#xff0c;当一个类型的数据频繁创建可以使用引用池进行管理。 2.实现 项目目录 IReference 接口 要放入引用池的数据只需要继承这个接口…

图床项目进度(一)——UI首页

1. 前言 前面我不是说了要做一个图床吗&#xff0c;现在在做ui。 我vue水平不够高&#xff0c;大部分参考b站项目照猫画虎。 vue实战后台 我使用ts&#xff0c;vite&#xff0c;vue3进行了重构。 当然&#xff0c;我对这些理解并不深刻&#xff0c;许多代码都是游离于表面&am…

经验分享:企业数据仓库建设方案总结!

导读 在企业的数字化转型浪潮中&#xff0c;数据被誉为“新时代的石油”&#xff0c;而数据仓库作为数据管理与分析的核心基础设施&#xff0c;在企业的信息化建设中扮演着重要的角色。本文将深入探讨企业数据仓库建设过程中所遇到的问题以及解决经验&#xff0c;为正在筹备或…

shell脚本——文件三剑客之sed

目录 一.sed基本用法及选项 ​二.sed脚本语法及命令 三.sed的查找替换使用 四.后向引用 五.变量 一.sed基本用法及选项 sed [选项]... {自身脚本语法};.... [input file...] seq 10 |sed #生成1-10数字传给sed #该格式报错&#xff0c;基本格式中的{自身脚本语法}不…

Python之Qt输出UI

安装PySide2 输入pip install PySide2安装Qt for Python&#xff0c;如果安装过慢需要翻墙&#xff0c;则可以使用国内清华镜像下载&#xff0c;输入命令pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple PySide2&#xff0c;如下图&#xff0c; 示例Demo i…