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

news2024/12/23 17:42:07

文章目录

  • 📕教程说明
  • 📕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.coloradmin.cn/o/903027.html

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

相关文章

ARM 配置晶振频率

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

Java-数组

什么是数组 数组&#xff1a;可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。 在java中&#xff0c; 数组中存放的元素其类型相同数组的空间是连在一起的每个空间有自己的编号&#xff0c;起始位置的编号为0&#xff0c;即数组的下标。 数组的创建及初始化 数…

FL Studio21最新版本升级中文语言教程

FL中文提供了跨版本升级&#xff0c;用户可以通过下载21入门版或其他非完整版的版本&#xff0c;升级为更高的版本&#xff0c;解锁更多的插件&#xff0c;下面为大家介绍在下载升级服务后&#xff0c;如何进行升级版本。 FL Studio 21 Win-安装包下载如下:https://wm.makeding…

CTF工具隐写分离神器Binwalk安装和详细使用方法

binwalk安装 1.Binwalk 介绍&#xff1a;2.Binwalk下载&#xff1a;3.Windows安装&#xff1a;4.Linux下载安装&#xff1a;5.Binwalk基本用法&#xff1a;6.Binwalk案例展示&#xff1a;7.Binwalk总结&#xff1a; 1.Binwalk 介绍&#xff1a; Binwalk 是用于搜索给定二进制镜…

Java之线程的状态

文章目录 一、线程状态二、代码演示1. Threadstate 类2. SleepUtils 类3. 运行示例 三、参考资料 一、线程状态 Java线程在运行的生命周期中可能处于下图所示的6种不同的状态,在给定的一个时刻线程只能处于其中的一个状态。 Java线程的状态 状态名称说明NEW初始状态&#xff0…

QCustomPlot的X轴是时间轴的曲线绘制

主要设置X轴的参数 SharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime); timeTicker->setTimeFormat("%h:%m:%s");demo如下 Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);dataTimer …

53 个 CSS 特效 1

53 个 CSS 特效 1 预计是会跟着教程做完 53 个小项目10 个大型的 Responsive 项目&#xff0c;预览地址在http://www.goldenaarcher.com/html-css-js-proj/&#xff0c;git 地址&#xff1a;https://github.com/GoldenaArcher/html-css-js-proj 实用性有加备注&#xff0c;可…

漏洞指北-VulFocus靶场专栏-初级02

漏洞指北-VulFocus靶场02-初级 初级005 &#x1f338;phpunit 远程代码执行 (CVE-2017-9841)&#x1f338;step1&#xff1a;进入漏洞页step2&#xff1a; burpsuite 抓包,等待请求页&#xff0c;获得flag 初级006 &#x1f338;splunk 信息泄露 &#xff08;CVE-2018-11409&am…

【操作系统】24王道考研笔记——第三章 内存管理

第三章 内存管理 一、内存管理概念 1.基本概念 2.覆盖与交换 覆盖技术&#xff1a; 交换技术&#xff1a; 总结&#xff1a; 3.连续分配管理方式 单一连续分配 固定分区分配 动态分区分配 动态分区分配算法&#xff1a; 总结&#xff1a; 4.基本分页存储管理 定义&#xf…

基于空间的图卷积神经网络:GNN

目录 欧氏空间中神经网络发挥巨大最作用&#xff0c;DNA&#xff0c;知识图谱三维或者多维空间不行 邻接矩阵实现图结构的矩阵化表示&#xff1a;造梦师 局和操作实现层内消息传递&#xff1a;带线的连接机传递消息 GCN通过邻域聚合实现特征提取 SVM支持向量机 ​编辑 硬分…

浅析Java设计模式之四策略模式

title: 浅析Java设计模式之四策略模式 date: 2018-12-29 17:26:17 categories: 设计模式 description: 浅析Java设计模式之四策略模式 1. 目录 1. 目录2. 概念 2.1. 应用场景2.2. 优缺点 2.2.1. 优点2.2.2. 缺点 3. 模式结构4. 样例 4.1. 定义策略4.2. 定义具体策略4.3. 定义…

用 VB.net,VBA 两种方式 读取单元格内的 换行数据,并出力到 CSV文件

用 VB.net&#xff0c;VBA 两种方式 读取单元格内的 换行数据&#xff0c;并出力到 CSV文件 需求 如下图所示&#xff0c;为了生成csv文件导入数据库&#xff0c;需要将下图 的 1 和 2 拼接成 如下 3 所示的一行数据&#xff0c; 开头为 1 &#xff0c;往后为 2 的换行数据 将换…

整理mongodb文档:批量操作

个人博客 整理mongodb文档:批量操作 个人公众号&#xff0c;求关注&#xff0c;文章如有不明&#xff0c;请指出。 文章概叙 本文讲的是关于bulkwrite的用法&#xff0c;依旧是在shell下使用。 关于批量操作 Performs multiple write operations with controls for order …

Eureka:服务注册-信息配置-自我保护机制

首先在提供者服务下&#xff0c;添加一个依赖 <!-- Eureka --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId><version>1.4.6.RELEASE</version><…

【模块系列】AHT10温湿度模块

前言 以下是AHT10模块官网介绍原话。还有就是官网已经显示停产了&#xff0c;不过淘宝还是有小模块玩玩的。 AHT10是一款高精度&#xff0c;完全校准&#xff0c;贴片封装的温湿度传感器&#xff0c;MEMS的制作工艺&#xff0c;确保产品具有极高的可靠性与卓越的长期稳定性。传…

【网络基础】数据链路层

【网络基础】数据链路层 文章目录 【网络基础】数据链路层1、对比网络层2、以太网2.1 基本概念2.2 类似技术2.3 以太网帧 3、MAC地址对比IP地址 4、MTU4.1 对IP协议影响4.2 对UDP协议影响4.3 对TCP协议影响4.4 地址、MTU查看 5、ARP协议5.1 协议作用5.2 协议工作流程5.3 数据报…

第一章:SpringBoot基础入门

第一章&#xff1a;SpringBoot基础入门 1.1&#xff1a;Spring与SpinrBoot Spring能做什么 Spring的能力 Spring的生态 网址&#xff1a;https://spring.io/projects/spring-boot 覆盖了&#xff1a;Web开发、数据访问、安全控制、分布式、消息服务、移动开发、批处理等。 …

面试题 : Top-k问题

目录 题目 示例 提示 开始解题 1.思路 2.解题代码 3.时间复杂度 4.运行结果 ​编辑 目前问题 真正的解法 1.以找前K个最大的元素为例 2.代码执行过程&&时间复杂度的计算 3.画图演示代码执行过程 4.解题代码 两种解法的比较 完结撒花✿✿ヽ(▽)ノ✿✿ …

CAPL通过lookupSignal和DBLookup获取DBC信号的属性信息

文章目录 演示CAPL通过lookupSignal和DBLookup获取DBC信号的属性信息lookupSignalDBLookup代码问题:DBLookup(信号名).AttributeName报错问题: motorola格式的信号使用DBLookup获取信号的bitstart跟ig模块里的信息不一样演示 CAPL通过lookupSignal和DBLookup获取DBC信号的属性…