用unity XR interaction Toolkit 制作垃圾分类虚拟仿真项目

项目效果演示:

垃圾分类虚拟仿真项目演示

1.环境配置

选择universal 3D(通用渲染管道)项目(不然导入素材包会丢失材质)。

选择Window->Package Manager,安装其中的XR interaction Toolkit。

选择其中的Samples,导入Starter Assets。

选择Edit->Project Settings->XR Plugin Management进行安装。

如果要用电脑模拟器进行VR控制,需要选择Edit->Project Settings->XR interaction Toolkit,勾选 Use XR Devcie Simulator in scenes。

选择Assets\Samples\XR Interaction Toolkit\2.5.4\Starter Assets路径位置下的DemoScene场景,打开运行,观察是否能进行控制。

2.选择界面场景制作(StartScene)

主要功能:射线交互实现主场景(mainScene)和测试场景(TestScene)两个场景的跳转。

新建场景命名为“StartScene”,将DemoScene场景文件拖入Hierarchy面板,把其中的XR interaction Setup拖入到StartScene场景中,点击运行,进行测试。

导入素材包Classification_Resourse.unitypackage,将Assets\Polytope Studio\Lowpoly_Demos\Environment_Free路径位置的Environment_Free场景文件中拖入Hierarchy面板。

把Environment_Free所有元素拖入到StartScene场景中并删除其中的Player游戏对象,把XR interaction Setup作为某个场景元素的子物体,对XR interaction Setup游戏对象的Transform进行reset重置,然后进行手动的坐标调整,就可以在场景中漫游。同时可以对场景元素进行删减与范围缩小,还可以通过设置下图中colliders的位置,限制主体漫游的范围。

导入素材包Classification_Resourse.unitypackage,新建画布Canvas和图像Image和按钮Button(Legacy),选择Assets\Resourse\01图片路径下中3D面板背景图片赋值给image组件,效果大致如下图:

接下来,为UI元素添加组件使其可以进行VR射线交互,为画布添加Tracked Device Graphic Raycaster组件,为按钮添加XR Poke Follow Affordance组件。

编写脚本SkipController.cs,用于控制脚本的跳转。

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.SceneManagement;//挂载在选择界面上,用于界面的跳转。public class SkipController : MonoBehaviour{// Start is called before the first frame update//控制返回主界面方法public void LoadScene(string sceneName){SceneManager.LoadScene(sceneName); // 加载指定名称的场景}}

新建空物体,命名为SkipController,将脚本挂载到该物体上,给两个按钮添加点击事件,如下图所示:

提前创建两个场景主场景(mainScene)和测试场景(TestScene),选择File->Build Settings,将三个场景拖入到Scene In Bulid中进行Build,随后测试是否能实现界面的跳转。

3.主界面场景制作(mainScene)

主要功能:通过VR抓取进行与垃圾的交互,需要将垃圾投入到正确的垃圾桶中,通过碰撞体检测和检测类型是否匹配,从而判断否正确分类,进行记录和反馈,也可以跳转到测试界面。

打开mainScene场景文件,导入素材包LowPolyTropicalEnvironment_LITE.unitypackage,将Assets\LowPolyTropicalEnvironment_LITE\Scenes路径位置的TropicalEnvironmentLite_Demo场景文件中拖入Hierarchy面板。

把TropicalEnvironmentLite_Demo所有元素拖入到StartScene场景中并删除其中的摄像头的游戏对象,再把DemoScene中的XR interaction Setup拖入到场景中,把其作为某个场景元素的子物体,进行坐标的调整,效果如下图,进行测试。

接下来进行垃圾分类场景的搭建,将Assets\Resources\02 模型 路径位置下的垃圾桶拖入场景中,调整四个垃圾桶的位置,将Assets\Resources\01 图片 路径位置下的干垃圾、有害垃圾、湿垃圾、可回收的图片拖入场景中,作为垃圾桶的子物体,进行位置的调整。

在Project面板右击,选择create->matertial,调整材料的颜色,并把该材质拖入到Scene中的垃圾桶上(调整整体和轮子的颜色)。

最终效果如下图所示:

为垃圾桶添加碰撞体,选择4个垃圾桶,添加Mesh Collider组件,不勾选Convex选项。

同时需要在底部创建一个碰撞体,用于检测是否分类正确。在Hierarchy面板中,选择垃圾桶右击,选择3D Object->Plane,作为其子物体,编写脚本Trash Can.cs:

using System.Collections;using System.Collections.Generic;using UnityEngine;//用枚举类型区分垃圾类型public enum GarbageType{recyclable,//可回收wet,//湿垃圾dry,//干垃圾hazardous//有害垃圾}//挂载在垃圾桶上public class TrashCan : MonoBehaviour{// Start is called before the first frame updatevoid Start(){}public GarbageType type; // 垃圾桶类型//垃圾桶底部设置碰撞体,用于碰撞检测,返回垃圾桶本身和垃圾的类型给控制器进行逻辑判断。private void OnCollisionEnter(Collision collision){Garbage garbage = collision.collider.GetComponent<Garbage>();if (garbage != null){ClassificationManager.Instance.OnGarbageCollision(garbage.type, type);Debug.Log("当前垃圾桶的类型为:" + type + "    当前垃圾桶的类型为: " + garbage.type);if (type != garbage.type){garbage.ResetToStartPosition();}}}}

然后挂载在该物体上,同时Plane需要进行调整位置、颜色,设置对应的类型。

将Assets\Resources\02 模型 路径位置下的“桌子”模型拖入场景中,调整到合适的大小和为止,为其添加Box Collider组件,点击Edit Collider,调整其碰撞体大小,同时添加Rigidbody组件,勾选Is Kinematic选项,使其不会受碰撞影响。

将Assets\Resources\02 模型 路径位置下的“大猩猩手办”、“可乐罐”、“药品2”、“蛋糕”、“陶瓷杯”、“电池”的模型拖入场景中,部分模型需要手动拖动material进行填色。

随后选中所有物体,为其添加Box Collider、Rigidbody、XR Grab Interactable组件,在Box Collider组件中点击Edit Collider,单独调整其碰撞体大小,并将物体放置在桌面上。

新建脚本Garbage.cs,并挂载在物体上。

using System.Collections;using System.Collections.Generic;using UnityEngine;//挂载在垃圾类上public class Garbage : MonoBehaviour{public GarbageType type; // 垃圾类型private Vector3 originalPosition; // 原始位置private Rigidbody rb;private void Start(){rb = GetComponent<Rigidbody>();originalPosition = transform.position;}//当被错误分类时调用,用于把垃圾重新放回桌子上public void ResetToStartPosition(){transform.position = originalPosition;rb.velocity = Vector3.zero;rb.angularVelocity = Vector3.zero;}}

在Garbage(Script)组件中设置每个物体的类型Type,类型如下表:

模型

实际垃圾类型

设置的Type

大猩猩手办

可回收

Recycle

可乐罐

可回收

Recycle

药品

有害

Hazardous

蛋糕

湿垃圾

Wet

陶瓷杯

干垃圾

Dry

电池

有害

Hazardous

创建脚本ClassificationManager.cs,用于垃圾分类逻辑处理。

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;using UnityEngine.Events;//挂载在主界面(垃圾分类)上的控制器public class ClassificationManager : MonoBehaviour{public static ClassificationManager Instance; // 单例模式public GameObject correctUI;//正确UIpublic GameObject incorrectUI;//错误UIpublic AudioSource audiosource;//播放器public AudioClip correctSound;//正确音效public AudioClip incorrectSound;//错误音效public GameObject CountUI;//用于统计正确分类的个数private int Count=0;//个数private void Start(){correctUI.SetActive(false);incorrectUI.SetActive(false);CountUI.SetActive(true);CountUI.GetComponent<Text>().text = "你目前正确分类的物体个数为:" + Count;}//用于判断垃圾和垃圾桶是否是同一类别的public void OnGarbageCollision(GarbageType garbageType, GarbageType trashCanType){if (garbageType == trashCanType){CorrectDispose();Count += 1;}else{IncorrectDispose();}CountUI.GetComponent<Text>().text = "你目前正确分类的物体个数为:" + Count;Debug.Log("Your score is: " + Count);}private void CorrectDispose(){audiosource.clip = correctSound;audiosource.Play();incorrectUI.SetActive(false);//控制UI先显示,2秒后消失correctUI.SetActive(true);Invoke("DisappearObject", 2f);}private void IncorrectDispose(){audiosource.clip = incorrectSound;audiosource.Play();correctUI.SetActive(false);incorrectUI.SetActive(true);Invoke("DisappearObject", 2f);}//挂载在按钮上,界面跳转public void LoadScene(string sceneName){SceneManager.LoadScene(sceneName); // 加载指定名称的场景}private void DisappearObject(){correctUI.SetActive(false);incorrectUI.SetActive(false);}}

在场景中创建一个空物体,命名为ClassificationManager,把创建的脚本挂载上去,为其添加Audio Source组件,对脚本中的Audiosource进行赋值,同时将Assets\Resources\03 音效 路径位置下的“正确音效”、“错误”文件拖入到Correct Sound和Incorrect Sound中进行赋值,效果如下图所示:

接下来,需要制作UI界面,需要在场景中新建画布Canvas、用于显示已分类数量的Text(Legacy)和用于跳转界面的按钮Button(Legacy)。同时新建3个Image游戏对象,用于显示背景、正确图像和错误图像,将Assets\Resources\01 图片 路径位置下“回顾3”、“正确”、“错误”的图片赋值给Image,修改UI元素名称,便于区分,调整UI元素位置,最终效果如下图所示:

为了使其能进行VR射线交互,给画布添加Tracked Device Graphic Raycaster组件,为按钮添加XR Poke Follow Affordance组件。

接下来继续给ClassificationManager物体进行参数的赋值。

进行测试,是否能进行判断垃圾分类的正误并进行反馈。

4.测试场景制作(TestScene)

主要功能:能通过射线交互,能进行选择题选项的选择和判断题的对错的选择。

首先导入素材,打开TestScene场景文件,将DemoScene场景文件拖入Hierarchy面板,把其中的XR interaction Setup拖入到StartScene场景中,Assets\Resources\02 模型 路径位置下的房屋模型导入到场景中,调整位置,让XR interaction Setup处于房屋之中,效果大致如下图,进行测试。

接下来要进行答题界面的制作,我们可以打开Assets\Resources\06 考题 路径位置下的垃圾分类考题文件,进行题干和选项的内容的设置。

首先新建一个画布Canvas,调整位置,为其添加TrackedDeviceGraphicRaycaster组件。新建Image子物体,设置画布的背景图片。

然后题目中有单选题和判断题,需要进行区分。创建脚本Question.cs,用于区别题型和设置答案:

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;//挂载在具体题目上(判断题、选择题)public class Question: MonoBehaviour{public Toggle[] options; // 单选题的选项public int correctAnswerIndex; // 单选题正确答案的索引public Toggle trueFalseToggle; // 判断题的Togglepublic bool correctAnswer; // 判断题的正确答案public bool isChoice; // 判断是选择题还是判断题}

接下进行题目的UI制作。

选择题的制作(以第一题为例):

创建一个空物体作为新建画布的子物体,命名为Question1。为其挂载Question脚本,并设置属性如下图所示(4个选项、D选项为正确选项,为选择题),点击Options下方“+”号,设置数量为4,设置Correct Answer Index的值为3,勾选 Is Choice选项。

同时为Question1游戏对象添加Toggle Group组件,用于控制其子对象的Toggle只能被选中一个,用于模拟单选题。同时勾选Allow Switch Off 选项,允许程序运行时,可以没有默认的勾选选项。

在Question1下新建Text(Lecary)和4个Toggle,作为其子物体,调整位置、颜色,并对选项进行取名(1_A,1_B,1_C,1_D),便于与后面的选择题选项区分。同时需要为每一个Toggle游戏对象添加XR Poke Follow Affordance组件。

选项新建完成后,对Question1的Question组件中的Option进行赋值,如下图所示:

这样一道选择题的设置就完成了。

判断题的制作(以第二题为例):

创建一个Toggle作为画布Panel的子物体,命名为Question2,为其挂载XR Poke Follow Affordance组件,同时挂载Question脚本,并设置属性如下图所示(答案为正确,为判断题),勾选Correct Answer选项,不勾选Is Choice。

新建一个Text(Legacy)作为Question2游戏对象的子物体,编辑其内容,显示题干,如下图所示:

这样一道判断题就编辑好了,按如下的两种方式将5道题目编辑好后(注意命名要进行区分),我们还需要提交按钮和返回主界面的按钮Button和显示分数的UI。在画布中新建两个按钮Button(Legacy),分别命名为returnButton、SubmitButton,新建Text(Legacy),命名为Score,在Hierarchy面板中将returnButton拖到到Score下,作为其子物体。

调整其位置,最后效果如下图所示:

到此为止,我们UI界面制作完毕。

接下来我们需要新建脚本TestController.cs,用于实现判断对错、交互的功能:

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;//挂载在测试界面的控制器上。public class TestController : MonoBehaviour{public List<Question> questions; // 包含所有问题的列表public int score = 0; // 最终得分public GameObject ScoreUI;private void Start(){ScoreUI.SetActive(false);  }// 用户点击提交按钮时调用的方法public void SubmitAnswers(){score = 0;foreach (Question question in questions){      //如果是选择题if (question.isChoice){// 单选题if (question.options[question.correctAnswerIndex].isOn){score++;}}else{// 判断题if (question.trueFalseToggle.isOn== question.correctAnswer){score++;}}}ScoreUI.SetActive(true);ScoreUI.GetComponent<Text>().text = "你的最终得分是:" + (score*1.0/questions.Count)*100;Debug.Log("Your score is: " + score);// 可以在这里添加代码显示得分或者转到下一个场景}//控制返回主界面方法public void LoadScene(string sceneName){SceneManager.LoadScene(sceneName); // 加载指定名称的场景}}

新建空物体,命名为TestController,挂载上该脚本,对Questions和Score UI属性进行赋值,如下图所示:

为两个按钮分别添加跳转场景的功能和提交答案的功能,添加点击事件,如下图所示:

最后进行测试,功能是否正常。

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

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

相关文章

基于web的便捷饭店点餐小程序的设计与实现(lw+演示+源码+运行)

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

快速入门HTML

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗 如有错误&#xff0c;欢迎指出~ 目录 第一个html文件 标签 h1~h6 p >段落标签 br > 换行标签 img >图片标签 a >超链接标签 表格标签 表单标签 表单控件 form表单 ⽆语义标签:div&span 综…

【简道云 -注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

C#与C++交互开发系列(十七):线程安全

前言 在跨平台开发和多线程编程中&#xff0c;线程安全是不可忽视的重要因素。C和C#中提供了各自的线程同步机制&#xff0c;但在跨语言调用中&#xff0c;如何确保数据一致性、避免数据竞争和死锁等问题&#xff0c;是开发人员必须考虑的重点。 本文将介绍在C#和C交互开发中确…

docker-minio启动参数

完整命令 docker run -p 9000:9000 -p 9090:9090 -v /opt/minio/data:/data -d --name minio -d --restartalways -e "MINIO_ACCESS_KEYminio" -e "MINIO_SECRET_KEYminioadmin123" minio/minio server --console-address ":9090" -address &…

理解 CSS 中的绝对定位与 Flex 布局混用

理解 CSS 中的绝对定位与 Flex 布局混用 在现代网页设计中&#xff0c;CSS 布局技术如 flex 和绝对定位被广泛使用。然而&#xff0c;这两者结合使用时&#xff0c;可能会导致一些意想不到的布局问题。本文将探讨如何正确使用绝对定位元素&#xff0c;避免它们受到 flex 布局的…

书生大模型实战营 L0 入门岛

书生大模型训练营入门岛任务——训练营链接 1. Linux前置知识 任务&#xff1a;端口转发 当使用vscode远程连接服务器时&#xff0c;在服务器运行的任务&#xff0c;vscode会自动帮忙进行端口映射&#xff0c;方便本地进行访问。 2. Python前置知识 任务1&#xff1a;Leec…

网络搜索引擎Shodan(2)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 声明&#xff1a;本文主要用作技术分享&#xff0c;所有内容仅供参考。任何使用或依赖于本文信息所造成的法律后果均与本人无关。请读者自行判断风险&#xff0c;并遵循相关法律法规。 感谢泷…

Linux 练习三

1、建立用户组 shengcan&#xff0c;其id 为 2000 [rootlocalhost 桌面]# groupadd -g 2000 shengchan 2、建立用户组 caiwu&#xff0c;其id 为 2001 [rootlocalhost 桌面]# groupadd -g 2001 caiwu 3、建立用户组 jishu&#xff0c;其 id 为 2002 [rootlocalhost 桌面]#…

Docker Compose一键部署Spring Boot + Vue项目

目录 前提条件 概述 Compose简介 Compose文件 Compose环境 Compose命令 帮助命令 关键命令 Compose部署项目 初始化环境 查看代码文件 sql数据准备 nginx配置文件准备 创建 compose.yaml 一键启动compose多个容器 浏览器访问虚拟机ip:80(可省略默认的80端口) …

C语言 | Leetcode C语言题解之第522题最长特殊序列II

题目&#xff1a; 题解&#xff1a; #define MAX(a, b) ((a) > (b) ? (a) : (b))bool is_subseq(const char *s, const char *t) {int pt_s 0, pt_t 0;int len_s strlen(s), len_t strlen(t);while (pt_s < len_s && pt_t < len_t) {if (s[pt_s] t[pt_…

第二十三章 Vue组件通信之非父子组件通信

目录 一、引言 1.1. event bus 事件总线 1.1.1. 实现步骤 1.2. provide & inject 1.2.1. 实现步骤 二、event bus事件总线完整代码 2.1. 工程结构图 ​2.2. main.js 2.3. App.vue 2.4. EventBus.js 2.5. BaseC.vue 2.6. BaseB.vue 2.7. BaseA.vue 三、provi…

无人机之自动控制原理篇

一、飞控系统 无人机飞控是指无人机的飞行控制系统&#xff0c;是无人机的大脑。飞控系统通过传感器、控制器和执行机构三部分实现对无人机的自动控制。 传感器&#xff1a;传感器负责收集无人机的姿态、速度、高度等信息。常见的传感器包括陀螺仪、加速度计、磁力计、气压计、…

JS实现图片放大镜效果

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><styl…

链表:两数相加

目录 LeetCode2 两数相加 LeetCode445 两数相加II LeetCode2 两数相加 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* …

练习LabVIEW第二十九题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第二十九题&#xff1a; 设计一评分程序&#xff0c;输入不同的分数会得到不同的评论。 分数小于60&#xff0c;“警告”指…

Unity3D 开发教程:从入门到精通

Unity3D 开发教程&#xff1a;从入门到精通 Unity3D 是一款强大的跨平台游戏引擎&#xff0c;广泛应用于游戏开发、虚拟现实、增强现实等领域。本文将详细介绍 Unity3D 的基本概念、开发流程以及一些高级技巧&#xff0c;帮助你从零基础到掌握 Unity3D 开发。 目录 Unity3D…

3.2 大数据概念、特征与价值

文章目录 大数据的概念美国高德纳咨询公司的定义麦肯锡全球研究所的定义狭义和广义的大数据 大数据的特征Volume&#xff08;体积&#xff09;Variety&#xff08;种类&#xff09;Velocity&#xff08;速度&#xff09;Value&#xff08;价值&#xff09;Veracity&#xff08;…

扫雷游戏(C语言详解)

扫雷游戏&#xff08;C语言详解&#xff09; 放在最前面的1、前言&#xff08;扫雷游戏的简介&#xff09;2、扫雷游戏的规则&#xff08;简易版&#xff09;3、代码实现&#xff08;3.1&#xff09;提醒一下&#xff1a;( i ) 提醒1&#xff1a;( ii ) 提醒2&#xff1a; &…

WPF+MVVM案例实战(十四)- 封装一个自定义消息弹窗控件(下)

文章目录 1、案例效果2、弹窗空间使用1.引入用户控件2、按钮命令实现 3、总结4、源代码获取 1、案例效果 2、弹窗空间使用 1.引入用户控件 打开 Wpf_Examples 项目&#xff0c;在引用中添加用户控件库&#xff0c;在 MainWindow.xaml 界面引用控件库&#xff0c;代码如下&…