- Unity游戏案例开发大全
- 吴亚峰 杜化美 于复兴编著
- 6010字
- 2020-06-27 12:19:02
2.4 主菜单界面
前一小节介绍了游戏的整体架构,从本节开始将介绍本案例场景的开发,首先介绍本案例的主菜单场景,该场景在游戏开始时呈现,控制所有界面之间的跳转,主要开发步骤介绍如下。
2.4.1 项目的基本创建
在这一小节,首先对项目的新建以及资源的准备进行详细的介绍,读者可以通过一些基本的操作,对该游戏的开发有一个较好的开始。详细步骤如下。
(1)新建项目文件夹。首先在电脑的某个磁盘下新建一个空文件夹“Table3D”,笔者的项目文件夹新建在“F:\U3D”文件夹下,如图2-22所示。
▲图2-22 新建项目文件夹
(2)新建工程。双击桌面的Unity快捷方式打开Unity,选择“Create New Project”,然后单击“Browse...”按钮,选择刚刚新建的“Table3D”空文件夹,最后单击“Create”按钮,如图2-23所示。
▲图2-23 新建工程
(3)导入资源。将本游戏所要用到的资源分类整理好,然后将分类好的资源都复制到项目文件夹下的“Assets”文件夹下,如图2-24所示。
▲图2-24 导入资源
说明
本游戏中所有的资源文件都已经整理好了,放在“第02章/资源包”文件夹下。读者可自行将“第02章/资源包”文件夹下的所有文件夹复制到项目文件夹下的“Assets”文件夹下。
(4)创建脚本文件夹。在项目资源列表中,单击鼠标右键,在弹出的菜单中选择“Create”→“Folder”,创建脚本文件夹,命名为“Scripts”,如图2-25所示。并用同样的方法,在Scripts文件夹下创建“MenuScript”脚本文件夹和“GameScript”脚本文件夹,如图2-26所示。
▲图2-25 创建脚本文件夹
▲图2-26 创建两个文件夹
(5)创建脚本。单击项目资源列表中的MenuScripts文件夹,单击鼠标右键,在弹出的快捷菜单中选择“Create”→“C# Script”命令,创建脚本,如图2-27所示。将脚本命名为“ConstOfMenu.cs”,如图2-28所示。创建好脚本后,就可以根据游戏开发的相应需要进行编写了。
▲图2-27 创建脚本
▲图2-28 脚本
2.4.2 脚本的编写与挂载
前一小节,大家已经对项目的初始化有了很好的理解,下面开始介绍脚本的编写,以及本游戏主菜单界面的开发所需要的各个脚本的功能。
(1)编写常量类脚本。双击“ConstOfMenu.cs”脚本,进入“MonoDevelop”编辑器中,开始脚本的编写。该脚本主要负责初始化游戏开发所需用的各类常量。详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的ConstOfMenu.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class ConstOfMenu : MonoBehaviour{ 4 public static float desiginWidth = 800.0f; //标准屏的宽度 5 public static float desiginHeight = 480.0f; //标准屏的与高度 6 public static int START_BUTTON = 0; //开始按钮的索引 7 public static int MUSSIC_BUTTON = 1; //声音设置按钮的索引 8 public static int HELP_BUTTON = 2; //帮助按钮的索引 9 public static int ABOUT_BUTTON = 3; //关于按钮的索引 10 public static int EIGHT_BUTTON = 0; //八球模式按钮的索引 11 public static int NINE_BUTTON = 1; //九球模式按钮的索引 12 public static int COUNTDOW_BUTTON = 0; //倒计时模式按钮的索引 13 public static int PRACTICE_BUTTON = 1; //练习模式按钮的索引 14 public static int RANK_BUTTON = 2; //排行榜按钮的索引 15 public static float movingSpeed = 80f; //主界面按钮的移动速度 16 public static float[] ButtonPositionOfX = new float[4] { 128, 416, 128, 416 }; //主界面按钮的位置 17 public static float[] ButtonMovingStep = new float[4] { 1, -1, 1, -1 }; //主界 面按钮的移动方向 18 public static float[] BPositionXOfMode = new float[3] { 128, 416, 128 }; //模 式选择界面按钮位置 19 public static float[] BMovingXStepOfMode = new float[3] { -1, 1, -1 }; //按钮移动方向 20 public static float movingSpeedOFMode = 80f; //该界面按钮的移动速度 21 public static int MainID = 1; //主菜单界面ID 22 public static int ChoiceID = 2; //种类选择界面ID 23 public static int SoundID = 3; //声音控制界面ID 24 public static int HelpID = 4; //帮助界面ID 25 public static int AboutID = 5; //关于界面ID 26 public static int ModeChoiceID = 6; //模式选择界面界面ID 27 public static int RankID = 7; //排行榜界面ID 28 public static Matrix4x4 getMatrix() //GUI自适应矩阵 29 { 30 Matrix4x4 guiMatrix = Matrix4x4.identity; //获取单位矩阵 31 float lux = (Screen.width - ConstOfMenu.desiginWidth * Screen.height 32 / ConstOfMenu.desiginHeight) / 2.0f; //计算位移距离 33 guiMatrix.SetTRS(new Vector3(lux,0,0), //设置GUI矩阵 34 Quaternion.identity, new Vector3(Screen.height / ConstOfMenu.desiginHeight, 35 Screen.height / ConstOfMenu.desiginHeight, 1)); 36 return guiMatrix; //返回该矩阵 37 } 38 public static Matrix4x4 getInvertMatrix() //GUI逆矩阵 39 { 40 Matrix4x4 guiInverseMatrix = getMatrix(); //获取GUI矩阵 41 guiInverseMatrix = Matrix4x4.Inverse(guiInverseMatrix); //计算GUI逆矩阵 42 return guiInverseMatrix; //返回该矩阵 43 }}
第4行~第15行定义了标准屏幕的高度与宽度,分别为800与480的屏幕高宽。同时为各个界面上涉及的按钮定义索引,方便后续处理使用。第15行定义了主菜单界面按钮动态移动效果的速度。
第16行~第20行定义了主菜单界面以及游戏模式选择界面的各个按钮的位置以及移动方向。两个界面上的按钮采用了动态移动的效果,为达到效果美观,按钮初始化位置对称,同时在按钮运动方向上采用了交叉运动的方式。
第21行~第27行定义了游戏所涉及的各个界面的ID,方便脚本开发过程中的管理和使用。其中包括主菜单界面、声音控制界面、关于界面、帮助界面、游戏种类选择界面、游戏模式选择界面以及排行榜界面。
第28行~第43行为游戏自适应矩阵方法,获取玩家手机屏幕高度、宽度,通过严格的矩阵计算,重新为矩阵赋值。已达到该游戏在任何设备上都能进行自适应呈现的目的。
(2)挂载常量类脚本。将Project界面内的常量脚本,拖曳到游戏对象“Main Camera”上,如图2-29、图2-30所示。
▲图2-29 脚本挂载1
▲图2-30 脚本挂载2
(3)编写主菜单界面脚本“MainLayer.cs”。创建脚本过程前面已经详细介绍,此处不再赘述。该脚本主要负责搭建主菜单界面以及4个按钮初始化的动态效果等工作。详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的MainLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class MainLayer : MonoBehaviour { 4 public Texture backgroundOfMainMenu; //菜单界面背景图片 5 public GUIStyle[] buttonStyleOfMain; //菜单界面按钮图样式 6 private float[] ButtonPositionOfX = new float[4]; //创建按钮数组 7 private float buttonOfficerOfHeight; //按钮之间的高度差 8 private float startYOfMainMenu; //第一个按钮的起始Y坐标 9 public bool moveFlag; //主菜单界面按钮是否进行移动的标志位 10 private float buttonOfCurrentMovingDistance; //主菜单界面按钮当前移动的距离 11 private float buttonOfMaxDistance; //主菜单界面按钮移动的最大距离 12 private Matrix4x4 guiMatrix; //GUI矩阵 13 void Start () { 14 buttonOfficerOfHeight = 75; //初始图片的高度 15 startYOfMainMenu = 150; //主菜单界面首个按钮位置 16 moveFlag = true; //按钮移动的标志位 17 restData(); //重新设置位置等信息 18 buttonOfCurrentMovingDistance = 0; //按钮移动距离 19 buttonOfMaxDistance = 80; //按钮最大移动距离 20 guiMatrix = ConstOfMenu.getMatrix(); //获取GUI自适应矩阵 21 } 22 void OnGUI(){ 23 GUI.matrix = guiMatrix; //设置GUI自适应矩阵 24 GUI.DrawTexture(new Rect(0, 0, ConstOfMenu.desiginWidth, 25 ConstOfMenu.desiginHeight), backgroundOfMainMenu); //绘制背景图片 26 DrawMainMenu(); //绘制menu界面 27 if (moveFlag) { //判断是否允许移动 28 ButtonOfManiMenuMove(); //若标志位为移动,则调用移动方法 29 } 30 } 31 public void restData(){ //重新设置数据的方法 32 for (int i = 0; i < ConstOfMenu.ButtonPositionOfX.Length; i++){ 33 ButtonPositionOfX[i] = ConstOfMenu.ButtonPositionOfX[i]; //设置位置 34 } 35 buttonOfCurrentMovingDistance = 0; //重置当前移动距离为0 36 moveFlag = true; //移动的标志位置为true 37 } 38 ……//此处省略了DrawMainMenu方法,将在下面进行介绍 39 ……//此处省略了ButtonOfManiMenuMove方法,将在下面进行介绍 40 }
第4行~第12行声明了按钮图以及按钮样式,同时创建了主菜单界面4个按钮的数组。第7行和第8行声明4个按钮之间的高度差以及第一个按钮的起始Y坐标,方便了游戏开发后续的其他3个按钮的位置确定。
第13行~第21行为Start方法,该方法主要初始化定义了按钮的高度以及第一个按钮的位置,将按钮移动标志位置为true。调用restData方法,重新设置按钮初始化默认的位置。同时定义了按钮移动的当前距离和最大距离,为按钮动态移动效果做了准备。
第22行~第30行为OnGUI方法,设置GUI自适应矩阵,通过矩阵计算后,绘制主菜单界面的背景图,并调用DrawMainMenu方法绘制主菜单界面。同时判断按钮移动标志位,若标志位为true,则调用ButtonOfManiMenuMove方法,实现按钮动态移动效果。
第31行~第37行为重新设置数据的方法,一旦重新设置位置,主菜单界面4个按钮全部回归为初始化位置,当前移动距离置为0,同时移动标志位置为true。
(4)前面介绍了主菜单界面脚本,接下来介绍上述代码省略的绘制主菜单界面“DrawMainMenu”方法和按钮移动“ButtonOfManiMenuMove”方法,脚本代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的MainLayer.cs。
1 void DrawMainMenu(){ //绘制主菜单界面 2 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.START_BUTTON], 3 startYOfMainMenu + buttonOfficerOfHeight * 0, 256, 64), 4 "", buttonStyleOfMain[ConstOfMenu.START_BUTTON])){ //如果单击开始游戏按钮 6 if (!moveFlag){ //如果按钮没有移动 7 (GetComponent("Constroler") as Constroler).ChangeScrip( 8 ConstOfMenu.MainID, ConstOfMenu.ChoiceID); //实现从主界面跳转到种类选择界面 9 }} 10 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.MUSSIC_BUTTON], 11 startYOfMainMenu + buttonOfficerOfHeight * 1, 256, 64), 12 "", buttonStyleOfMain[ConstOfMenu.MUSSIC_BUTTON])){ //如果单击声音控制按钮 13 if (!moveFlag) { //如果按钮没有移动 14 (GetComponent("Constroler") as Constroler).ChangeScrip( 15 ConstOfMenu.MainID, ConstOfMenu.SoundID);//实现从主界面跳转到声音设置界面 16 }} 17 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.HELP_BUTTON], 18 startYOfMainMenu + buttonOfficerOfHeight * 2, 256, 64), 19 "", buttonStyleOfMain[ConstOfMenu.HELP_BUTTON])) { //如果单击帮助按钮 20 if (!moveFlag){ //如果按钮没有移动 21 (GetComponent("Constroler") as Constroler).ChangeScrip( 22 ConstOfMenu.MainID, ConstOfMenu.HelpID); //实现从主界面跳转到帮助界面 23 }} 24 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.ABOUT_BUTTON], 25 startYOfMainMenu + buttonOfficerOfHeight * 3, 256, 64), 26 "", buttonStyleOfMain[ConstOfMenu.ABOUT_BUTTON])){ //如果单击关于按钮 27 if (!moveFlag){ //如果按钮没有移动 28 (GetComponent("Constroler") as Constroler).ChangeScrip( 29 ConstOfMenu.MainID, ConstOfMenu.AboutID); //实现从主界面跳转到关于界面 30 }}} 31 void ButtonOfManiMenuMove(){ //按钮移动的方法 32 float length = ConstOfMenu.movingSpeed * Time.deltaTime; //按钮移动的距离 33 buttonOfCurrentMovingDistance += length; //按钮移动一次 34 for (int i = 0; i < ButtonPositionOfX.Length; i++){ //设置按钮的位置 35 ButtonPositionOfX[i] += (ConstOfMenu.ButtonMovingStep[i] * length); } //按钮交叉方向移动 36 moveFlag = buttonOfCurrentMovingDistance < buttonOfMaxDistance; //计算是否移动到最大距离 37 }
第2行~第16行为绘制主菜单界面的两个按钮,其中包括开始游戏按钮、声音控制按钮。在主菜单界面加载时按钮有动态效果,按钮处于静态时,用户方可单击按钮实现界面跳转。当用户单击开始游戏按钮,界面跳转至游戏种类选择界面;当用户单击声音控制按钮,界面跳转至游戏音乐及音效开关界面。
第17行~第30行为绘制主菜单界面的两个按钮,其中包括帮助按钮和关于按钮。当用户单击帮助按钮和关于按钮时,分别跳转至帮助界面和关于界面,供用户查看。
第31行~第37行为控制主菜单界面按钮移动方法,为了实现4个按钮交叉移动的效果,在规定的时间内让按钮匀速交叉运动,实时更改按钮的位置。最终呈现按钮的动态初始化效果。
(5)挂载主菜单界面脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值,可参考如图2-31所示的脚本变量赋值。
图2-31 脚本变量赋值
(6)前面介绍了主菜单界面脚本所有方法,接下来介绍控制界面跳转脚本,该脚本主要负责各个界面之间的跳转调度,并将其挂载到游戏对象“Main Camera”上,详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。其详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的Constroler.cs。
1 using UnityEngine;
2 using System.Collections;
3 public class Constroler : MonoBehaviour { 4 private int currentID = ConstOfMenu.MainID; //初始当前界面ID 5 MonoBehaviour[] script; //声明脚本组件 6 void Awake() { 7 script = GetComponents<MonoBehaviour>(); //定义脚本组件 8 } 9 void Update () { //返回键监听 10 if(Input.GetKeyDown(KeyCode.Escape)){ 11 EscapeEvent(); //调用EscapeEvent方法 12 }} 13 public void ChangeScrip(int offID,int onID ) { //修改界面的方法 14 restData(); //重新设置界面中的相应数据 15 script[offID].enabled = false; //禁用当前界面脚本组件 16 script[onID].enabled = true; //启用需要进入界面的脚本组件 17 currentID = onID; //设置当前界面ID 18 } 19 void EscapeEvent(){ //返回键调用的方法 20 switch (currentID) { //按下返回键时检测跳转到哪个界面 21 case 1: if ((GetComponent("MainLayer") as MainLayer).moveFlag) { 22 break; }Application.Quit(); break; 23 case 2: 24 case 3: 25 case 4: 26 case 5: 27 ChangeScrip(currentID,ConstOfMenu.MainID); break; //跳转到主菜单界面 28 case 6: 29 ChangeScrip(currentID,ConstOfMenu.ChoiceID); break;//跳转到游戏种类选择界面 30 case 7: 31 ChangeScrip(currentID,ConstOfMenu.ModeChoiceID); break;//跳转到游戏模式选择界面 32 }} 33 private void restData(){ //对各个脚本组件的重新设置数据的方法 34 (GetComponent("MainLayer") as MainLayer).restData(); 35 (GetComponent("ChoiceLayer") as ChoiceLayer).restData(); 36 (GetComponent("ModeChoiceLayer") as ModeChoiceLayer).restData(); 37 HelpLayer helpLayer = GetComponent("HelpLayer") as HelpLayer; 38 helpLayer.restData(); 39 } }
第4行~第12行声明当前界面ID,初始化界面时定义脚本组件,当用户按下返回键时,调用界面跳转控制方法EscapeEvent,判断如何跳转界面。
第13行~第18行为修改界面的方法,首先需要重新设置当前界面数据,例如主菜单界面4个按钮的初始化位置。然后禁用本界面的脚本组件并启用即将跳转到的界面的脚本组件,同时将界面ID索引更改为即将跳转到的界面的ID。
第19行~第32行为返回键调用的方法,由于游戏开发的脚本组件是按顺序加载的,所以可按顺序直接跳转到其他的界面。在这里,本游戏采用了为各个界面编码的方式,方便界面跳转管理。
第33行~第39行为对各个脚本组件的重新设置数据的方法。其中包括三个界面的重设数据方法,分别为主菜单界面、游戏种类选择界面和游戏模式选择界面。
(7)前面介绍了控制界面跳转脚本代码,接下来介绍声音控制脚本,该脚本主要负责游戏背景音乐和游戏音效的开关控制,并将其挂载到游戏对象“Main Camera”上,详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的MusicLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class MusicLayer : MonoBehaviour{ 4 public Texture backgroundOfMusicLayer; //菜单界面背景图片 5 public Texture2D[] musicBtns; //声明音乐按钮数组 6 public Texture2D[] musicTex; //声音按钮对应的图片 7 public Texture2D[] effectBtns; //声明音效按钮数组 8 public Texture2D[] effectTex; //音效按钮对应的图片 9 private int effectIndex; //音效索引 10 private int musicIndex; //音乐索引 11 public GUIStyle btStyle; //按钮样式 12 private Matrix4x4 guiMatrix; //GUI自适应矩阵 13 void Start(){ 14 effectIndex = PlayerPrefs.GetInt("offEffect"); //初始化音效索引 15 musicIndex = PlayerPrefs.GetInt("offMusic"); //初始化音乐索引 16 guiMatrix = ConstOfMenu.getMatrix(); //初始化GUI自适应矩阵 17 } 18 void OnGUI(){ 19 GUI.matrix = guiMatrix; //设置GUI矩阵 20 GUI.DrawTexture(new Rect(0, 0, ConstOfMenu.desiginWidth, //绘制背景图片 21 ConstOfMenu.desiginHeight), backgroundOfMusicLayer); 22 GUI.DrawTexture(new Rect(200, 180, 273, 80), musicTex[musicIndex % 2]); 23 if (GUI.Button(new Rect(473, 190, 110, 80), musicBtns[musicIndex % 2], btStyle)){ 24 musicIndex++; //按钮索引加一 25 PlayerPrefs.SetInt("offMusic", musicIndex % 2); //将新的按钮索引存入prefer中 26 } 27 GUI.DrawTexture(new Rect(200, 320, 273, 80), effectTex[effectIndex % 2]); //绘制显示图片 28 if (GUI.Button(new Rect(473, 330, 110, 80), effectBtns[effectIndex % 2], btStyle)){ 29 effectIndex++; //按钮索引加一 30 PlayerPrefs.SetInt("offEffect", effectIndex % 2); /将新的按钮索引存入prefer中 31 }}}
第4行~第12行声明了声音控制界面背景图片、音乐按钮数组和其文字图片、音效按钮数组和其文字图片,背景音乐和游戏音效索引以及两个按钮样式。
第13行~第17行初始化背景音乐和游戏音效索引,初始化GUI自适应矩阵,为了该声音控制界面同样自适应各种客户端。
第18行~第31行为绘制背景音乐和游戏音效的按钮开关图,以及“音乐关”、“音乐开”、“音效关”和“音效开”的文字图片。同时,根据玩家按下按钮的次数,来调控每次按钮图片和文字的切换。同时,存储两个按钮状态,方便游戏后续开发使用。
(8)挂载声音控制脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值,可参考如图2-32所示的声音控制界面变量赋值。
▲图2-32 声音控制界面变量赋值
(9)前面介绍了声音设置脚本所有方法,接下来介绍关于界面脚本。该脚本主要介绍了游戏的名称、版本号,以及版权所有者“百纳科技”,并将其挂载到游戏对象“Main Camera”上。详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的AboutLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class AboutLayer : MonoBehaviour { 4 public Texture backgroundOfAboutLayer; //界面背景图片 5 public Texture aboutOfAboutLayer; //关于界面背景图片 6 private Matrix4x4 guiMatrix; //GUI自适应矩阵 7 void Start () { 8 guiMatrix = ConstOfMenu.getMatrix(); //获取GUI自适应矩阵 9 } 10 void OnGUI(){ 11 GUI.matrix = guiMatrix; //设置GUI矩阵 12 GUI.DrawTexture(new Rect(0, 0, ConstOfMenu.desiginWidth, //绘制界面背景 13 ConstOfMenu.desiginHeight), backgroundOfAboutLayer); 14 GUI.DrawTexture(new Rect(148, 150, 504, 299), aboutOfAboutLayer); //绘制关于图片 15 }}
第4行~第9行声明了关于界面大背景图以及关于界面小背景图,并声明GUI自适应矩阵,通过获取自适应矩阵,来调整关于界面以便适应各种客户端,达到美观效果。
第10行~第15行设置GUI矩阵的同时,按照客户端设备的宽高比,在准确位置绘制关于界面主背景,并绘制关于图片。
(10)挂载关于界面脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值可参考图2-33所示的“关于界面变量赋值”。
▲图2-33 关于界面变量赋值
(11)前面介绍了关于界面脚本所有方法,接下来介绍帮助界面脚本。该脚本主要介绍了游戏的玩法,通过手指上下抹动屏幕,可实现翻页功能。帮助界面共八条规则,将其挂载到游戏对象“Main Camera”上,详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的HelpLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class HelpLayer : MonoBehaviour { 4 public Texture2D[] helpTexture; //帮助界面的图片 5 private float positionY; //第一张图片的位置 6 private float officerY; //图片直接Y方向的偏移量 7 private Matrix4x4 guiMatrix; //GUI自适应矩阵 8 private int currentIndex; //当前显示图片的索引 9 private Vector2 touchPoint ; //触控点坐标 10 private float currentDistance; //当前移动距离 11 private float scale; //自适应的滑动距离缩放系数 12 private bool isMoving; //图片是否移动 13 private float moveStep; //图片移动的步径 14 private int stepHao; //移动距离的正负行 15 private Vector2 prePositon; //上一次触控点的位置 16 void Start () { 17 touchPoint = Vector2.zero; //初始化2维向量 18 prePositon = Vector2.zero; 19 currentIndex = 0; //当前图片索引 20 positionY = 0.0f; //移动的Y距离 21 moveStep = 300; //移动步径 22 currentDistance = 0; //当前移动距离 23 isMoving = false; //是否移动的标志位 24 officerY = ConstOfMenu.desiginHeight; //屏幕高度 25 guiMatrix = ConstOfMenu.getMatrix(); //获取GUI自适应矩阵 26 scale = Screen.height / 480.0f; //滑动自适应系数 27 } 28 void OnGUI(){ 29 GUI.matrix = guiMatrix; //设置GUI自适应矩阵 30 for (int i = 0; i < helpTexture.Length; i++){ //循环数组 31 if (Mathf.Abs(currentIndex - i) < 2){ //每次绘制当前显示图片与上下两张 32 GUI.DrawTexture(new Rect(0, positionY + officerY * i, ConstOfMenu. desiginWidth, ConstOfMenu.desiginHeight), helpTexture[i]); 33 34 }} 35 if(isMoving){ //如果允许图片移动,则移动 36 textureMove(); //调用textureMove方法 37 }} 38 void indexChange(int step){ 39 int newIndex = currentIndex+step; //计算当前编号 40 if (newIndex>7||newIndex<0) { //如果编号超出边界 41 return; 42 } 43 currentIndex = newIndex; //修改当前索引值currentIndex确保其在0~6之间 44 isMoving = true; //设置为可移动 45 } 46 public void restData(){ 47 currentIndex = 0; //重新设置当前所有 48 positionY = 0.0f; //重新设置Y的位置 49 moveStep = 300; //设置移动步径 50 currentDistance = 0; //设置移动距离 51 isMoving = false; //设置移动的标志位 52 } 53 …//此处省略了Update方法,将在下面进行介绍 54 …//此处省略了textureMove方法,将在下面进行介绍 55 }
第4行~第15行声明帮助界面所需要的变量,包括帮助界面的背景图,以及帮助界面八条规则的第一条的图片的坐标,帮助图片的移动标志位和移动步径。还有最重要的,用户触控点的坐标,这关系到该游戏帮助界面实现上下翻页的功能。
第16行~第27行为Start方法,初始化帮助界面翻页功能所用到的二维向量,同时声明当前界面的索引、移动的步径,以及移动的距离,界面移动标志位置为false。
第38行~第45行为indexChange方法,由于帮助界面有八页,计算当前页面步径索引的同时,要检测该值是否超出范围。同时,界面移动标志位置为true。
第46行~第52行为重置数据方法,由于每次初始化帮助界面,规则一的页面显示在首页。定义了翻页时候的移动步径。同时默认的帮助界面移动的标志位置为false。只有当用户抹动界面的时候,界面才会翻页。
(12)前面介绍了帮助界面脚本的部分方法,接下来介绍上述代码省略的“Update”方法和“textureMove”方法。这两个方法至关重要,直接关系到帮助界面翻页功能的实现,脚本代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的HelpLayer.cs。
1 void Update(){ 2 if(!isMoving && Input.touchCount>0) { //判断是否允许触控 3 Touch touch = Input.GetTouch(0); //获取一个触控点 4 if (touch.phase == TouchPhase.Began) { //按钮按下时的回调方法 5 touchPoint = touch.position; //记录down点 6 prePositon = touch.position; //记录down点 7 }else if (touch.phase == TouchPhase.Moved){ //positionY的范围-480*7-0 8 float newPositonY= positionY - touch.position.y + prePositon.y; //等号后面为move的距离 9 positionY=(newPositonY>0)?0:(newPositonY>(-480*7)?newPositonY:(-480*7)); 10 prePositon = touch.position; //记录上一次的触控点 11 }else if (touch.phase == TouchPhase.Ended){ //用户触控结束 12 isMoving = true; //图片开始自动移动 13 currentDistance = (touch.position.y - touchPoint.y) / scale; //计算从触控开始到抬起的距离 14 stepHao = (Mathf.Abs(currentDistance) > 150.0f) ? (currentDistance > 0 ? 1 : (-1)) : 0; //执行移动方法 15 moveStep = (Mathf.Abs(currentDistance) > 150.0f) ? (currentDistance > 0 ? //计算当前移动步径 16 -Mathf.Abs(moveStep) : Mathf.Abs(moveStep)) : (currentDistance > 0 ? 17 Mathf.Abs(moveStep) : -Mathf.Abs(moveStep)); 18 indexChange(stepHao); //调用indexChange方法修改移动索引值 19 } } } 20 void textureMove(){ 21 float positionYOfNew = positionY + moveStep * Time.deltaTime; //计算新位置 22 float minDistance = -480*Mathf.Abs(currentIndex); //计算positonY的最大值 23 if (stepHao==1) { //判断移动方向 24 positionY = Mathf.Max(positionYOfNew, minDistance);//计算positionY的值 25 }else if (stepHao == -1){ 26 positionY = Mathf.Min(positionYOfNew, minDistance); //计算positionY的值 27 } else{ 28 if (moveStep > 0){ 29 positionY = Mathf.Min(positionYOfNew, minDistance); //计算positionY的值 30 }else{ 31 positionY = Mathf.Max(positionYOfNew, minDistance); //计算positionY的值 32 }} 33 isMoving = !(positionY == minDistance); //计算是否可移动的标志位 34 }
第2行~第6行为判断帮助界面是否允许触控,由于帮助图片在移动过程中不允许触控移动,所以当移动标志位为false时,获取用户设备的触控点。
第7行~第10行为当用户抹动屏幕的过程中,记录用户抹动的距离。距离大小直接关系到帮助界面翻过的页数,如果移动距离过小,帮助界面将不执行翻页功能。
第11行~第19行为当用户抹动屏幕结束时,记录结束触控点,并将帮助界面移动标志位置为true,计算从触控开始到抬起的距离,判断距离是否达到翻页步径后执行翻页功能。
第20行~第34行为帮助界面翻页方法。根据用户抹动的方向以及距离,来判断是向上翻页还是向下翻页。
(13)挂载帮助界面脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值,可参考如图2-34所示的帮助界面变量赋值。
▲图2-34 帮助界面变量赋值
(14)前面介绍了帮助界面脚本所有方法,接下来介绍游戏种类选择界面脚本。该脚本主要负责绘制游戏种类选择界面的两个按钮,供用户选择八球模式或九球模式。同时,该游戏切换至相应的游戏界面,并将其挂载到游戏对象“Main Camera”上,详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的ChoiceLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class ChoiceLayer : MonoBehaviour { 4 public Texture backgroundOfChoiceMenu; //菜单界面背景图片 5 public GUIStyle[] buttonStyleOfChoice; //菜单界面按钮图样式 6 private bool scaleFlag; //进行缩放的标志位 7 private float scaleFactor; //缩放因子 8 private float buttonSize; //按钮大小 9 private float buttonStartX; //按钮X方向位置 10 private float buttonStartY; //按钮Y方向位置 11 private Matrix4x4 guiMatrix; //GUI自适应矩阵 12 void Start () { 13 scaleFlag = true; //初始化缩放的标志位 14 scaleFactor = 0.0f; //设置缩放因子 15 buttonSize = 120; //按钮大小 16 buttonStartX = 200; //按钮X方向位置 17 buttonStartY = 220; //按钮Y方向的位置 18 guiMatrix = ConstOfMenu.getMatrix(); //获取GUI自适应矩阵 19 }void OnGUI(){ 20 GUI.matrix = guiMatrix; //设置GUI自适应矩阵 21 GUI.DrawTexture(new Rect(0, 0, ConstOfMenu.desiginWidth, //绘制背景图片 22 ConstOfMenu.desiginHeight), backgroundOfChoiceMenu); 23 ButtonScale(); //按钮的执行缩放动作 24 if (GUI.Button(new Rect(buttonStartX, buttonStartY, buttonSize * scaleFactor, 25 buttonSize * scaleFactor), "", buttonStyleOfChoice[ConstOfMenu.EIGHT_ BUTTON])){ 26 if (!scaleFlag){ 27 PlayerPrefs.SetInt("billiard", 8); //8球模式标志存入 28 (GetComponent("Constroler") as Constroler).ChangeScrip( //界面切换 29 ConstOfMenu.ChoiceID, ConstOfMenu.ModeChoiceID); 30 }}if(GUI.Button(new Rect(buttonStartX+240.0f,buttonStartY,buttonSize*scaleFactor, 31 buttonSize * scaleFactor), "", buttonStyleOfChoice[ConstOfMenu.NINE_ BUTTON])){ 32 if (!scaleFlag){ 33 PlayerPrefs.SetInt("billiard", 9); //9球模式标志存入 34 (GetComponent("Constroler") as Constroler).ChangeScrip(//界面切换 35 ConstOfMenu.ChoiceID, ConstOfMenu.ModeChoiceID); }}} 36 void ButtonScale(){ //按钮执行缩放动作37 scaleFactor = Mathf.Min(1.0f, scaleFactor + Time.deltaTime); //计算缩放比38 scaleFlag = (scaleFactor != 1f); } //计算缩放标志位39 public void restData(){ //重置缩放比 40 scaleFlag = true; //设置缩放标志位 41 scaleFactor = 0.0f; //计算缩放因子 42 }}
第4行~第11行声明了菜单界面背景图片,菜单界面按钮图样式,两个游戏种类按钮进行缩放的标志位以及按钮X、Y方向位置。
第12行~第18行为Start方法,初始化缩放标志位的同时设置按钮缩放因子,初始化两个按钮的大小,以及它们的位置坐标。同时获取GUI自适应矩阵,通过矩阵计算,使得该界面适用于各种终端设备。
第19行~第35行设置GUI自适应矩阵,绘制该界面的背景图片和两个按钮图片。同时,执行两个按钮的缩放动作。当用户单击这两个按钮的时候,分别执行相应的操作,包括数据的存储以及界面的切换。
第36行~第41行为按钮执行缩放动作和重置数据的两个方法。由于两个按钮都有缩放动态效果,所以需要进行计算按钮的缩放比。初始化该界面的时候,需要重新进行缩放。
(15)挂载游戏种类选择界面脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值,可参考如图2-35的“游戏种类选择界面变量赋值”。
▲图2-35 游戏种类选择界面变量赋值
(16)前面介绍了游戏种类选择界面脚本所有方法,接下来介绍游戏模式选择界面脚本,该脚本主要负责绘制三个按钮以及两种游戏模式界面加载,并将其挂载到游戏对象“Main Camera”上,详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的ModeChoiceLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class ModeChoiceLayer : MonoBehaviour { 4 public Texture backgroundOfModeChoicerMenu; //菜单界面背景图片 5 public GUIStyle[] buttonStyleOfModeChoice; //菜单界面按钮图样式 6 private float[] ButtonPositionOfX = new float[3]; //首先需要创建数组 7 private float buttonOfCurrentMovingDistance; //按钮移动的距离 8 private float buttonOfMaxDistance; //按钮移动的最大距离 9 private float startYOfModeChoice; //第一个按钮的起始Y坐标 10 private float buttonOfficerOfHeight; //按钮直接的高度差 11 private bool moveFlag; //按钮移动的标志位 12 private Matrix4x4 guiMatrix; //定义GUI自适应矩阵 13 void Start () { 14 moveFlag = true; //移动的标志位 15 restData(); //获取菜单界面3个按钮的X方向位置 16 buttonOfCurrentMovingDistance = 0; //按钮当前移动的距离 17 buttonOfMaxDistance = 144f; //按钮移动的最大距离 18 startYOfModeChoice = 180f; //按钮起始高度 19 buttonOfficerOfHeight = 90f; //按钮间距 20 guiMatrix = ConstOfMenu.getMatrix(); //GUI自适应矩阵 21 } 22 void ButtonMove(){ 23 float length = ConstOfMenu.movingSpeedOFMode * Time.deltaTime; //计算移动距离 24 buttonOfCurrentMovingDistance += length; //按钮移动 25 for (int i = 0; i < ButtonPositionOfX.Length; i++){ 26 ButtonPositionOfX[i] += (ConstOfMenu.ButtonMovingStep[i] * length); 27 } 28 moveFlag = buttonOfCurrentMovingDistance < buttonOfMaxDistance; //计算是否移动到最大距离 29 } 30 public void restData(){ //重置数据方法 31 for (int i = 0; i < ConstOfMenu.BPositionXOfMode.Length; i++){ 32 ButtonPositionOfX[i] = ConstOfMenu.BPositionXOfMode[i]; //设置位置 33 } 34 buttonOfCurrentMovingDistance = 0; //重置当前移动距离为0 35 moveFlag = true; //移动标志位置为true 36 } 37 ……//此处省略了OnGUI方法,将在下面进行介绍 38 }
第4行~第12行声明了菜单界面背景图片、菜单界面按钮图样式、创建三个按钮的数组、按钮移动的距离、按钮直接的高度差和按钮移动的标志位。
第13行~第21行为Start方法,按钮移动标志位置为true,通过调用重置数据方法获取菜单界面三个按钮的X方向位置。同时,定义了按钮移动的距离,以及按钮之间高度差。
第22行~第29行为按钮移动方法,由于初始化界面的按钮移动是匀速的,所以可以通过时间和固定速度计算出按钮移动的距离,直到移动到按钮可以移动的最大距离。
第30行~第35行为重置数据方法,设置按钮的最初位置,重置当前移动距离为0,并且移动标志位重新置为true。
(17)前面介绍了游戏种类选择界面脚本部分方法,接下来介绍上述代码省略的OnGUI方法代码,脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的ModeChoiceLayer.cs。
1 void OnGUI(){ 2 GUI.matrix = guiMatrix; //设置GUI的自适应矩阵 3 GUI.DrawTexture(new Rect(0, 0, ConstOfMenu.desiginWidth, //绘制背景图片 4 ConstOfMenu.desiginHeight), backgroundOfModeChoicerMenu); 5 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.COUNTDOW_BUTTON], 6 startYOfModeChoice, 256, 64), "", 7 buttonStyleOfModeChoice[ConstOfMenu.COUNTDOW_BUTTON])){ 8 if (!moveFlag){ 9 PlayerPrefs.SetInt("isTime", 1); //倒计时模式 10 GameLayer.resetAllStaticData(); //设置游戏界面的静态变量数据 11 Application.LoadLevel("GameScene");//加载LevelSelectScene场景 12 } } 13 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.PRACTICE_BUTTON], 14 startYOfModeChoice + buttonOfficerOfHeight * 1, 256, 64), "", 15 buttonStyleOfModeChoice[ConstOfMenu.PRACTICE_BUTTON])){ 16 if (!moveFlag){ 17 PlayerPrefs.SetInt("isTime", 0); //练习模式 18 GameLayer.resetAllStaticData(); //设置游戏界面的静态变量数据 19 Application.LoadLevel("GameScene");//加载LevelSelectScene场景 20 } } 21 if (GUI.Button(new Rect(ButtonPositionOfX[ConstOfMenu.RANK_BUTTON], 22 startYOfModeChoice + buttonOfficerOfHeight * 2, 256, 64), 23 "", buttonStyleOfModeChoice[ConstOfMenu.RANK_BUTTON])){ 24 if (!moveFlag){ 25 (GetComponent("Constroler") as Constroler).ChangeScrip( //切换到历史记录界面 26 ConstOfMenu.ModeChoiceID, ConstOfMenu.RankID); 27 }} 28 if (moveFlag){ //如果按钮移动标志位为true 29 ButtonMove(); //则调用按钮移动方法 30 }}
第5行~第20行绘制倒计时模式按钮和练习模式按钮,当用户单击任一按钮的时候,将该模式索引存储起来,设置游戏界面的静态变量数据。最后加载该模式的游戏界面。
第21行~第29行绘制了排行榜模式按钮,当用户单击该按钮的时候,切换到排行榜记录界面。同时,如果按钮移动标志位为true,则调用按钮移动方法。
(18)挂载游戏模式选择界面脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值,可参考如图2-36所示的“游戏模式选择界面变量赋值”。
▲图2-36 游戏模式选择界面变量赋值
(19)前面介绍了游戏模式选择界面脚本所有方法,接下来介绍排行榜界面脚本,该脚本主要负责记录玩家的游戏记录,并将其挂载到游戏对象“Main Camera”上,详细挂载步骤和变量赋值前面已经介绍过,这里不再赘述。脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的RankLayer.cs。
1 using UnityEngine; 2 using System.Collections; 3 public class RankLayer : MonoBehaviour { 4 public float groupX = 177, groupY = 0, groupW = 300, groupH = 240; //显示数字图片的宽和高 5 private int maxHeight; //移动的最大距离 6 private int numSize = 19; //数字图片的大小 7 public Texture2D bg; //背景图片 8 public Texture2D box; //中间显示的背景图片 9 public Texture2D date; //时间按钮图片 10 public Texture2D score; //分数按钮图片 11 public Texture2D[] textures; //数字图片数组 12 public GUIStyle style; //GUIStyle 13 private string txt = ""; //初始字符串 14 private float oldPosY; //位置比变量 15 private float currPosY; 16 private string[] showRecords; //分数数组 17 private Matrix4x4 guiMatrix; //GUI自适应矩阵 18 void Start(){ 19 guiMatrix = ConstOfMenu.getMatrix(); //获取GUI自适应矩阵 20 showRecords = Result.LoadData(); //通过调用LoadData方法初始化数组 21 maxHeight = numSize * showRecords.Length -192; //计算最大高度 22 } 23 void Update(){ 24 if (Input.GetMouseButtonDown(0)) { //计算每条记录移动 25 oldPosY = Input.mousePosition.y; 26 } 27 if (Input.GetMouseButton(0)){ 28 currPosY = Input.mousePosition.y; 29 groupY = Mathf.Clamp((groupY - currPosY + oldPosY), -maxHeight, 0); 30 oldPosY = currPosY; 31 }} 32 void OnGUI(){ 33 GUI.matrix = guiMatrix; //设置GUI自适应矩阵 34 GUI.DrawTexture(new Rect(0, 0, 800, 480), bg); //绘制背景图片 35 GUI.DrawTexture(new Rect(150, 150, 530, 294), box); //绘制中心小图 36 if (GUI.Button(new Rect(230, 180, 130, 40), date, style)){ 37 string[] records = Result.LoadData();//通过调用LoadData方法初始化数组 38 showRecords = records; 39 } 40 if (GUI.Button(new Rect(470, 180, 130, 40), score, style)){ 41 string[] records = Result.LoadData(); //通过调用LoadData方法初始化数组 42 RecordsSort(ref records); 43 showRecords = records; 44 } 45 GUI.BeginGroup(new Rect(177, 220, 476, 192)); //绘制图片 46 GUI.BeginGroup(new Rect(0, groupY, 476, numSize * showRecords.Length)); 47 if (showRecords[0] != ""){ 48 DrawRecrods(showRecords); //需要绘制的时候绘制记录 49 } 50 GUI.EndGroup(); 51 GUI.EndGroup(); 52 }}
第4行~第17行定义了显示数字图片的宽和高,声明了数字图片的大小和排行榜界面背景图,声明了时间、分数和数字的图片,声明按钮样式以及位置变量。
第18行~第22行为Start方法,获取GUI自适应矩阵,以便该排行榜界面能够适应各种手机终端,通过调用LoadData方法初始化数组,同时计算各条记录的最大高度。
第23行~第31行为Update方法,每当有新的游戏记录产生,就要在排行榜界面的固定位置进行绘制。绘制所需要计算上一条记录的位置,同时确定本条记录移动的距离。
第32行~第52行绘制了排行榜的大背景图和中心小背景图,时间和得分记录都按照固定位置进行绘制,如果游戏记录不为空,则进行绘制。
(20)前面介绍了排行榜界面脚本部分方法,接下来介绍上述代码省略的DrawRecords方法、RecordsSort方法和StringToNumber方法代码,脚本详细代码如下。
代码位置:见随书光盘中源代码/第02章/Table3D/Assets/Scripts/MenuScript目录下的RankLayer.cs。
1 public void DrawRecrods(string[] records){ //绘制记录方法 2 for (int i = 0; i < records.Length; i++){ 3 string date = records[i].Split(',')[0]; //按照逗号拆分日期记录 4 string score = records[i].Split(',')[1]; //按照逗号拆分分数记录 5 int[] dateNum = StringToNumber(date); //string型转化成整型数据 6 int[] scoreNum = StringToNumber(score); //string型转化成整型数据 7 for (int j = 0; j < dateNum.Length; j++){//根据日期选择对应的数字图进行绘制 8 GUI.DrawTexture(new Rect((j + 1) * numSize, i * numSize, 9 numSize, numSize), textures[dateNum[j]]); 10 } 11 for (int j = 0; j < scoreNum.Length; j++){//根据日期选择对应的数字图进行绘制 12 GUI.DrawTexture(new Rect((j + 17) * numSize, i * numSize, 13 numSize, numSize), textures[scoreNum[j]]); 14 }}} 15 public void RecordsSort(ref string[] records){ //记录排序方法 16 for (int i = 0; i < records.Length -1; i++){ 17 for (int j = i + 1; j < records.Length; j++){ 18 if (int.Parse(records[i].Split(',')[1]) < int.Parse(records[j].Split (',')[1])){ 19 string tempRecord = records[i]; //赋值 20 records[i] = records[j]; //赋值 21 records[j] = tempRecord; //赋值,实现位置的交换 22 }}}} 23 public static int[] StringToNumber(string str){ //数据类型转换方法 24 int[] result = new int[str.Length]; //将游戏记录的结果转换成整型数组 25 for (int i = 0; i < str.Length; i++){ 26 char c = str[i]; //拆分整条记录 27 if (c == '-'){ 28 result[i] = 10; 29 }else{ 30 result[i] = str[i] - '0'; 31 }} 32 return result; //返回结果 33 }
第2行~第14行按照逗号拆分日期记录和分数记录,并根据这两条记录里面的数字,选择对应的图片索引,进行排行榜时间和得分绘制。
第15行~第22行为记录排序方法,由于排行榜的记录是有高低之分的,所以需要对其进行排序处理。对比每次得分情况,进行排序。
第23行~第32行数据类型转换方法,将游戏记录的结果转换成整型数组,方便游戏开发的其他操作。
(21)挂载排行榜界面脚本和变量赋值。关于脚本的挂载在前面已经介绍过,这里不再赘述。关于脚本的变量赋值,可参考如图2-37的“排行榜界面变量赋值”。
▲图2-37 排行榜界面变量赋值
(22)至此,本游戏主菜单界面开发所需要的各个脚本的编写挂载、变量赋值以及功能的详细介绍都已结束。所有脚本挂载效果如图2-38所示。
▲图2-38 所有脚本挂载效果