当前位置: 首页 > news >正文

Unity Meta Quest 一体机开发(十三):【手势追踪】自定义交互事件 EventWrapper

文章目录

  • 📕教程说明
  • 📕交互事件概述
  • 📕自定义交互逻辑
    • ⭐方法一:Inspector 面板赋值
    • ⭐方法二:纯代码处理

此教程相关的详细教案,文档,思维导图和工程文件会放入 Spatial XR 社区。这是一个高质量 XR 社区,博主目前在内担任 XR 开发的讲师。此外,该社区提供教程答疑、及时交流、进阶教程、外包、行业动态等服务。

社区链接:
Spatial XR 高级社区(知识星球)
Spatial XR 高级社区(爱发电)

在这里插入图片描述


📕教程说明

这篇教程将会介绍如何用 Meta XR SDK,自定义交互事件触发时执行的逻辑。最后会实现一个功能:用手指点击 UI 按钮后,在前方召唤一把剑。

环境配置可参考:https://blog.csdn.net/qq_46044366/article/details/133967343

配置一个基本的玩家物体可以参考前几期教程:https://blog.csdn.net/qq_46044366/article/details/134097455

系列教程专栏:https://blog.csdn.net/qq_46044366/category_12118293.html

配套的视频链接:
上半部分:https://www.bilibili.com/video/BV1rK4y1B7Zs
下半部分:https://www.bilibili.com/video/BV1vT4y1p7EK

​电脑操作系统:Windows 11

使用的 VR 设备:Meta Quest 3(Quest 系列都适用)

使用的 Unity 版本:2021.3.5 LTS (这里推荐使用 2021 及以上的 LTS 版本)

Meta XR SDK 版本:v57

官方文档:https://developer.oculus.com/documentation/unity/unity-gs-overview/

Event Wrapper 介绍文档:
https://developer.oculus.com/documentation/unity/unity-isdk-event-wrappers/

最终效果:

在这里插入图片描述


📕交互事件概述

交互事件是 XR 开发中经常使用的一个东西。当一个交互动作发生的时候,可能会伴随着一些事情的发生。比如点击一个 “游戏开始” 的UI按钮,就会触发 “游戏开始” 事件,从而对游戏场景里的一些东西进行初始化。这个时候 “点击UI按钮” 就是一个交互事件,对游戏场景里的东西初始化就是这个事件触发后需要执行的事。在 Meta XR SDK 中,交互事件一般会在一个交互过程中的不同状态下触发,以点击 UI 按钮为例,这个动作属于 Poke 交互,我们知道交互的发生需要有 Interactor 和 Interactable 两个对象的参与,那么 Poke 交互对应的 Interactor 在手上,对应的 Interactable 在 UI 按钮物体上。对于 UI 按钮这个 Interactable 来说,当手指靠近按钮的时候,按钮自身会进入到 Hover 状态,这个时刻就可以当作一个交互事件发生了。然后当手指点击到按钮,将按钮按到底的时候,按钮自身会进入到 Select 状态,这边需要注意的是对于一个可以被推动的按钮来说,必须要推到底,也就是推到按钮 Surface 的位置才会进入到 Select 状态,当手指刚刚触碰到按钮表面的时候是不会进入到 Select 状态的。那么进入到 Select 状态这个瞬间也可以当作一个交互事件发生了。

其实前几期教程我们已经有接触到交互事件,我这里是在场景中添加了一个 Poke 教程里配置的 UI 按钮(教程链接:Unity Meta Quest 一体机开发(十二):【手势追踪】Poke 交互 - 用手指点击由 3D 物体制作的 UI 按钮)。

在这里插入图片描述

比如按钮身上的 Interactable Color Visual 脚本,这个脚本能够实现物体在进入不同状态的时候改变物体的颜色。那么这就和交互事件的概念比较像了,进入到不同的状态相当于不同交互事件的触发,改变颜色相当于事件触发后执行的事。Meta XR SDK 会自动检测相应的交互事件什么发生,但是这个脚本把交互事件触发后执行的逻辑写死了,它只能改变物体的颜色,无法处理其他的事。而接下来我会介绍如何去自定义交互事件触发时执行的逻辑。

📕自定义交互逻辑

Meta XR SDK 提供了一个 EventWrapper 的概念,叫做事件包装器(官方文档:https://developer.oculus.com/documentation/unity/unity-isdk-event-wrappers/)。它能够处理 Interaction SDK 中的一些交互事件,并且我们能够自定义交互事件发生时执行的逻辑。如下图所示,Meta 提供了不同类型的 EventWrapper:

在这里插入图片描述

我们这期教程主要关注可交互物体,也就是 Interactable 的交互事件,那么可以使用这两种 EventWrapper:InteractableUnityEventWrapper 和 PointableUnityEventWrapper。这两个脚本有一些相同的交互事件,也有一些不同的交互事件。不过最常用的是下图中标出的 4 个共同的交互事件:

在这里插入图片描述

Hover 是悬停的状态,Interactor 靠近 Interactable 的时候触发。当交互动作完成的时候,也就是 Interactor 选中 Interactable 时,由 Hover 状态转变为 Select 状态。

我们这期教程会介绍 InteractableUnityEventWrapper 脚本的用法,它用起来会稍微简单一点。

我们需要把 InteractableUnityEventWrapper 脚本添加到 UI 按钮物体上:

在这里插入图片描述
我们可以在脚本的 Inspector 面板上看到这个脚本提供的交互事件。

⭐方法一:Inspector 面板赋值

Event Wrapper 提供交互事件,并且检测交互事件什么时候触发。但是触发交互事件后需要执行什么事情需要我们自己处理。第一种处理方式是在 Event Wrapper 脚本的 Inspector 面板上直接进行赋值。我们会实现按下 UI 按钮后在前方生成一把剑的功能,判断什么时候按下 UI 按钮会由 Event Wrapper 来处理,我们这里把按下 UI 按钮视为 Select 交互事件触发,也就是将按钮按到底的时候,触发 Select 事件,然后执行生成剑的逻辑。那么我们需要自己写个脚本实现生成物体的功能,然后让 Event Wrapper 在判断到 Select 事件触发时去调用我们脚本中生成物体的方法。

脚本如下:

using Oculus.Interaction;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ItemSpawner : MonoBehaviour
{public GameObject spawnObj;public Transform spawnPoint;public void SpawnItem(){GameObject obj = GameObject.Instantiate(spawnObj);obj.transform.position = spawnPoint.position;}
}

spawnObj 是需要生成的物体,spawnPoint 是物体生成的位置,SpawnItem 方法负责将需要生成的物体生成在需要生成的位置上。

然后将这个脚本挂载到按钮物体身上,并且在面板上进行赋值:

在这里插入图片描述

我这边将一个剑的模型制作成了 Prefab,拖到了 spawnObj 变量上。然后在按钮物体上新建了一个子物体,作为生成剑的位置。

在这里插入图片描述
我们可以在场景中调整 SpawnPoint 子物体的位置。

然后点击 InteractableUnityEventWrapper 脚本上的 WhenSelect 事件的 “+”号,进行事件触发执行逻辑的添加:

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

在这里插入图片描述

当按钮被按到底的时候, WhenSelect 事件触发,然后调用 SpawnButton 物体上的 ItemSpawner 脚本中的 SpawnItem 方法,在设定的生成点生成剑的游戏物体。

⭐方法二:纯代码处理

我们修改 ItemSpawner 脚本:

using Oculus.Interaction;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ItemSpawner : MonoBehaviour
{public GameObject spawnObj;public Transform spawnPoint;private InteractableUnityEventWrapper eventWrapper;void Start(){eventWrapper = GetComponent<InteractableUnityEventWrapper>();eventWrapper.WhenSelect.AddListener(SpawnItem);}private void OnDestroy(){eventWrapper.WhenSelect.RemoveListener(SpawnItem);}public void SpawnItem(){GameObject obj = GameObject.Instantiate(spawnObj);obj.transform.position = spawnPoint.position;}
}

和方法一的区别是,我们在代码中获取了 InteractableUnityEventWrapper 脚本,然后用代码为 InteractableUnityEventWrapper 的 WhenSelect 事件添加了事件触发后需要执行的方法。

InteractableUnityEventWrapper 的 WhenSelect 事件的监听器(AddListener 方法)需要传入一个 UnityAction 类型的参数。UnityAction 是 Unity 中的一种委托类型,可以绑定无返回值,无参数的方法。我们写的 SpawnItem 方法正好符合条件,所以能直接传入 AddListener 方法中,相当于我们把 SpawnItem 方法的执行委托给了 Event Wrapper,当 Event Wrapper 检测到 WhenSelect 事件触发后,会执行我们委托的事情,也就是调用 SpawnItem 方法,在设定的生成点生成指定的物体。

另外需要注意的是,当我们调用了 AddListener 后,需要在合适的地方调用 RemoveListener 方法,将事件监听器移除掉。

如果我们选用纯代码的方法处理交互事件,就不用在 Unity 的 Inspector 面板中拖拽赋值了。然后 ItemSpawner 脚本需要和 InteractableUnityEventWrapper 脚本挂载到同一个游戏物体身上。

最终效果:

在这里插入图片描述

相关文章:

Unity Meta Quest 一体机开发(十三):【手势追踪】自定义交互事件 EventWrapper

文章目录 &#x1f4d5;教程说明&#x1f4d5;交互事件概述&#x1f4d5;自定义交互逻辑⭐方法一&#xff1a;Inspector 面板赋值⭐方法二&#xff1a;纯代码处理 此教程相关的详细教案&#xff0c;文档&#xff0c;思维导图和工程文件会放入 Spatial XR 社区。这是一个高质量…...

13、Redis高频面试题

1、项目中为什么用Redis 我们项目中之所以选择Redis&#xff0c;主要是因为Redis有下面这些优点&#xff1a; 操作速度快&#xff1a;Redis的数据都保存在内存中&#xff0c;相比于其它硬盘类的存储&#xff0c;速度要快很多数据类型丰富&#xff1a;Redis支持 string&#x…...

Koa学习笔记

1、npm 初始化 npm init -y生成 package.json 文件,记录项目的依赖2、git 初始化 git init生成 .git 隐藏文件夹,.git 的本地仓库创建 .gitignore 文件,添加不提交文件的名称3、创建 ReadMe.md 文件 记录项目笔记4、搭建项目 安装 Koa 框架npm install koa5、编写最基本的…...

HiDataPlus 3.3.2-005 搭建(个人的一点心得体会 x86 平台)

HDP 集群搭建 前置安装 yum -y install createrepo yum install -y lrzsz yum install -y wget yum install -y vim修改当前集群机器的主机名 hostnamectl set-hostname XXX​ 这里的 XXX 就是要设置的当前机器的主机名称。主机名称是集群唯一的&#xff0c;一定不要重复&am…...

【PHP】PHP实现与硬件串口交互,接收硬件发送的实时数据

一、前言 目的&#xff1a;借助虚拟串口软件&#xff08;VSPD&#xff09;模拟硬件串口发送数据&#xff0c;使用PHP语言实现接收硬件发送的数据。 我这里的需求是连接天平&#xff0c;把天平的称量数据实时的传送到PHP使用。 使用工具&#xff1a;vspd串口调试工具 使用语…...

HNU-数据库系统-作业

数据库系统-作业 计科210X 甘晴void 202108010XXX 第一章作业 10.09 1.(名词解释)试述数据、数据库、数据库管理系统、数据库系统的概念。 数据&#xff0c;是描述事物的符号记录。 数据库&#xff08;DB&#xff09;&#xff0c;是长期存储在计算机内、有组织、可共享的大量…...

Python基础知识:整理10 异常相关知识

1 异常的捕获 1.1 基础写法 """基本语法&#xff1a;try:可能发生错误的代码except:如果出现异常&#xff0c;将执行的代码""" try:fr open("D:/abc.txt", "r", encoding"utf-8") except:print("出现异常…...

golang并发安全-select

前面说了golang的channel&#xff0c; 今天我们看看golang select 是怎么实现的。 数据结构 type scase struct {c *hchan // chanelem unsafe.Pointer // 数据 } select 非默认的case 中都是处理channel 的 接受和发送&#xff0c;所有scase 结构体中c是用来存储…...

微软Visual Studio产品之Visual C++编程进阶——一维数组(画画版)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;看到不少初学者在学习编程语言的过程中如此的痛苦&#xff0c;我决定做点什么&#xff0c;我小时候喜欢看小人书&#xff08;连环画&#xff09;&#xff0c;在那个没有电视、没有手机的年代&#xff0c;这是…...

Moonbeam生态项目分析 — — 下一代DeFi协议HydraDX

作者&#xff1a;David 概览 HydraDX是一个基于Substrate区块链框架构建的DeFi协议&#xff0c;旨在为波卡带来大量流动性。HydraDX的特色服务&#xff0c;HydraDX Omnipool&#xff0c;是一种创新的自动化做市商&#xff08;AMM&#xff09;&#xff0c;通过将所有资产组合在…...

Spark九:Spark调优之Shuffle调优

Spark shuffle调优方法 map端和reduce端缓存大小设置&#xff0c;reduce端重试次数和等待时间间隔&#xff0c;以及bypass设置 学习资料&#xff1a;https://mp.weixin.qq.com/s/caCk3mM5iXy0FaXCLkDwYQ 一、map和reduce端缓冲区大小 1.1 map端 在Spark任务运行过程中&…...

linux c多线程优先级

在 Linux 系统中&#xff0c;可以使用 pthread_setschedparam 函数来设置线程的优先级。该函数需要传入一个指向 pthread_t 类型的线程 ID&#xff0c;以及一个指向 struct sched_param 类型的结构体对象。struct sched_param 结构体包含了线程的优先级信息。 下面是一个示例代…...

Redis在项目开发中的应用

Spring Boot集成Redis构建博客应用 在这个示例中&#xff0c;我们将展示如何使用Spring Boot和Redis构建一个简单的博客应用&#xff0c;包括文章发布、点赞和评论功能。 1. 添加依赖 首先&#xff0c;我们需要在pom.xml文件中添加Spring Boot和Redis的依赖项。 <!-- Sp…...

mapper向mapper.xml传参中文时的乱码问题

1.起因&#xff1a; 在idea中进行模糊查询传参时&#xff0c;发现在idea中查中文查不出记录&#xff0c;在navicate中可以查出来。 2.猜测&#xff1a; 1.idea中的编码问题导致的乱码。 2.idea和navicate的编码一致性导致的乱码。 3.mapper向mapper.xml传参后出现乱码。 3.解…...

基于Docker官方php:7.1.33-fpm镜像构建支持67个常见模组的php7.1.33镜像

实践说明&#xff1a;基于RHEL7(CentOS7.9)部署docker环境(23.0.1、24.0.2)&#xff0c;所构建的php7.1.33镜像应用于RHEL7-9(如AlmaLinux9.1)&#xff0c;但因为docker的特性&#xff0c;适用场景是不限于此的。 文档形成时期&#xff1a;2017-2023年 因系统或软件版本不同&am…...

Type-C PD充电器受电端sink诱骗取电汇总:小家电应用5V9V12V15V20V28V

小家电产品、美容产品、电动产品等升级采用Type-C接口&#xff0c;在Type-C接口上使用Type-C取电芯片&#xff0c;即可使用快速充电器的5V、9V、12V、15V、20V供电&#xff0c;无需再配充电器&#xff0c;各类品牌的充电器都可以支持。目前充电器常见的USB-PD功率为&#xff1a…...

禁用code server docker容器中的工作区信任提示

VSCode 添加受限模式&#xff0c;主要是防止自动运行代码的&#xff0c;比如在vscode配置的task和launch参数是可以运行自定义代码的。如果用VScode打开未知的工程文件就有可能直接运行恶意代码。 但是当我们的实验基础模板文件可控的情况下&#xff0c;要想禁用code server do…...

JSON格式插件-VUE

JsonEditor 安装&#xff1a; npm i bin-code-editor -S引入&#xff1a; import Vue from vue; import CodeEditor from bin-code-editor; import bin-code-editor/lib/style/index.css; import App from ./App.vue; Vue.use(CodeEditor); new Vue({el: #app,render: h > …...

dubbo的springboot集成

1.什么是dubbo&#xff1f; Apache Dubbo 是一款 RPC 服务开发框架&#xff0c;用于解决微服务架构下的服务治理与通信问题&#xff0c;官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力&#xff0c; 利用 Dubbo …...

【人工智能】智能电网:未来能源的革命

未来能源的革命 智能电网革命的意义在于将电力行业从传统的集中式发电和集中式输配电模式转变为智能化、分布式、互动式的能源网络。 现在我们从以下方面详细认真的了解一下智能电网&#xff1a; 智能变电站&#xff0c;智能配电网&#xff0c;智能电能表&#xff0c;智能交互…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...