别踩白块(u3d)
刚开始接触unity 3d,现在要从头学起,模仿《别踩白块》做一个游戏。下面开始正文了。
在做之前,先想好需要哪些界面。需要一个开始界面和一个游戏界面。由于刚开始,先做的是游戏界面。截图如下:
用了一个面板做天空北京,一个球体做地面,摄像机角度调整好,有那么一点3D的感觉。将整个游戏场景放在一个空对象GameUI中,方面后面的编程。
固定场景搞定,下面开始动态的游戏物体--黑白块了。游戏素材有黑块和白块两种,但是在搭建场景的过程中,发现黑块的坐标有问题,没办法,将黑块托给一个空游戏物体,调整好坐标。下面,根据开始的分析,需要六行四列黑白块同时出现在屏幕上。(这一点,需要根据自己搭建的场景来判断,具体的数量,自己把握)。现在,在场景视图中调整块的位置,找一下规律:每行的块的坐标有什么规律,每列的块的坐标有什么规律(因人而异)。注意,由于要做的是3D的游戏,所以每行块都有一定的角度偏移,这个也要考虑。如下如所示:
这一点,主要是为了动态根据预制体生成黑白块确定坐标。好了,我本人的绑定黑白块的代码如下:
1 using UnityEngine; 2 using System.Collections; 3 4 public class Block : MonoBehaviour { 5 6 //判断块是否可以踩 7 public bool cantTouch = false ; 8 // Use this for initialization 9 //x,y,z偏移量 10 //初始化,基准坐标 11 private float px = -0.5f; 12 private float py = 0.15f; 13 private float pz = -6.3f; 14 private float rx = -54.5f; 15 16 private GameController gameController; 17 18 //行列索引 19 public int columnIndex; 20 public int rowIndex; 21 22 void Start () { 23 gameController = GameObject .FindObjectOfType<GameController> (); 24 } 25 //按键,开始游戏 26 // Update is called once per frame 27 void OnMouseDown () { 28 // print ("Block OnMouseDown"); 29 gameController.Select(this); 30 31 } 32 //设置方块位置 33 public void SetPosition(int columnIndex,int rowIndex){ 34 this .rowIndex =rowIndex ; 35 this .columnIndex = columnIndex ; 36 gameObject .transform .position = 37 new Vector3 (px +columnIndex *0.25f,py +rowIndex *0.275f, pz + rowIndex*0.2f); 38 // new Vector3 (px +columnIndex *0.25f,py +rowIndex *0.3f, pz + rowIndex*0.2f); 39 gameObject .transform .eulerAngles = new Vector3 (rx + rowIndex*4.5f,0,0); 40 //new Vector3 (rx + rowIndex*5f,0,0); 41 } 42 //色块往下移动一行 43 public void MoveDown(){ 44 SetPosition (columnIndex ,rowIndex -1); 45 } 46 }
首先,确定左下角块的初始位置。使用行列索引来确定每一个块。在SetPosition()函数中,确定每个块的坐标。之后,将黑白块分别做成prefab,将上面的脚本分别绑定给它们。
游戏界面做好了,现在开始做开始界面。使用NGUI来做开始界面。最后的效果图如下:
主要的按钮有四个,最上面的是开始按钮,下面的从左到右分别是more(连接到互联网)、声音开关和排行按钮,这四个使用的是Button。隐藏有得分条、时间条、gameover和排名,这四个是显示作用,使用的是Label。
顺便说一下NGUI的使用。
首先要导入NGUI,这个自己从网上找吧,很多的。导入之后,project视图中会出现NGUI。之后,将需要使用的图片放在一个文件夹,在放在NGUI下面的Resources文件夹下。在resources文件夹下用鼠标全选需要使用的照片,然后点击菜单栏NGUI->open->Atlas Maker,如图,点击create。
使用的时候,NGUI->create->sprite,这样,所有的sprite都会在camera目录下,如图:
创建好sprite之后,选中,在右边的inspector中UISprite选项里面,点击Atlas,选择先前创建的Atlas,然后,点击Sprite,选择需要的图片。这样,就可以在场景视图中调节了。另外,如果要做的是按钮,需要给它添加一个碰撞体,在inspector视图中的最下面Add componet ,physics。注意,添加碰撞体后,一定要调节碰撞体的大小,确保可以完全覆盖sprite。还要在project视图中搜索UIbuttonmessage脚本,然后绑定给需要的sprite,如图:
注意图中的标记,在UIButton Message中,将按钮要执行的动作的脚本的绑定物体拖给target,将要执行的动作的函数拖给function name。
上面介绍的是做按钮。如果要做显示条的话,先拖一个sprite到camera下,调整大小,再在NGUI->create->Label创建一个label,覆盖sprite。之后,可以像操作label一样操作了。
回归正题。我在hierarchy视图中创建了一个空游戏对象GameController来控制所有的游戏逻辑,所有的游戏逻辑都在脚本GameController中。所有的代码如下:
1 using UnityEngine; 2 using System.Collections; 3 4 public class GameController : MonoBehaviour { 5 6 //得分 7 public static int score = 0; 8 //public int i=0; 9 10 //是否播放音乐 11 public bool baudio = true ; 12 13 //是否计时 14 // public bool CountTime = false ; 15 16 //时间 17 public float jishi= 0.0f; 18 19 //第几次按下 20 //public bool presscount = false ; 21 // public static bool ShowScore = false ; 22 //Time GameTime = Time.time ; 23 24 //开始界面 25 public GameObject StartUI; 26 //游戏界面 27 public GameObject GameUI; 28 //分数条 29 public GameObject Score; 30 public UILabel ScoreLabel; 31 //游戏结束 32 public GameObject GameOver; 33 //容器,盛放生成的块 34 public GameObject container; 35 //排名 36 public GameObject Paiming; 37 public UILabel PaimingLabel; 38 //时间条 39 public GameObject shitiao; 40 public UISprite shijiantiao; 41 //游戏音乐控制 42 public GameObject Shuta; 43 public GameObject Playa; 44 45 //白块和黑块 46 public GameObject whiteBlock; 47 public GameObject blackBlock; 48 49 //动态数组,存放块 50 private ArrayList blocks; 51 52 // 进入游戏界面 53 public void EnterGameUI () { 54 //初始化jishi 55 jishi = 0.0f; 56 // print("more"); 57 //关闭开始界面,打开游戏界面 58 StartUI.SetActive(false); 59 GameUI.SetActive(true); 60 //开始游戏 61 StartGame (); 62 } 63 //开始游戏 64 private void StartGame(){ 65 // Adunion4Unity.Instance.showInterstitialAd(Adunion4Unity.IAD_TYPE_GAMESTART); 66 // CountTime = true ; 67 //显示时间条,分数,GameOver关闭 68 shitiao .SetActive (true); 69 GameOver .SetActive (false ); 70 Score .SetActive (true); 71 //初始化时间条长度 72 shijiantiao.fillAmount = 1f; 73 //初始化六行块 74 blocks = new ArrayList(); 75 for (int rowIndex=0; rowIndex <6; rowIndex ++) { 76 AddBlock(rowIndex); 77 } 78 } 79 //在指定的行添加一行色块 80 void AddBlock(int rowIndex){ 81 82 //随机生成列数 83 int columnIndex = Random .Range (0,4); 84 85 for(int i=0;i!=4;++i){ 86 GameObject o; 87 if(i==columnIndex){ 88 o = Instantiate(blackBlock) as GameObject; 89 } 90 else { 91 o = Instantiate (whiteBlock) as GameObject; 92 } 93 o.transform .parent = container .transform ; 94 Block b = o.GetComponent<Block>(); 95 b.SetPosition(i,rowIndex); 96 blocks.Add(b); 97 } 98 } 99 //点击块,进行游戏 100 public void Select(Block block){ 101 //播放音乐 102 if(baudio){ 103 audio .Play(); 104 } 105 //判断踩的是不是最下面一行的块 106 if(block.rowIndex==0){ 107 //踩黑块 108 if(block.cantTouch){ 109 score +=1; 110 for(int i=0;i<blocks.Count;i++){ 111 Block b = (Block)blocks[i]; 112 b.MoveDown(); 113 114 if(b.rowIndex ==-1){ 115 blocks.RemoveAt(i); 116 Destroy (b.gameObject); 117 i--; 118 } 119 } 120 //在最上面添加一行 121 AddBlock(5); 122 } 123 else{ 124 // Adunion4Unity.Instance.showInterstitialAd(Adunion4Unity.IAD_TYPE_GAMEGIFT); 125 //读取游戏分数值 126 int i=PlayerPrefs.GetInt("score",0); 127 //print(score); 128 //如果分数比读取的大的话,将score写入 129 if(score>i){ 130 // print(score); 131 PlayerPrefs.SetInt("score",score); 132 } 133 //清理,返回开始界面 134 Clean (); 135 GameUI .SetActive (false); 136 StartUI.SetActive (true); 137 GameOver .SetActive (true ); 138 // Score.SetActive(false); 139 Score .SetActive (false ); 140 shitiao .SetActive (false); 141 ScoreLabel .text = "Score:"; 142 // goshow=true; 143 // print("failed"); 144 } 145 } 146 //显示分数 147 ShowScore(); 148 } 149 150 //清理游戏状态 151 void Clean(){ 152 for(int i=0;i<blocks.Count;i++){ 153 Block b = (Block)blocks[i]; 154 blocks.RemoveAt(i); 155 Destroy(b.gameObject); 156 i--; 157 } 158 score = 0; 159 } 160 //显示分数条 161 void ShowScore(){ 162 ScoreLabel.text="Score:"+score; 163 } 164 //播放音乐 165 void PlayAudio(){ 166 baudio = false ; 167 Shuta .SetActive (false); 168 Playa .SetActive (true ); 169 } 170 //关闭音乐 171 void shutAudio(){ 172 baudio = true ; 173 Shuta .SetActive (true); 174 Playa .SetActive (false); 175 } 176 //计时,时间条变化,超过20s,游戏结束,返回开始界面 177 void Update(){ 178 // jishi ++; 179 //计时 180 jishi += Time.deltaTime; 181 //时间条 182 shijiantiao.fillAmount -=0.05f*Time.deltaTime; 183 // if(CountTime){ 184 // if(Time.realtimeSinceStartup>=15){ 185 if(jishi>=20){ 186 int i=PlayerPrefs.GetInt("score",0); 187 if(score>i){ 188 PlayerPrefs.SetInt("score",score); 189 } 190 Clean (); 191 GameUI .SetActive (false); 192 StartUI.SetActive (true); 193 GameOver .SetActive (true ); 194 Score .SetActive (false ); 195 shitiao .SetActive (false); 196 ScoreLabel .text = "Score:"; 197 // CountTime = false ; 198 } 199 // } 200 //获取键值,如果按下返回键,退出游戏 201 if(Input.GetKeyDown(KeyCode.Escape)) 202 Application.Quit(); 203 } 204 205 //显示排名 206 void ShowPaiming(){ 207 int score; 208 score=PlayerPrefs.GetInt("score",0); 209 Paiming.SetActive(true); 210 PaimingLabel.text ="HIGH: "+score ; 211 // print(score); 212 } 213 //链接网页 214 void More(){ 215 Application.OpenURL("http://www.hao123.com"); 216 } 217 //排名 218 void PaimingBtn(){ 219 Paiming.SetActive(false); 220 } 221 }
最后,游戏工程和最后的apk文件都在下面:http://download.csdn.net/detail/longfeiah/8565119