Unity游戏案例开发大全
上QQ阅读APP看书,第一时间看更新

4.4 主菜单界面

前一小节介绍了游戏的整体架构,从本节开始将介绍本案例场景的开发,首先介绍本案例的主菜单场景,该场景在游戏开始时呈现,控制所有界面之间的跳转,主要开发步骤如下。

4.4.1 基本场景的搭建

(1)创建项目文件夹。首先在电脑的某个磁盘下新建一个空的文件夹“FPSGame”,笔者的项目文件夹创建在“E:\Unit3DWorkspace”文件夹下,如图4-14所示。

▲图4-14 创建项目文件夹

(2)创建工程。双击桌面的Unity快捷方式打开Unity,选择“Create New Project”,然后单击“Browse...”按钮选择刚刚创建的“FPSGame”空文件夹,最后单击“Create”按钮,如图4-15所示。

▲图4-15 创建工程

(3)导入资源。将本游戏所要用到的资源分类整理好,然后将分类好的资源都复制到项目文件夹下的“Assets”文件夹下,如图4-16所示。然后在Unity界面,单击“File”→“Save Scene”保存场景,取名为“MenuScene.unity”。

▲图4-16 导入资源

说明

本游戏中所有的资源文件都已经整理好了,放在“第04章/资源包”文件夹下。读者可自行将“第04章/资源包”文件夹下的所有文件夹复制到项目文件夹下的“Assets”文件夹下。

(4)导入NGUI资源包。双击NGUI安装包,导入NGUI资源,如图4-17所示。单击“import”按钮,导入完成后重启Unity,可以看到在工具栏处出现了NGUI按钮。读者如果电脑上没有NGUI资源包,可自行从网上搜索下载。

▲图4-17 导入NGUI资源包

(5)因为NGUI自带摄像机,所以需要首先删除“Main Camera”对象,然后单击“NGUI”→“Create”→“Panel”按钮,即可看到在左侧窗口创建了一个NGUI Panel,选中“Panel”,将其重命名为“Window_Panel”,如图4-18所示。

▲图4-18 创建NGUI Panel

(6)制作图集。单击“NGUI”→“Open”→“Atlas Maker”,之后读者可以在Project视窗中打开Assets/MenuTestures文件夹,用鼠标选中所有图片,在Atlas Maker窗口中写上图集名字“menuAtlas”,单击Create按钮。之后可看到在MenuTestures文件夹下面多了三个文件menuAtlas.mat、menuAtlas.png、menuAtlas.prefab,如图4-19所示。

▲图4-19 制作图集

(7)创建NGUI Button。单击“NGUI”→“Open”→“Widget Wizard”,在Template中选择“Button”,Atlas选择刚才创建的menuAtlas图集,Background选择想要在按钮上显示的图片,之后单击“Add To”即可在Window_Panel下面创建一个按钮,如图4-20所示。

▲图4-20 创建NGUI Button

(8)单击“Add Component”→“NGUI”→“Interaction”→“Button Message”。之后设置在Inspector属性窗口中将Camera拖动到“Target”中,Trigger选中为“OnClick”,Function Name填上“ExitGame”。编写脚本“CameraEventMask.cs”并挂载到摄像机上。脚本代码如下。

代码位置:见随书光盘中源代码/第04章/FPSGame/Assets/Scripts/MenuScripts目录下的CameraEventMask.cs。

      1   using UnityEngine;
      2   using System.Collections;
      3   public class CameraEventMask : MonoBehaviour {
      4   ......//此处省略了其他函数和变量等的声明,请读者自行查阅光盘
      5   void ExitGame(){                                        //退出游戏按钮的回调方法
      6        Application.Quit();                                //退出应用
      7   }}

说明

当单击“Exit_Btn”按钮的时候,此按钮会向Target指定的对象发送消息,该消息将寻找所有挂载到Target对象上的Scripts脚本中的Function Name函数,并执行此函数。

(9)其他按钮也是通过这样的方式创建的,当用户单击某个按钮的时候,此按钮会发送消息,然后调用相应的函数,完成指定的功能。接下来介绍一下几个搭建NGUI其他效果的方法。

4.4.2 其他常用界面效果的实现

(1)关闭窗口效果的实现。为不同的NGUI控件设置不同的LayerMask,然后当单击关闭窗口的时候,设置摄像机只渲染游戏需要的Layer,这样可以达到显示和隐藏NGUI控件的效果。在CameraEventMask.cs脚本中,大家可看到这样的函数。

代码位置:见随书光盘中源代码/第04章/FPSGame/Assets/Scripts/MenuScripts目录下的CameraEventMask.cs。

      1   using UnityEngine;
      2   using System.Collections;
      3   public class CameraEventMask : MonoBehaviour {
      4   ......//此处省略了其他函数和变量等的声明,请读者自行查阅光盘
      5   public LayerMask mainMask;                              //主菜单界面mask
      6   public LayerMask otherMask;                             //其他界面mask
      7   void SetOtherMask(){
      8        uiCamera.eventReceiverMask = otherMask.value;     //设置摄像机的mask为otherMask
      9   }
      10   void SetMainMask(){
      11      uiCamera.eventReceiverMask = mainMask.value;       //设置摄像机的mask为mainMask
      12  }

提示

给NGUI控件设置Layer名称之后,一定要将Camera的Culling Mask(如图4-21所示)和UICamera脚本中的Event Mask(如图4-22所示)设置为相应的Layer层。摄像机默认Culling Mask层为default,即默认对default层进行渲染,因此如果不进行设置的话,屏幕上将什么也看不到。

▲图4-21 设置Culling Mask

▲图4-22 设置Event Mask

(2)界面图片的变化。本游戏中,界面图片的变化是通过设置NGUI控件的隐藏和显示实现此效果的。以关闭声音为例,当单击按钮的时候,声音按钮将会发送消息调用下面的函数以实现声音开启和关闭按钮图片的更换。脚本代码如下。

代码位置:见随书光盘中源代码/第04章/FPSGame/Assets/Scripts/MenuScripts目录下的CameraEventMask.cs。

      1   ......//此处省略了其他函数和变量等的声明,请读者自行查阅光盘
      2   void SoundOn_Btn()  {                                   //开枪声音按钮的回调方法
      3        PlayerPrefs.SetInt("sound",0);                    //存储声音状态
      4        audioListener.enabled = false;                    //禁用audioListener
      5        soundOffBtn.SetActive(true);                       //声音关闭按钮的显示
      6        soundOnBtn.SetActive(false);                       //声音开启按钮的隐藏
      7   }

说明

通过调用精灵自身的SetActive方法来实现对相应精灵的隐藏和显示。

(3)滑动条的实现。在设置面板中,利用滑动条控制敌人血量和游戏时间。制作滑动条需要先创建一个NGUI Slider控件,然后添加NGUI自带的脚本Slider,然后在属性窗口中,分别为各个属性赋值。图4-23所示给出的是血条属性的设置窗口。

▲图4-23 设置滑动条属性

(4)编写“SliderTest.cs”脚本,然后附加到上面Notify属性指定的LabelObj对象上,则当移动滑动条的时候,会执行SliderTest.OnSliderChange方法,用PlayerPrefs达到动态存储变量值的效果。脚本代码如下。

代码位置:见随书光盘中源代码/第04章/FPSGame/Assets/Scripts/MenuScripts目录下的SliderTest.cs。

      1   using UnityEngine;
      2   using System.Collections;
      3   public class SliderTest : MonoBehaviour {
      4   ......//此处省略了其他函数和变量等的声明,请读者自行查阅光盘
      5   public void OnSliderChange() {                     //当Slider的Value改变时的回调方法
      6        float value = Slider.value;                   //获取Slider的值
      7        switch(curWidge) {
      8             case Widget.time:                        //滑动时间轴
      9                  PlayerPrefs.SetInt(curWidge.ToString(), (int)(value * 300) + 300);//存储时间
      10                 Lable.text = (PlayerPrefs.GetInt(curWidge.ToString())).ToString();//显示
      11            break;
      12            case Widget.enemyblood:                  //滑动血条轴
      13                 PlayerPrefs.SetInt(curWidge.ToString(), (int)(value * 100) + 100);//存储血量
      14                 Lable.text = (PlayerPrefs.GetInt(curWidge.ToString())).ToString();//显示
      15            break;
      16  }}

说明

通过Slider.value来得到当前滑动条的值,再根据curWidge所指示的精灵的不同,来判断当前操作的是滑动时间轴还是滑动血条轴,滑动的时候及时存储滑动条的值,然后动态地改变标签上值的显示。

(5)动态加载界面滚动条的制作。单击“开始”按钮,将会进入异步加载游戏场景的界面,一个绿色的滚动条在屏幕上水平滚动。做到这样的效果其实很简单,只需要动态改变屏幕上文字和精灵(滚动条)的位置即可。

代码位置:见随书光盘中源代码/第04章/FPSGame/Assets/Scripts/MenuScripts目录下的LoadScene.cs。

      1   using UnityEngine;
      2   using System.Collections;
      3   public class LoadScene : MonoBehaviour {
      4         ......//此脚本省略了部分变量和函数,如需查看完整代码,请参考光盘。
      5         public GameObject showObj;                        //需要显示的对象
      6         public GameObject hideObj;                        //需要隐藏的对象
      7         AsyncOperation asyncOperation;                    //异步对象
      8         private UILabel loadingLabel;                     //显示“加载中”的Label组件
      9         public Transform progressBar;
      10        private string[] loadTxt = { "加载中。 ",
      11                           "加载中。。", "加载中。。。" };     //加载场景时显示的字符串
      12        private float count = 0;                          //计数器
      13        private float currentTime;                        //记录当前时间
      14        void LoadGameScene() {
      15             hideObj.SetActive(false);                   //隐藏对象
      16             showObj.SetActive(true);                    //显示对象
      17             StartCoroutine(LoadingAnimation());         //启动加载动画的协程方法
      18        }
      19        IEnumerator LoadingAnimation() {
      20             yield return new WaitForSeconds(0.1f);      //等待0.1秒
      21             asyncOperation = Application.LoadLevelAsync("GameScene");
      22             while (!asyncOperation.isDone) {            //加载未完成
      23                   int index = (int)count % 3;           //对count取值
      24                   loadingLabel.text = loadTxt[index];   //更新UILabel
      25                   count += Time.deltaTime * 3;          //计数器自加
      26                   Vector3 locationPosition = progressBar.localPosition;//获取进度条父节点
      27                   locationPosition.x += Time.deltaTime * 500;    //改变进度条位置
      28                   locationPosition.x=(locationPosition.x>200)?-200:locationPosition.x;
      29                   yield return new WaitForSeconds(0.01f);        //等待0.01秒
      30  }}}

第14行~第18行先使界面中需要隐藏的界面隐藏,接着使界面需要显示的元素显示,然后使用StartCoroutine方法异步调用LoadingAnimation方法,这样可以实现在不至于影响前台界面元素显示的情况下,后台动态加载主游戏场景资源的效果。

第19行~第29行用Application.LoadLevelAsync异步加载主游戏界面未完成的情况下,每隔0.01秒便重新给加载文字和加载滚动条的位置赋值,从而使其达到动态更新Label文字和滚动条位置的效果。