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.mzph.cn/news/46066.shtml

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

相关文章

前端框架Vue

Vue 学习路线 学习HTML、CSS和JavaScript基础知识&#xff1a;Vue是基于JavaScript的框架&#xff0c;所以首先需要掌握HTML、CSS和JavaScript的基础知识&#xff0c;包括DOM操作、事件处理、变量和函数等。 学习Vue的基本概念&#xff1a;了解Vue的核心概念&#xff0c;如Vu…

Win10+anaconda+CUDA+pytorch+vscode配置

Win10anacondaCUDApytorchvscode配置 1.安装anaconda2.安装CUDA确认CUDA版本确认CUDA和pytorch版本安装CUDA 3.安装cudnn4.安装Pytorch5.vscode配置安装VScodevscode配置pytorch环境 1.安装anaconda 官网https://www.anaconda.com 下载安装&#xff0c;路径全英文然后记得有一…

【RabbitMQ】消息队列-RabbitMQ篇章

文章目录 1、RabbitMQ是什么1.1、RabbitMQ---使用场景一般场景解耦削峰异步 2、Dokcer安装RabbitMQ2.1安装Dokcer2.2安装rabbitmq 3、RabbitMQ入门案例 - Simple 简单模式4、RabbitMQ的核心组成部分4.1 RabbitMQ整体架构4.2RabbitMQ的运行流程 5、RabbitMQ的模式5.1 发布订阅模…

大数据-玩转数据-Flink App市场推广统计

一、说明 电商网站中已经有越来越多的用户来自移动端&#xff0c;相比起传统浏览器的登录方式&#xff0c;手机APP成为了更多用户访问电商网站的首选。对于电商企业来说&#xff0c;一般会通过各种不同的渠道对自己的APP进行市场推广&#xff0c;而这些渠道的统计数据&#xf…

iOS自定义下拉刷新控件

自定义下拉刷新控件 概述 用了很多的别人的下拉刷新控件&#xff0c;想写一个玩玩&#xff0c;自定义一个在使用的时候也会比较有意思。使应用更加的灵动一些&#xff0c;毕竟谁不喜欢各种动画恰到好处的应用呢。 使用方式如下&#xff1a; tableview.refreshControl XRef…

小程序多图片组合

目录 子组件 index.js 子组件 index.wxml 子组件 index.wxss 父组件引用&#xff1a; 子组件&#xff1a;preview-image 子组件 index.js Component({properties: {previewData: {type: Array,default: [],observer: function (newVal, oldVal) {console.log(newVal, ol…

回归预测 | MATLAB实现GWO-SVM灰狼优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GWO-SVM灰狼优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现GWO-SVM灰狼优化算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基…

图论基础和表示(Java 实例代码)

目录 图论基础和表示 一、概念及其介绍 二、适用说明 三、图的表达形式 Java 实例代码 src/runoob/graph/DenseGraph.java 文件代码&#xff1a; src/runoob/graph/SparseGraph.java 文件代码&#xff1a; 图论基础和表示 一、概念及其介绍 图论(Graph Theory)是离散数…

MySQL基础篇(二)

DML 定义&#xff1a;Data Manipulation Language、数据操作语言&#xff08;增删改&#xff09; 添加数据&#xff08;INSERT&#xff09;修改数据&#xff08;UPDATE&#xff09;删除数据&#xff08;DELETE&#xff09; 添加数据&#xff08;INSERT&#xff09; 给指定的…

Nginx:网站服务

nginx&#xff1a;一个高性能、轻量级的web服务软件 1、稳定性高&#xff08;没有apache稳&#xff09; 2、系统资源消耗低&#xff08;处理http请求的并发能力很高&#xff0c;单台物理服务器可以处理3万到5万个并发请求&#xff09; 稳定&#xff1a;一般在企业中&#xff…

系统架构设计专业技能 · 信息安全技术

系列文章目录 系统架构设计专业技能 网络技术&#xff08;三&#xff09; 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师】 系统架构设计高级技能 …

<数据结构与算法>堆的应用二叉树的链式实现

目录 前言 一、堆的应用 1. 堆排序 1.1 排升序&#xff0c;建大堆 1.2 时间复杂度计算 2. Top k问题 二、 二叉树的链式实现 1. 二叉树的遍历 2. 二叉树基础OJ 2.2 100. 相同的树 总结 前言 学习完堆的数据结构&#xff0c;我们要清楚&#xff0c;它虽然实现了排序功能&am…

售后服务管理软件怎么选择?售后服务管理系统有什么用?

随着企业信息化发展&#xff0c;越来越多的企业纷纷选择售后服务管理软件来服务客户和进行内部人员管理。借助这款软件&#xff0c;企业能够高效地满足客户提出的需求&#xff0c;并提高客户对售后服务的满意度。售后服务通常涉及客户、客服、维修师傅和服务管理人员等各种角色…

用C++/JS/Python/Java代码描述秋天的味道

前言 秋天是一个充满诗意和浪漫的季节&#xff0c;它带来了清新、芬芳和美食的味道。让我们一起探索如何用编程语言来写出秋天味道的代码吧&#xff01;无论是C、JavaScript、Python还是Java&#xff0c;以下是几个简单的步骤来帮助你创造出充满秋天味道的代码&#xff1a; …

Redis缓存问题(穿透, 击穿, 雪崩, 污染, 一致性)

目录 1.什么是Redis缓存问题&#xff1f; 2.缓存穿透 3.缓存击穿 4.缓存雪崩 5.缓存污染&#xff08;或满了&#xff09; 5.1 最大缓存设置多大 5.2 缓存淘汰策略 6.数据库和缓存一致性 6.1 4种相关模式 6.2 方案&#xff1a;队列重试机制 6.3 方案&#xff1a;异步更新缓…

[C++11]

文章目录 1. 自动类型推导1.1 auto1.1.1 推导规则1.1.2 auto的限制1.1.3 auto的应用1.1.4 范围for 1.2 decltype1.2.1 推导规则1.2.2 decltype的应用 1.3 返回类型后置 2.可调用对象包装器、绑定器2.1 可调用对象包装器2.1.1 基本用法2.1.2 作为回调函数使用 2.2 绑定器 3. usi…

idea创建javaweb项目,jboss下没有web application

看看下图这个地方有没有web application

C++_模板进阶_非类型模板参数_模板特化_分离编译

一、非类型模板参数 模板参数&#xff0c;分为类型形参和非类型形参。 类型形参就是在模板中跟在typename和class之后的参数类型名称&#xff0c;非类型形参就是用一个常量作为类模板或者函数模板的一个参数&#xff0c;在类模板和函数模板中&#xff0c;可以将该参数当作常量…

【JUC系列-01】深入理解JMM内存模型的底层实现原理

一&#xff0c;深入理解JMM内存模型 1&#xff0c;什么是可见性 在谈jmm的内存模型之前&#xff0c;先了解一下并发并发编程的三大特性&#xff0c;分别是&#xff1a;可见性&#xff0c;原子性&#xff0c;有序性。可见性指的就是当一个线程修改某个变量的值之后&#xff0c…

卷积神经网络全解:(AlexNet/VGG/ GoogLeNet/LeNet/ResNet/卷积/激活/池化/全连接)、现代卷积神经网络、经典卷积神经网络

CNN&#xff0c;卷积神经网络&#xff0c;Convolution Neural Network 卷积计算公式&#xff1a;N &#xff08;W-F2p&#xff09;/s1 这个公式每次都得看看&#xff0c;不能忘 1 经典网络 按照时间顺序 1.1 LeNet LeNet是 Yann LeCun在1998年提出&#xff0c;用于解决手…