11.9 蓝牙摇杆使用及其他设置功能的实现
上一小节介绍了太阳系VR模式的开发,本小节将要介绍软件设置的开发,其中包括:VR是否开启、摇杆灵敏度调整、音效是否开启以及时间缩放比;设置VR开启和关闭,设置蓝牙摇杆灵敏度调整场景中摄像机运动速度,设置音效开关,设置时间缩放比调整太阳系普通模式场景中的时间因子。
11.9.1 蓝牙摇杆控制脚本开发
蓝牙摇杆可以实现对手机系统桌面的控制,使用Unity 3D游戏开发引擎内置的输入输出监听可以方便地在软件中实现与蓝牙摇杆的控制。在该软件中主要是使用摇杆控制太阳系普通模式的场景中的摄像机实现场景漫游,具体代码如下。
代码位置:见随书源代码/第11章/Universe/Assets/Script目录下的YaoGanControl.cs。
1 using UnityEngine; //导入软件包 2 using UnityEngine.UI; 3 using System.Collections; 4 public class YaoGanControl : MonoBehaviour{ 5 private float[] axisInput = new float[2]; //摇杆参数变量 6 public GameObject PT_Camera; //场景摄像机索引 7 public GameObject Left; //VR摄像机做眼 8 void Start(){ 9 for (int i = 0; i < axisInput.Length; i++) //初始化摇杆参数 10 axisInput[i] = 0.0f;} 11 void Awake(){ 12 gameObject.AddComponent <XuanZhuan>();} //场景加载后给摄像机挂载脚本 13 void Update(){ 14 axisInput[0] = Input.GetAxisRaw("Horizontal") * Time.deltaTime; //获取摇杆横向参数值 15 axisInput[1] = Input.GetAxisRaw ("Vertical") * Time.deltaTime; //获取摇杆竖向参数值 16 if(Constraints.GOD_MANYOU=="GOD"&&Constraints.MS_Selected=="PuTong"){ 17 YG_God();} //普通模式和上帝视角调用方法 18 if(Constraints.GOD_MANYOU=="GOD"&&Constraints.MS_Selected=="VR"){ 19 YG_ManYou();} //VR模式和上帝视角调用方法 20 if(Constraints.GOD_MANYOU=="MANYOU"&&Constraints.MS_Selected=="VR"){ 21 VR_ManYou();} //VR模式和漫游调用方法 22 if(Constraints.GOD_MANYOU=="MANYOU"&&Constraints.MS_Selected=="PuTong"){ 23 YG_ManYou();}} //漫游模式调用方法 24 void VR_ManYou(){ //朝摄像机正方向前进 25 transform.Translate (Left.transform.forward*35*Time.deltaTime);} 26 void YG_ManYou(){ //默认是漫游模式 27 transform.Rotate(Vector3.up*axisInput[1]*Constraints.YG_CanShu); //X即抬头/低头 28 transform.Rotate (Vector3.right*(-axisInput[0])*Constraints.YG_CanShu); //Y即左右旋转 29 transform.Translate (Vector3.forward*35*Time.deltaTime);} //以一定速度前进 30 void YG_God(){ 31 transform.Rotate(Vector3.up*axisInput[1]*30.0f); //X即抬头/低头 32 transform.Rotate (Vector3.right*axisInput[0]*30.0f); //Y即左右旋转 33 if (Input.GetKey(KeyCode.Joystick1Button10)){ //摇杆上Start键监听 34 if(PT_Camera.GetComponent<XuanZhuan>().AngularVelocity==0){ 35 PT_Camera.GetComponent<XuanZhuan>().AngularVelocity=20; //上帝视角旋转 36 }else{ 37 PT_Camera.GetComponent<XuanZhuan>().AngularVelocity=0;}}}} //上帝视角没有旋转 |
第1~7行为导入系统包、定义axisInput、PT_Camera变量。
第8~10行为在场景加载时挂载旋转脚本,以及在运行第一帧之前初始化摇杆参数值。
第11~37行为在太阳系普通模式和虚拟现实模式下对于摇杆的调用方式,在摇杆的使用过程中,还会有旋转脚本需要配合。在VR模式中始终调用VR_ManYou()方法,在太阳系普通模式中则分为上帝视角和漫游两种,前者调用YG_God()方法,后者调用YG_ManYou()方法。
11.9.2 VR开关、摇杆灵敏度、音效及时间缩放因子的开发
上一小节中介绍了蓝牙摇杆控制场景中摄像机的脚本开发,接下来将要介绍VR是否开启、摇杆灵敏度、音效以及时间缩放因子的脚本开发。设置蓝牙摇杆灵敏度可以调整场景中摄像机运动速度,设置音效开关可以控制按键声音大小,设置时间缩放比调整太阳系普通模式场景中的时间因子,具体代码如下。
代码位置:见随书源代码/第11章/Universe/Assets/Script目录下的YaoGanControl.cs。
1 public void toggle_LY_YES(){ //VR开启事件监听 2 Constraints.VR_Alignment = "开启";} 3 public void toggle_LY_NO(){ //VR关闭事件监听 4 Constraints.VR_Alignment = "关闭";} 5 public void toggle_YX_YES(){ //音效开启事件监听 6 Constraints.YinXiao = "open";} 7 public void toggle_YX_NO(){ //音效关闭事件监听 8 Constraints.YinXiao = "close";} 9 public void Slider_Time(){ //时间缩放比事件监听 10 Constraints.timeScale = slider_YG_Time [1].value;} 11 public void Slider_YG(){ //摇杆灵敏度设置 12 Constraints.timeScale = slider_YG_Time [0].value * 10;} |
说明:该脚本中有6个方法toggle_LY_YES、toggle_LY_NO、toggle_YX_YES、toggle_YX_NO、Slider_Time、Slider_YG用于监听Toggle、Slider的数据变化。然后通过设置常量类Constraints里值去改变场景中VR开关、音效、时间缩放、蓝牙摇杆的灵敏度。
11.9.3 主菜单脚本的开发
单击软件图标闪屏之后就进入主菜单界面,在该界面中控制场景切换、模式转换等功能,如图11-82所示,这里需要开发一个脚本来控制这些功能之间的转换,具体代码实现步骤如下。
(1)主界面左侧有4个按钮分别控制星空、太阳系、VR/AR操作说明、设置4个界面或者场景的切换,在按下按钮时会有按键抖动效果,在每个界面或者场景的切换过程中,需要根据常量类中相关默认值初始化界面或者场景设置,具体代码如下。
代码位置:见随书源代码/第11章/Universe/Assets/Script目录下的XieCheng.cs。
1 public void Click_a(){ //星座按钮转换场景事件监听 2 Index = 0; 3 StartCoroutine(Click()); //启用抖动特效协程 4 if(Constraints.YinXiao=="open"){ //添加音效 5 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));} //播放音效 6 Application.LoadLevelAsync ("XingZuo");} //转换星座场景 7 public void Click_b(){ //选择太阳系观测模式 8 Index = 1; 9 StartCoroutine(Click()); //启用抖动特效协程 10 scroll.SetActive(false); //操作说明界面消失 11 moshishezhi.gameObject.SetActive (true); //显示太阳系显示模式 12 if(Constraints.YinXiao=="open"){ //添加音效 13 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));} //播放音效 14 if(Constraints.MS_Selected=="PuTong"){ //选择3种模式 15 Toggle_GM.gameObject.SetActive(true); 16 /*此处省略了选择太阳系模式的代码,有兴趣的读者可以自行查看书中的程序内容进行学习*/ 17 }} 18 public void Click_c(){ //AR/VR操作说明按钮监听 19 Index = 2; 20 StartCoroutine(Click()); //启用抖动特效协程 21 scroll.SetActive(true); //显示操作说明界面 22 if(Constraints.YinXiao=="open"){ //添加音效 23 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));}} //播放音效 24 public void Click_d(){ //"设置"按钮监听 25 Index = 3; 26 StartCoroutine(Click()); //启用抖动特效协程 27 moshishezhi.gameObject.SetActive (false); //太阳系显示模式消失 28 scroll.SetActive(false); //操作说明界面消失 29 shezhi.gameObject.SetActive (true); //显示设置界面 30 if(Constraints.YinXiao=="open"){ //开启音效 31 toggle[2].isOn=true; 32 }else if(Constraints.YinXiao=="close"){ //关闭音效 33 toggle[3].isOn=true;} 34 if(Constraints.YinXiao=="open"){ //添加音效 35 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));}} //播放音效 36 public void Click_e(){ //太阳系中"开始"按钮监听 37 Index = 4; 38 if (Constraints.MS_Selected == "PuTong") { //进入太阳系普通模式场景 39 Application.LoadLevelAsync ("SkyboxBlueNebula_Scene"); 40 } else if (Constraints.MS_Selected == "AR") { //进入太阳系AR场景 41 Application.LoadLevelAsync ("AR"); 42 } else if (Constraints.MS_Selected == "VR") { //进入太阳系VR模式场景 43 Application.LoadLevelAsync("SkyboxBlueNebula_Scene");} 44 if(Toggle_MS[0].isOn==true){ //上帝视角 45 Constraints.GOD_MANYOU="GOD"; 46 }else if(Toggle_MS[1].isOn==true){ //漫游 47 Constraints.GOD_MANYOU="MANYOU";} 48 if(Constraints.YinXiao=="open"){ //添加音效 49 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));}} //播放音效 |
第1~6行为"星座"按钮切换场景事件监听方法,单击按钮之后即可进入"星空"场景。
第7~17行为选择太阳系观察模式的按钮单击事件监听方法,单击该按钮之后VR/AR操作说明和设置界面消失,启用抖动特效协程会有按钮图片抖动效果,同时播放音效。由于太阳系模式选择中会有普通模式(其中包括:上帝视角、漫游)、增强现实(AR)模式、虚拟现实(VR)模式几种选择,在涉及常量类常量赋值时有逻辑关系且简单重复,这里就不再赘述。
第18~23行为VR/AR操作说明界面,单击按钮之后,启用抖动特效协程,然后将太阳系模式选择界面和设置界面消失。
第24~35行为"设置"按钮监听方法,与太阳系模式和VR/AR操作说明监听方法类似,先启用抖动特效协程,再将太阳系模式和VR/AR操作说明界面设置为不可见。接下来就要对"设置"界面进行默认设置。其中包括:实现对VR是否关闭、摇杆、音效、时间缩放比的自定义设置。
第36~49行为太阳系中"开始"按钮监听方法,根据已经选择的模式进入相应的太阳系场景。选择有以下4种可能:太阳系普通模式-上帝时角、太阳系普通模式-漫游、太阳系增强现实(AR)模式、太阳系虚拟现实(VR)模式。
(2)主菜单界面场景加载时有些设置需要初始化,接下来将要介绍场景加载时的运行方法Awake方法,在该方法中主要设置了从其他场景切换回来之后恢复切换之前的选择模式。SpeedDown和Click两个协程方法给出了加载场景时抖动特效,如图11-83所示为单击按钮时的抖动特效。
代码位置:见随书源代码/第11章/Universe/Assets/Script目录下的XieCheng.cs。
1 void Awake(){ 2 if(Constraints.BackTemp==""){ 3 StartCoroutine (SpeedDown ()); //启用抖动协程 4 }else if(Constraints.BackTemp=="back"){ 5 moshishezhi.gameObject.SetActive (true); //模式选择设置为可见 6 if(Constraints.MS_Selected=="PuTong"){ //选择普通模式 7 Toggle_GM.gameObject.SetActive(true); 8 if(Constraints.GOD_MANYOU=="MANYOU"){ //常量为漫游模式 9 ok [0].gameObject.SetActive (true); //选择普通模式 10 ok [1].gameObject.SetActive (false); //取消AR模式 11 ok [2].gameObject.SetActive (false); //取消VR模式 12 Toggle_MS[1].isOn=true; //选择漫游模式 13 }else if(Constraints.GOD_MANYOU=="GOD"){ 14 /*此处省略了在Awake中重复选择模式代码,有兴趣的读者可以自行查看程序内容进行学习*/ 15 } 16 PT_LY_IsOn.gameObject.SetActive(false);}}} 17 IEnumerator SpeedDown(){ //加载场景抖动特效 18 ImageBG.sprite = Index_MainMenu [0]; //替换精灵图片 19 yield return new WaitForSeconds(0.1f); //等待0.1s 20 ImageBG.sprite = Index_MainMenu [1]; //再次替换精灵图片 21 yield return new WaitForSeconds(0.1f); //等待0.1s 22 ImageBG.sprite = Index_MainMenu [2];} //换回无抖动图片 23 IEnumerator Click(){ //单击抖动特效 24 Index_Click [Index].gameObject.SetActive(true); //特效图片可见 25 yield return new WaitForSeconds(0.1f); //等待0.1s 26 Index_Click [Index].gameObject.SetActive (false);} //特效图片不可见 |
第1~16行为场景加载时的运行方法Awake,在该方法中主要设置了从其他场景切换回来之后恢复切换之前的选择模式,以及第一次进入该场景时初始化场景。
第17~26行为两个协程方法给出了加载场景时抖动特效和单击按钮时的抖动特效。实现特效抖动的策略就是配合协程替换经过特别处理的具有抖动效果的精灵图片,经过0.1s的等待之后,替换回原来无抖动效果的精灵图片。
(3)常量类是该软件的中枢,它定义了许多静态公共字符串,利用它可以在主菜单设置、选择等操作之后,改变Constraints常量类中字符串常量,在不同场景或者在不同界面就可以根据这些常量进行不同的初始化调整,具体代码如下。
代码位置:见随书源代码/第11章/Universe/Assets/Script目录下的Constraints.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class Constraints : MonoBehaviour { 4 public static string NameStar = ""; //普通太阳系场景中3D拾取到的物体名称 5 public static string MS_Selected="PuTong"; //主场景中模式选择标志区分 6 public static string GOD_MANYOU = "MANYOU"; //上帝视角或者漫游 7 public static string BackTemp = ""; //记忆从某个场景返回后主菜单显示什么 8 public static string YinXiao = "open"; //是否开启音效 9 public static float timeScale = 0.2f; //时间因子缩放比,"默认是0.2s" 10 public static float YG_CanShu = 5.0f; //设置摇杆灵敏度,"默认是5.0" 11 public static float[] N=new float[8]; //八大行星黄经 12 public static float[] W=new float[8]; //八大行星黄纬 13 public static Vector3 YQ_POS; //月球位置 14 public static string VR_Alignment= "开启"; //控制VR是否开启 15 } |
说明这个类中设置的常量对于星空模块、太阳系模块(普通模式、AR、VR),以及主菜单设置界面都非常重要,它协调各个场景、界面不同功能之间的工作。
11.9.4 陀螺仪脚本开发
星空观察模块最重要的一部分就是对于手机传感器-陀螺仪的使用。在开发陀螺仪脚本的过程中,需要用到3D数学中四元数的相关知识,由于篇幅有限,对于四元数如何使用请读者参考其他有关3D数学方面的书籍。
代码位置:见随书源代码/第11章/Universe/Assets/Script/Line目录下的MobileGyro.cs。
1 using UnityEngine; //导入系统包 2 using UnityEngine.UI; 3 using System.Collections; 4 public class MobileGyro : MonoBehaviour{ 5 Gyroscope gyro; //声明陀螺仪 6 Quaternion quatMult; //声明旋转四元数 7 Quaternion quatMap; //传感器参数组装四元数 8 GameObject player; //声明层 9 GameObject camParent; //声明父对象 10 public AudioClip Sound; //声音资源 11 public void BackToMenu(){ //返回主菜单 12 Application.LoadLevelAsync ("Start"); 13 Constraints.BackTemp = ""; 14 if(Constraints.YinXiao=="open"){ //添加音效 15 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));}} //播放音效 16 public void ToMStar(){ //返回主菜单 17 if(Constraints.YinXiao=="open"){ //添加音效 18 AudioSource.PlayClipAtPoint(Sound,new Vector3(0,0,0));}//设置播放片段的位置 19 Application.LoadLevelAsync ("MStar");} //切换到M界面 20 void Awake(){ 21 Transform currentParent = transform.parent; //获取摄像机父对象 22 camParent = new GameObject ("camParent"); //实例化一个空对象 23 camParent.transform.position = transform.position; //给定位置 24 transform.parent = camParent.transform; //移到实例化的对象之下 25 GameObject camGrandparent = new GameObject ("camGrandParent");//实例化空对象 26 camGrandparent.transform.position = transform.position; //给定位置 27 camParent.transform.parent = camGrandparent.transform; //作为父对象 28 camGrandparent.transform.parent = currentParent; //将摄像机挂载到子对象 29 gyro = Input.gyro; //返回默认的陀螺仪 30 gyro.enabled = true; //打开手机陀螺仪 31 camParent.transform.eulerAngles = new Vector3(90,0, 0); //绕x轴旋转90° 32 quatMult = new Quaternion(0, 0, 1, 0);} 33 void Update(){ //陀螺仪参数组装四元数 34 quatMap = new Quaternion(gyro.attitude.x, gyro.attitude.y, gyro.attitude.z, gyro.attitude.w); 35 Quaternion qt = quatMap * quatMult; //旋转 36 transform.localRotation = qt;}} //给摄像机实时旋转 |
第1~10行为导入系统包,声明下面方法中所需要的各种变量。
第11~19行为两个监听事件方法-BackToMenu、ToMStar,前者是从星空场景返回主菜单的事件监听,后者是从星空场景进入梅西耶天体列表场景中,在单击按钮时都会有音效产生。
第20~36行为实现通过手机传感器-陀螺仪,控制场景摄像机进行场景漫游的功能。在开启传感器之前,首先对摄像机进行一下重新挂载组装,即将摄像机挂载在子对象的位置,然后通过开启传感器之后获取参数组装四元数用于各个方向的旋转。
说明:对于该脚本可以作为一个脚本工具使用,将它挂载在场景中的主摄像机上,即可实现陀螺仪控制场景中摄像机旋转。由于四元数过于复杂,请读者参考其他3D数学书籍。
11.10 本章小结
本章对星空漫游这款软件做出了简要介绍,应用中实现了星空观察、太阳系天体认知(普通模式、增强现实模式、虚拟现实模式)等功能,读者在项目开发过程中可以以本应用作为参照。星空观察模块还可以进一步开发成星座定位功能,希望广大读者可以在此基础上进行再次开发。
说明:本书中只是将本应用中难以理解但比较重要的部分进行了介绍,还有一些部分并未详细叙述,不熟悉的读者可以进一步根据需要参考其他的相关资料或书籍。
本文选自《VR及AR开发高级教程—基于Unity》第七章,本站经人民邮电出版社和作者的授权。
版权声明:51Testing软件测试网获清华大学出版社和作者授权连载本书部分章节。任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。