@作者 : SYFStrive
质量达到99的文章分享给大家💪
@作者 : SYFStrive
@博客首页 : HomePage
🥧: Unity版本2019💪
📜: VR虚拟现实
📌:个人社区(欢迎大佬们加入) 👉:社区链接🔗
📌:觉得文章不错可以点点关注 👉:VR开发专栏🔗
💃:程序员每天坚持锻炼💪
🔗:点击直接阅读文章
👉 VR开发专栏(🔥)
目录
- 个人介绍
- 新学期目标
- 项目准备与介绍
- 设备模样
- 实现效果如下
- 导入素材
- 开始页UI简单搭建
- 开发步骤
- 1、使用预制体 Galaxy:
- 2、调整 Galaxy 和 SteamVR摄像机
- 3、使用SteamVR摄像机
- 4、VR模拟UI界面搭建效果图如下:
- 5、VRTK 3.2.1v的相关使用
- 6、手臂发射射线
- 7、UI交互
- 8、射线触发UI播放对于的视频
- 9、创建LodingPageUI
- 10、完成过山车场景
- 10.1、车到达终点播放声音
- 11、托马斯场景泪水过山车
- 开发相关脚本
- StartPage 脚本
- ItemManager、EventManager 脚本
- AudioManager脚本
- Loading 脚本
- AntorController 脚本
- 最后
个人介绍
我叫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界面搭建效果图如下:
- 摄像机使用世界坐标:
- 创建UI调整
5、VRTK 3.2.1v的相关使用
- 创建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<Button>();exitBut = transform.Find("EquitBut").GetComponent<Button>();}private void Start(){//开始按钮绑定相关事件startBut.onClick.AddListener(() =>{SceneManager.LoadScene("Scene2");});//结束按钮绑定相关事件exitBut.onClick.AddListener(() =>{Application.Quit();});}
}
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<MeshRenderer>().material = materials[i];//播放该图的AudioitemObj.GetComponentInChildren<AudioManager>().SetVideoName(materials[i].name);//判断射线只能触发当前的页面itemObj.GetComponentInChildren<AudioManager>().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);}}
EventManager
using UnityEngine;
using UnityEngine.UI;public class EventManager : MonoBehaviour {//场景名字private string[] sceneNameSText;//名字文本public Text sceneNameStext;private void Start(){//右按钮transform.Find("Right").GetComponent<Button>().onClick.AddListener(() =>{ItemManager.instance.RightRisition();});//左按钮transform.Find("Left").GetComponent<Button>().onClick.AddListener(() =>{ItemManager.instance.LeftRisition();});//中间事件transform.Find("Center").GetComponent<Button>().onClick.AddListener(() =>{Loading.Instance.LoadScene();});//获取Resources文件夹里面的Text文本ReadSceneName();}private void Update(){//同步文本sceneNameStext.text = sceneNameSText[ItemManager.instance.risitionDirection];}/// <summary>/// 获取resourcesText/// </summary>private void ReadSceneName(){TextAsset textAsset = Resources.Load<TextAsset>("unityVR");sceneNameSText=textAsset.text.Split('\n');}
}
效果如下:
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<VideoPlayer>();//获取VRTK_ControllerEventsGameObject.Find("Right").GetComponent<VRTK_ControllerEvents>();}private void Update(){//判断射线只能触发当前的页面if (Index == ItemManager.instance.risitionDirection){GetComponent<MeshCollider>().enabled = true;GetComponent<MeshRenderer>().material.color = Color.white;}else{GetComponent<MeshCollider>().enabled = false;GetComponent<MeshRenderer>().material.color = Color.gray;}}/// <summary>/// 初始化视屏名字/// </summary>public void SetVideoName(string videoName){video.url = GetVideoPath(videoName);}/// <summary>/// 获取视频路径、播放路径/// </summary>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();}}
效果如下:
Loading 脚本
实现的功能:实现加载相关逻辑
using System.Collections;
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
using UnityEngine.SceneManagement;public class Loading : MonoBehaviour
{//单例public static Loading Instance;//加载页UIprivate Image loading;//异步加载场景AsyncOperationprivate AsyncOperation asyncOn;//是否加载完成private bool isLoad = false;private void Awake(){//单例Instance = this;//找到对应的组件loading = transform.Find("Loading").GetComponent<Image>();transform.localScale = Vector3.zero;}//加载场景public void LoadScene(){//DOTween相关使用transform.DOScale(Vector3.one, 0.3f).OnComplete(() =>{//开启携程StartCoroutine("LoadingS");});}IEnumerator LoadingS(){//startValueint displayProgress = -1;//endValueint 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;}
}
效果如下:
AntorController 脚本
实现的功能:实现火车到达终点播放声音
using UnityEngine;
using UnityEngine.SceneManagement;public class AntorController : MonoBehaviour
{public AudioSource audioS;private Animation anim;/// <summary>/// 动画片段的时间/// </summary>private float clipTime;/// <summary>/// 是否播放欢呼音效/// </summary>private bool isPlay = false;/// <summary>/// 动画是否播放完/// </summary>private bool isEnd = false;/// <summary>/// 计时器/// </summary>private float timer = 0f;private void Awake(){//获取相关组件anim = GetComponent<Animation>();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;}}
}
最后
本文到这里就结束了,大佬们的支持是我持续更新的最大动力,希望这篇文章能帮到大家💪相关专栏连接🔗
下篇文章再见ヾ( ̄▽ ̄)ByeBye