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> 方法获取输入的值。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python学习笔记_基础篇(七)_常用模块

模块&#xff0c;用一砣代码实现了某个功能的代码集合。 类似于函数式编程和面向过程编程&#xff0c;函数式编程则完成一个功能&#xff0c;其他代码用来调用即可&#xff0c;提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来&#xff0c;可能需要多个函数才能完成…

华为OD机试关于无输入截止条件的ACM输入逻辑

无输入截止条件的ACM输入 华为OD机试题中有一些题目是没有输入截止条件的,比如 华为OD机试 - 数字游戏(Java & JS & Python)_伏城之外的博客-CSDN博客 从输入描述来看,每组有两行输入,但是并没有告诉我们具体有几组? 那么输入该如何截止呢? 此时,有两种输入…

【旅游度假】Axure酒店在线预订APP原型图 旅游度假子模块原型模板

作品概况 页面数量&#xff1a;共 10 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;旅游度假&#xff0c;生活服务 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为「酒店在线预订」的移动端…

Qt6之如何为QDialog添加最大化和最小化按钮

在QDialog构造函数中添加以下几行代码&#xff1a; // 设置窗体最大化和最小化Qt::WindowFlags windowFlag Qt::Dialog;windowFlag | Qt::WindowMinimizeButtonHint;windowFlag | Qt::WindowMaximizeButtonHint;windowFlag …

三、Kafka生产者

目录 3.1 生产者消息发送流程3.1.1 发送原理 3.2 异步发送 API3.3 同步发送数据3.4 生产者分区3.4.1 kafka分区的好处3.4.2 生产者发送消息的分区策略3.4.3 自定义分区器 3.5 生产者如何提高吞吐量3.6 数据可靠性 3.1 生产者消息发送流程 3.1.1 发送原理 3.2 异步发送 API 3…

【观察】戴尔科技:构建企业创新“韧性”,开辟数实融合新格局

过去几年&#xff0c;国家高度重视发展数字经济&#xff0c;将其上升为国家战略。其中&#xff0c;“十四五”规划中&#xff0c;就明确提出要推动数字经济和实体经济的深度融合&#xff0c;以数字经济赋能传统产业转型升级&#xff1b;而2023年年初正式发布的《数字中国建设整…

python使用matplotlib实现折线图的绘制

一、意义 数据可视化可以以简洁的方式呈现出数据&#xff0c;发现众多数据中隐藏的规律和意义。Matplotlib是一个数学绘图库。利用它可以制作简单的图表&#xff08;散点图、折线图&#xff09;。然后&#xff0c;将基于漫步概念生成一个更有趣的数据集–根据一系列随机决策生成…

【React学习】—组件三大核心属性: state(七)

【React学习】—组件三大核心属性: state&#xff08;七&#xff09; 2.2.2. 理解 state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件) 2.2.3. 强烈注意 组件中rend…

RocketMQ 消息消费 轮询机制 PullRequestHoldService

1. 概述 先来看看 RocketMQ 消费过程中的轮询机制是啥。首先需要补充一点消费相关的前置知识。 1.1 消息消费方式 RocketMQ 支持多种消费方式&#xff0c;包括 Push 模式和 Pull 模式 Pull 模式&#xff1a;用户自己进行消息的拉取和消费进度的更新Push 模式&#xff1a;Broker…

Redis从基础到进阶篇(一)

目录 一、了解NoSql 1.1 什么是Nosql 1.2 为什么要使用NoSql 1.3 NoSql数据库的优势 1.4 常见的NoSql产品 1.5 各产品的区别 二、Redis介绍 2.1什么是Redis 2.2 Redis优势 2.3 Redis应用场景 2.4 Redis下载 三、Linux下安装Redis 3.1 环境准备 3.2 Redis的…

通过LD_PRELOAD绕过disable_functions

LD_PRELOAD 在UNIX的动态链接库的世界中&#xff0c;LD_PRELOAD就是这样一个环境变量&#xff0c;它可以影响程序的运行时的链接&#xff08;Runtime linker&#xff09;&#xff0c;它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态…

udp与can通信的选择与比较

UDP&#xff08;用户数据报协议&#xff09;和CAN&#xff08;控制器局域网&#xff09;是两种不同的通信协议&#xff0c;它们在实时传递性上有一些区别。 UDP是一种无连接的传输协议&#xff0c;它提供了简单的、不可靠的数据传输。UDP不提供可靠性保证、流控制或重传机制。…

根据源码,模拟实现 RabbitMQ - 内存数据管理(4)

目录 一、内存数据管理 1.1、需求分析 1.2、实现 MemoryDataCenter 类 1.2.1、ConcurrentHashMap 数据管理 1.2.2、封装交换机操作 1.2.3、封装队列操作 1.2.4、封装绑定操作 1.2.5、封装消息操作 1.2.6、封装未确认消息操作 1.2.7、封装恢复数据操作 一、内存数据管理…

protobuf+netty自定义编码解码

protobufnetty自定义编 项目背景 protobufnetty自定义编码解码 比如心跳协议&#xff0c;客户端请求的协议是10001&#xff0c;在java端如何解码&#xff0c;心跳返回协议如何编码&#xff0c;将协议号带过去 // 心跳包 //10001 message c2s_heartbeat { }//10002 message …

【C++笔记】C++之类与对象(中)

【C笔记】C之类与对象&#xff08;中&#xff09; 1、类的构造函数1.1、构造函数的基本用法1.2、构造函数的7个特性 2、类的析构函数2.1、析构函数的基本用法2.2、析构函数的6个特性 3、类的拷贝构造函数3.1、拷贝构造的基本用法3.2、拷贝构造的“无限套娃”陷阱3.3、深拷贝与浅…

二叉树搜索

✅<1>主页&#xff1a;我的代码爱吃辣&#x1f4c3;<2>知识讲解&#xff1a;数据结构——二叉搜索树☂️<3>开发环境 &#xff1a;Visual Studio 2022&#x1f4ac;<4>前言&#xff1a;在之前的我们已经学过了普通二叉树&#xff0c;了解了基本的二叉树…

vue导出文件流获取附件名称并下载(在response.headers里解析filename导出)

导出文件流下载&#xff0c;拦截器统一处理配置 需求以往实现的方法&#xff08;各自的业务层写方法&#xff09;现在实现的方法&#xff08;axios里拦截器统一配置处理&#xff09;把文章链接复制粘贴给后端&#xff0c;让大佬自己赏阅。 需求 之前实现的导出都是各自的业务层…

springboot之多数据源配置

文章目录 一、多数据源的典型使用场景1 业务复杂&#xff08;数据量大&#xff09;2 读写分离 二、如何实现多数据源通过AbstractRoutingDataSource动态指定数据源多数据源切换方式AOPMyBatis插件 三、spring集成多个Mybatis框架 实现多数据源控制四、dynamic-datasource 多数据…

01.Django入门

1.创建项目 1.1基于终端创建Django项目 打开终端进入文件路径&#xff08;打算将项目放在哪个目录&#xff0c;就进入哪个目录&#xff09; E:\learning\python\Django 执行命令创建项目 F:\Anaconda3\envs\pythonWeb\Scripts\django-admin.exe&#xff08;Django-admin.exe所…