• 猿创征文|School StartsFirstProject~UnityVR(HTCVive设备开发)


    请添加图片描述

    @作者 : SYFStrive

     
    请添加图片描述
     
    质量达到99的文章分享给大家💪

    在这里插入图片描述

    @作者 : SYFStrive

    @博客首页 : HomePage

    🥧: Unity版本2019💪

    📜: VR虚拟现实

    📌:个人社区(欢迎大佬们加入) 👉:社区链接🔗

    📌:觉得文章不错可以点点关注 👉:VR开发专栏🔗

    💃:程序员每天坚持锻炼💪

    🔗:点击直接阅读文章
    请添加图片描述
    在这里插入图片描述
    相关专栏

    👉 VR开发专栏(🔥)


    个人介绍

        我叫XXX,今年上大二,主学游戏开发虚幻引擎、Unity引擎,在校期间开发了很多小Demo我严格要求自己,自觉、遵纪、守时。本人坦诚且有责任心,有独立进取的品性,勤于动手、善于动脑,适应新环境能力很强。能够在最短时间内完成从学生到职业工作人员的转型,尽自己最大的努力融入新的工作生活。

    新学期目标

    ①:学好新学期课程,好好学习天天向上💪
    ②:参加VR虚拟现实比赛
    ③:继续提升学历~争取考公务员💪
    ④:程序员坚持每天锻炼💪

    在这里插入图片描述

    ⑤:在这里插入图片描述

    项目准备与介绍

    • 前期准备如下:
      ①:SteamVR下载步骤 : 下载Steam链接 → 下载SteamVR1.2.2
      ②:VRTK3.2.1下载 :下载链接

    • 项目介绍
      ☺:课程使用HTC Vive设备开发,使用 SteamVR1.2.2 和 VRTK3.2.1 版本开发。
      ☺:将游乐项目在VR里体验,使用新版VRTK实现了射线与UI的交互、新版VRTK的使用。

    设备模样

    在这里插入图片描述
    设备图:

    在这里插入图片描述

    实现效果如下

    在这里插入图片描述

    导入素材

    资源:在这里插入图片描述

    SteamVR:在这里插入图片描述

    VRTK:在这里插入图片描述

    夸克网盘下载 ☑:下载链接

    提取码:PCks

    导入+ 创建相关文件夹如下图:

    在这里插入图片描述

    在这里插入图片描述

    开始页UI简单搭建

    在这里插入图片描述
    效果如下:

    在这里插入图片描述

    开发步骤

    1、使用预制体 Galaxy:

    在这里插入图片描述

    2、调整 Galaxy 和 SteamVR摄像机

    如下图所示:

    在这里插入图片描述

    3、使用SteamVR摄像机

    在这里插入图片描述

    在这里插入图片描述

    4、VR模拟UI界面搭建效果图如下:

    1. 摄像机使用世界坐标:

    在这里插入图片描述

    1. 创建UI调整

    请添加图片描述

    在这里插入图片描述

    5、VRTK 3.2.1v的相关使用

    1. 创建VRTK(添加VRTK_SDK Manager) 👉 创建空GameObject (添加VRTK_SDK Setup组件)

    如👇:

    在这里插入图片描述

    6、手臂发射射线

    要与UI交互需要添加 3个组件:

    在这里插入图片描述

    把renderer添加到PointerRenderer如下:

    在这里插入图片描述

    添加右手炳到RightController

    在这里插入图片描述

    效果如下:

    在这里插入图片描述

    7、UI交互

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    效果如 👇:

    在这里插入图片描述

    bug(射线移进Canvas就会碰撞检测)

    在这里插入图片描述

    解决如下:

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

    射线与UI碰撞的原理如下:

    在这里插入图片描述

    检测自带的碰撞体与刚体如下:

    在这里插入图片描述
    效果如下:

    在这里插入图片描述

    8、射线触发UI播放对于的视频

    在这里插入图片描述

    9、创建LodingPageUI

    效果如下:

    在这里插入图片描述

    10、完成过山车场景

    在这里插入图片描述

    在这里插入图片描述

    VR设画面如下:

    在这里插入图片描述

    10.1、车到达终点播放声音

    如下图:
    在这里插入图片描述

    11、托马斯场景泪水过山车

    在这里插入图片描述

    VR场景如下:

    在这里插入图片描述

    开发相关脚本

    StartPage 脚本

    实现的功能:开始结束按钮的相关逻辑

    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    
    public class StartPage : MonoBehaviour {
    
      //结束按钮
    	private Button startBut;
      //退出按钮
    	private Button exitBut;
    
      private void Awake()
      {
       //获取相关组件
        startBut = transform.Find("StartBut").GetComponent

    ItemManager、EventManager 脚本

    实现的功能:创建动态图片、左右点击按钮相关代码

    ItemManager

    using UnityEngine;
    using DG.Tweening;
    public class ItemManager : MonoBehaviour {
    
    	//单例
    	public static ItemManager instance;
    
    	//获取图片材质球
    	public Material[] materials;
    
    	//图片预制体
    	public GameObject prefabe;
    
    	//旋转的角度
    	private float angle;
    
    	//旋转方向
    	public int risitionDirection;
    
    	private void Awake () {
    
    		//单例
    		instance = this;
    
    		//旋转的方向
    		risitionDirection = 0;
    		
    		//计算图片与图片的角度
    		angle = 360f / materials.Length;
    
    		for (int i = 0; i < materials.Length; i++)
        {
    			//创建图片预制体
    			GameObject itemObj=Instantiate(prefabe, transform);
    			//设置角度
    			itemObj.transform.localEulerAngles=new Vector3(0, i*angle, 0);
    			//设置其图片
    			itemObj.GetComponentInChildren().material = materials[i];
          //播放该图的Audio
          itemObj.GetComponentInChildren().SetVideoName(materials[i].name);
    			//判断射线只能触发当前的页面
    			itemObj.GetComponentInChildren().Index = i;
    		}
    	}
    
    	//右旋转
    	public void RightRisition()
      {
    		risitionDirection++;
    
    		if (risitionDirection>= materials.Length)
        {
    			risitionDirection = 0;
    		}
    
    		transform.DORotate(new Vector3(0, -risitionDirection * angle, 0), 0.3f);
    	}
    
    	//左旋转
    	public void LeftRisition()
    	{
    		risitionDirection--;
    
    		if (risitionDirection < 0)
    		{
    			risitionDirection = materials.Length;
    		}
    
    		transform.DORotate(new Vector3(0, -risitionDirection * angle, 0), 0.3f);
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    EventManager

    using UnityEngine;
    using UnityEngine.UI;
    
    public class EventManager : MonoBehaviour {
    
      //场景名字
      private string[] sceneNameSText;
    
      //名字文本
      public Text sceneNameStext;
      private void Start()
      {
        //右按钮
        transform.Find("Right").GetComponent

    效果如下:

    在这里插入图片描述

    AudioManager脚本

    实现的功能:实现射线碰撞到UI触发相关视频

    using UnityEngine;
    using UnityEngine.Video;
    using VRTK;
    using System.IO;
    
    public class AudioManager : MonoBehaviour {
    
      //获取VideoPlayer组件
      private VideoPlayer video;
    
      public int Index;
      private void Awake()
      {
        //获取VideoPlayer组件
        video = GetComponent();
    
        //获取VRTK_ControllerEvents
        GameObject.Find("Right").GetComponent();
      }
    
      private void Update()
      {
        //判断射线只能触发当前的页面
        if (Index == ItemManager.instance.risitionDirection)
        {
          GetComponent().enabled = true;
          GetComponent().material.color = Color.white;
        }
        else
        {
          GetComponent().enabled = false;
          GetComponent().material.color = Color.gray;
        }
      }
    
    
      /// 
      /// 初始化视屏名字
      /// 
      public void SetVideoName(string videoName)
      {
        video.url = GetVideoPath(videoName);
      }
    
      /// 
      /// 获取视频路径、播放路径
      /// 
      private string GetVideoPath(string videoName)
      {
        return Application.dataPath+"/StreamingAssets/"+ videoName+".mp4";
      }
    
    
      //满足触发条件执行
      private void OnTriggerEnter(Collider other)
      {
        //代表文件不存在 
        if (File.Exists(video.url) == false) return;
        video.Play();
      }
      private void OnTriggerExit(Collider other)
      {
        video.Pause();
      }
    
    
     
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    效果如下:

    在这里插入图片描述

    Loading 脚本

    实现的功能:实现加载相关逻辑

    using System.Collections;
    using UnityEngine;
    using DG.Tweening;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    
    public class Loading : MonoBehaviour
    {
      //单例
      public static Loading Instance;
    
      //加载页UI
      private Image loading;
    
      //异步加载场景AsyncOperation
      private AsyncOperation asyncOn;
    
      //是否加载完成
      private bool isLoad = false;
    
      private void Awake()
      {
        //单例
        Instance = this;
        //找到对应的组件
        loading = transform.Find("Loading").GetComponent();
        transform.localScale = Vector3.zero;
      }
    
      //加载场景
      public void LoadScene()
      {
        //DOTween相关使用
        transform.DOScale(Vector3.one, 0.3f).OnComplete(() =>
        {
          //开启携程
          StartCoroutine("LoadingS");
        });
      }
      IEnumerator LoadingS()
      {
        //startValue
        int displayProgress = -1;
        //endValue
        int toProgress = 100;
    
        while (displayProgress < toProgress)
        {
          displayProgress++;
          //同步UI进度条
          ShowProgress(displayProgress);
    
          if (isLoad == false)
          {
            //场景中有两个初始场景所以从第二个开始算
            asyncOn = SceneManager.LoadSceneAsync(2 + ItemManager.instance.risitionDirection);
            //加载完成不让跳转
            asyncOn.allowSceneActivation = false;
            isLoad = true;
          }
          yield return new WaitForEndOfFrame();
        }
        if (displayProgress == 100)
        {
          //跳转
          asyncOn.allowSceneActivation = true;
          StopCoroutine("LoadingS");
        }
      }
      private void ShowProgress(int progress)
      {
        loading.fillAmount = progress * 0.01f;
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    效果如下:

    在这里插入图片描述

    AntorController 脚本

    实现的功能:实现火车到达终点播放声音

    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class AntorController : MonoBehaviour
    {
      public AudioSource audioS;
    
      private Animation anim;
      /// 
      /// 动画片段的时间
      /// 
      private float clipTime;
      /// 
      /// 是否播放欢呼音效
      /// 
      private bool isPlay = false;
      /// 
      /// 动画是否播放完
      /// 
      private bool isEnd = false;
      /// 
      /// 计时器
      /// 
      private float timer = 0f;
    
      private void Awake()
      {
        //获取相关组件
        anim = GetComponent();
        clipTime = anim.clip.length;
      }
      private void Update()
      {
        clipTime -= Time.deltaTime;
        if (clipTime <= 10 && isPlay == false)
        {
          //到达终点播放声音
          audioS.Play();
          isPlay = true;
        }
        if (clipTime <= 0 && isEnd == false)
        {
          UnityEngine.XR.InputTracking.disablePositionalTracking = false;
          //调整场景
          SceneManager.LoadScene("StartScene");
          //结束游戏
          isEnd = true;
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    最后

    在这里插入图片描述
    本文到这里就结束了,大佬们的支持是我持续更新的最大动力,希望这篇文章能帮到大家💪

     

                     相关专栏连接🔗

    在这里插入图片描述

    下篇文章再见ヾ( ̄▽ ̄)ByeBye

    在这里插入图片描述

  • 相关阅读:
    计算机网络复习03——数据链路层
    JavaWeb -- MySQL
    基于51单片机电子微波炉控制系统(源程序+仿真+原理图+全套资料)
    Python|OpenCV-访问并修改图片像素值,鉴别彩色和灰色图像(6)
    Docker和anaconda的区别?
    【LLS-Player】webrtc m94 修改
    pom.xml中的配置无法被yaml读取
    java毕业生设计医患辅助系统计算机源码+系统+mysql+调试部署+lw
    【发送邮件报错】535 Error:authentication failed
    QT-信号与槽机制学习笔记
  • 原文地址:https://blog.csdn.net/m0_61490399/article/details/126643477