参考:http://game.ceeger.com/forum/read.php?tid=1719

———————————————————开始————————————— 
好吧,吹了那么多我们开始吧,先发个最终截图

 
当然,你觉得3个格子太少,你还可以扩展成任意格子的,只要你有足够的创意.... 
 
游戏是自娱自乐的  圈圈先下一步,然后叉叉下一步,圈圈再下一步..... 
———————————先来制作UI部分————————————————— 
  
我的游戏基本上用ngui作为ui层,我会在第一节课详细的讲一下ngui的操作,灰常详细的... 
以后我的教程都会忽略这部分的详细过程... 
我的教程中绝对不会出现一句系统自带的GUI东西,我都会用NGUI来代替它 
  
让我们打开一个全新的unity项目,然后删除掉主相机,导入ngui... 
接着NGUi菜单- > Create a New UI ->然后会出现一个这样的面板,点Create your UI 
 
—————————————————新手可跳过这部分—————————— 
我建议你们新建一个命名为2dLayer的层,然后设置成它,至于为什么这样做,是为了养成一个良好的习惯,为了以后3d和2d的东西混杂一起时,物理碰撞光线渲染什么的都可以简单的通过这个层,Default这个层在我看来是很危险的   因为你不知何时何地某个东西和它发生了关系.... 
顺便日西下我其他项目的层... 
 
——————————————————请继续—————————— 
  
这时候场景还是空空如也  不过我们的看到场景中多了一个由UI Root (2D)构成的树结构的东西 
 
然后我们最好先确定我们最终要导出的程序屏幕大小是多少,比如我的屏幕设置成了800*600 
那么我们先选择UI Root (2D)->然后在右边的属性面板中这样 
UIRoot这个脚本的Auto删掉勾,然后Manual Height设置成600... 
(注意Transform的Scale是自动设置的   你不用动它) 
 
然后选择Panel,然后Ngui菜单->Create a widget -> 出现了一个新面板 
这时候先不要着急, 先放到一边,点回资源文件夹中NGUI  Examples自带的SciFi 的 资源  SciFi Atlas 
 像这样   直接拖动SciFi Atlas 到新面板的Atlas中, Font 也是如此,将SciFi Font - Header 拖到新面板的Font中 
 
这样子,Template选择Label 
 
成功出现一个New Label的字样在屏幕上.... 
=,=这个Label用来给我们的游戏提示输赢信息..... 
—————— 
然后我们再一次这样子创建一个button....方法和上面几乎一样,这时Altas和Font应该不用再拖动了 
Template选择button, 
background选择Dark, 
在屏幕上出现了一个button了,然后选择button,删除掉UIButton offset 这个脚本(我可不想选什么的时候都乱动一下) 
菜单-> component -> NGUI -> interaction -> button message 的脚本 
 
请将button message 脚本的target设置为 UI Root(2d) 
然后 Function Name 设置为 ButtonPress   
这里这样设置是为了下面我们的程序来调用的.... 
将boxCollider 的 x 和 y  分别设置成40,这个东西很重要  因为我们鼠标点击的时候就靠这个... 
好了 到此我希望你还能跟得上我的节奏.... 
选择button,然后将它下面的子物体Label删去... 添加两个新的Sprite... 
添加方法和上面的一样:菜单 -> NGUI - > create a widget ... 
Template 选择 sprite 然后 
其中一个sprite选择 X ,  然后将名字改成Chacha 
另一个sprite选择 Button , 然后将名字改成Quan 
 
Chacha的Depth改成1,Scale 改成(25,25,1) 
Quan的Depth改成2,Scale 改成(40,40,1) 
SlicedSprite (Dark)的Depth改成0,Scale 改成(50,50,1) 
  
其中一个Chacha的截图 
 
大功告成 
到此为止,我们的UI/交互层 算是全部做好了.... 
  
  
—————————————————新手可跳过这部分—————————— 
我们在游戏制做过程中一定要规划好游戏的逻辑层次关系,比如我推崇最起码的三层游戏结构 
UI/交互层 <--> 逻辑层 <--> 数据层    这样的关系  各层之间留有一定的接口可以相互访问,绝对不要将所有的东西放在一起,这样会混乱得难以管理的
游戏越大型  这样的层次就越重要.... 
不过这个圈圈叉叉游戏还是用不到数据层了... 
  
  
—————————————————下面我们开始逻辑层的接口部分—————————— 
终于要开始写代码了   基动啊..... 
创建一个名为QuanQuan的c#脚本,然后付在UI Root (2D)上,我们目前整个游戏都靠这个脚本来管理 
首先我们想到的肯定是把这个Label和Button 作为2d的接入口传到脚本中 
    public GameObject gamePanel;   //将Panel这个物体拖到这里 
    public GameObject ShowLable;   //将Label这个物体拖到这里 
    public GameObject _Qizi;            //将Button这个物体拖到这里 
简单吧...然后我们定义棋盘的大小,我们先规定这个棋盘必须是n*n的-,-就是长和宽一样啦 
    public int number_N = 3;  //棋盘大小 
    public int TwohengWidth = 50; //两个棋子的距离 
最后如图:public的接口算是写好了.... 
(注 那个HengWidth属性在这个游戏中大家可无视....,还有number_N 请设置成3) 
———————————然后我们讨论下核心的判断部分———————————————— 
这种明显的方块格子的游戏,很多时候我们一眼就应该想到用 int[][] 这样的2维数组来存储和判断信息.... 
我们这里设置空的方块为0   叉叉的用-1表示     圈圈用1表示 
每下一步的时候,判断横边,竖边,斜边 每一边相加的结果是不是3或者是-3  这样子就可以判断输赢了 
比如一开始的状态 

0 , 0 , 0 
0 , 0 , 0 
0 , 0 , 0 

某种赢了的状态 

 0 ,   0 ,  0 
 1,    1 ,  1 
  -1 , -1 ,  0 

————————————游戏的状态机制———————————————— 
我们下棋的时候总是这样:我下完一步,然后到你下一步,一直到最终结束 
    enum GameState 
    { 
        MyAction, 
        AiAction, 
        GameOver, 
    } 
GameState gameState = GameState.MyAction; 
—————————————start()应该放什么————————————— 
首先算出一个左下角的原点OriginPoint,以方便我们排列整个棋盘 
然后根据棋盘的大小创建3*3个棋子(复制于_Qizi) 
                mQizi[i, j] = Instantiate(_Qizi) as GameObject; 
                mQizi[i, j].name = "qizi_"+i+"_"+j; //命名很重要  因为我们在button获取信息时就是通过name的不同来区分不同物体的 
                mQizi[i, j].transform.parent = _Qizi.transform.parent; //设置相同的父物体方便我们管理 
                mQizi[i, j].transform.localPosition = new Vector3(OriginPoint.x + (j) * TwohengWidth, OriginPoint.y + (i) * TwohengWidth, 0); 
                mQizi[i, j].transform.localScale = new Vector3(1, 1, 1); //父物体改变后我们应该重新设置scale 
               mQizi[i,j].transform.FindChild("Quan").GetComponent().enabled = false; 
               mQizi[i,j].transform.FindChild("Chacha").GetComponent().enabled = false; 
—————————————updata应该放什么——————————————— 
nothing , 这个简单的游戏机制导致我们不用设置“等待”和 “过渡” 这样的东西.... 
—————————————扩展学习部分——————— 
通常我们见到的简单的状态机都是类似这样的设置..   
void updata() 

   if (gameState == MyAction){} 
   else if(gameState == AiAction){} 
    else if(gameState==GameOver){} 

———————————button怎么交互——————————————— 
还记得池塘边的夏荷么  还记得上面的Button message 发送给ui root的fun 函数么 
我们对物体进行  y_x 这样的命名就是方便干这个的... 
void ButtonPress(GameObject o)  这个函数要通过GameObject o这样的参数得到它自身 
简单来说,我们点了button之后就sendmessage给这个函数了 
  
  
通过对button的名字的操作   可以得到物体所处的横竖坐标 
string[] _strArr = (o.name).Split(new char[]{'_'}); 
int _row = Convert.ToInt32(_strArr[1]); 
int _column = Convert.ToInt32(_strArr[2]); 
比如这个qizi_0_0就是表示左下角数起的0,0 这个棋子 
int数组中坐标排列方式 

(2,0),(2,1),(2,2) 
(1,0),(1,1),(1,2) 
(0,0),(0,1),(0,2) 

然后我们判断现在的游戏状态(也就是是谁在下) 
if (gameState == GameState.MyAction) 这样 
  
然后判断下的棋子是不是空格(只有空格子能下) 
if (isNullStep(BoxMatrix , _row, _column)) 
能下的空格子的话就改变BoxMatrix【】【】的值,改成1或者-1 
———————重要的逻辑判断——————— 
分为4大步骤: 
1先判断横列 
2判断数列 
3如果是斜边的话,判断斜边的列 
4如果TotleStep ==棋盘大小,则和局  游戏结束 
这里说得好简单   其实真正写起来这个好复杂.... 
——————————

完整代码:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System;
  4.  
  5. /**
  6. * by:KuKu小夭
  7. * email:djy2130@qq.com
  8. */
  9.  
  10. public class QuanQuan : MonoBehaviour {
  11. public GameObject gamePanel;
  12. public GameObject ShowLable;
  13. public GameObject _Qizi;
  14. public int number_N = ;//行列数
  15. public int TwohengWidth = ;//两个横边之间的间隔
  16.  
  17. private int BoxHeight;
  18. private int BoxWidth;
  19. private int[,] BoxMatrix;
  20. private Vector3 OriginPoint;//左下角原点的位置
  21. private int TotleStep = ;//总共下的次数,如果次数等于棋盘的大小则和局
  22. private int _winTotle = ; //几个子连一起为赢。
  23.  
  24. enum GameState
  25. {
  26. MyAction,
  27. AiAction,
  28. GameOver,
  29. }
  30. GameState gameState = GameState.MyAction;
  31.  
  32. void Start()
  33. {
  34.  
  35. BoxHeight = number_N;
  36. BoxWidth = number_N;
  37.  
  38. BoxMatrix = new int[BoxHeight, BoxWidth];
  39. //0 表示空,1表示圈,-1表示叉
  40. //创建一个和棋盘等数量的int数组
  41. OriginPoint = new Vector3(-(BoxWidth - ) * 0.5f * TwohengWidth, -(BoxHeight - ) * 0.5f * TwohengWidth, );
  42. /*
  43. if (number_N%2==0)
  44. {
  45. OriginPoint = new Vector3(-(BoxWidth-1) * 0.5f * TwohengWidth, -(BoxHeight-1) * 0.5f * TwohengWidth, 0);
  46. }else{
  47. OriginPoint = new Vector3(-(BoxWidth-1) * 0.5f * TwohengWidth, -(BoxHeight-1) * 0.5f * TwohengWidth, 0);
  48. }
  49. */
  50.  
  51. //最重要的部分
  52. GameObject[,] mQizi = new GameObject[BoxWidth,BoxHeight];
  53. for (int i = ; i < BoxWidth; i++)
  54. {
  55. for (int j = ; j < BoxHeight; j++)
  56. {
  57. BoxMatrix[i, j] = ;
  58. mQizi[i, j] = Instantiate(_Qizi) as GameObject;
  59. mQizi[i, j].name = "qizi_"+i+"_"+j; //命名很重要 因为我们在button获取信息时就是通过name的不同来区分不同物体的
  60. mQizi[i, j].transform.parent = _Qizi.transform.parent;
  61. mQizi[i, j].transform.localPosition = new Vector3(OriginPoint.x + (j) * TwohengWidth, OriginPoint.y + (i) * TwohengWidth, );
  62. mQizi[i, j].transform.localScale = new Vector3(, , );
  63. }
  64. }
  65. _Qizi.transform.localPosition = new Vector3(-, , );//这个东西移到屏幕外
  66. //Destroy(_Qizi);
  67. }
  68.  
  69. //动作
  70. void ButtonPress(GameObject o)
  71. {
  72. if (gameState == GameState.MyAction)
  73. {
  74. string[] _strArr = (o.name).Split(new char[]{'_'});
  75. int _row = Convert.ToInt32(_strArr[]);
  76. int _column = Convert.ToInt32(_strArr[]);
  77. //Debug.Log(_row + "," + _column);
  78. if (isNullStep(BoxMatrix , _row, _column))
  79. {
  80. BoxMatrix[_row, _column] = ;
  81. o.transform.FindChild("Quan").GetComponent<UISprite>().enabled = true;
  82. bool isGameover = Logic(BoxMatrix, _row, _column);
  83. if (isGameover) { gameState = GameState.GameOver; }
  84. else{ gameState = GameState.AiAction;}
  85. }
  86. }
  87. else if (gameState == GameState.AiAction)
  88. {
  89. string[] _strArr = (o.name).Split(new char[] { '_' });
  90. int _row = Convert.ToInt32(_strArr[]);
  91. int _column = Convert.ToInt32(_strArr[]);
  92. //Debug.Log(_row + "," + _column);
  93. if (isNullStep(BoxMatrix , _row, _column))
  94. {
  95. BoxMatrix[_row, _column] = -;
  96. o.transform.FindChild("Chacha").GetComponent<UISprite>().enabled = true;
  97. bool isGameover = Logic(BoxMatrix, _row, _column);
  98. if (isGameover) { gameState = GameState.GameOver; }
  99. else { gameState = GameState.MyAction; }
  100. }
  101. }
  102. }
  103.  
  104. bool isNullStep(int[,] _Matrix, int row, int column)
  105. {
  106. if (_Matrix[row, column] == )
  107. {
  108. return true;
  109. }
  110. return false;
  111. }
  112.  
  113. bool Logic(int[,] _Matrix,int row, int column)
  114. {
  115. //check row
  116. int _totle = ;
  117. for(int i=; i < number_N;i++)
  118. {
  119. _totle += _Matrix[i,column];
  120. }
  121. if (_totle == _winTotle)
  122. {
  123. Winner(); return true;
  124. }
  125. else if (_totle == - * _winTotle)
  126. {
  127. Winner(); return true;
  128. }
  129.  
  130. //check column
  131. _totle = ;
  132. for(int i=; i < number_N;i++)
  133. {
  134. _totle += _Matrix[row,i];
  135. }
  136. if (_totle == _winTotle)
  137. {
  138. Winner(); return true;
  139. }
  140. else if (_totle == - * _winTotle)
  141. {
  142. Winner(); return true;
  143. }
  144.  
  145. ////check left xie 这里只判断最长的斜对角线
  146. //if(row ==column){
  147. // _totle = 0;
  148. // for (int i = 0; i < number_N; i++)
  149. // {
  150. // _totle += _Matrix[i, i];
  151. // }
  152. // if (_totle == number_N)
  153. // {
  154. // Winner(1); return true;
  155. // }
  156. // else if (_totle == -1 * number_N)
  157. // {
  158. // Winner(2); return true;
  159. // }
  160. //}
  161.  
  162. ////check right xie 这里只判断对角线
  163. //if(row == number_N - 1 - column)
  164. //{
  165. // _totle = 0;
  166. // for (int i = 0; i < number_N; i++)
  167. // {
  168. // _totle += _Matrix[i, number_N - i-1];
  169. // }
  170. // if (_totle == number_N)
  171. // {
  172. // Winner(1); return true;
  173. // }
  174. // else if (_totle == -1 * number_N)
  175. // {
  176. // Winner(2); return true;
  177. // }
  178. //}
  179.  
  180. int iCount = row + column;
  181. //check left xie
  182. _totle = ;
  183. //把棋盘分成两部分,沿对角线分
  184. if (iCount < number_N) //在对角线下部分,必定有[x,0]
  185. {
  186. for (int j = ; j < iCount + ; j++)
  187. {
  188. _totle += _Matrix[iCount - j, j];
  189. }
  190. if (_totle == _winTotle)
  191. {
  192. Winner(); return true;
  193. }
  194. else if (_totle == - * _winTotle)
  195. {
  196. Winner(); return true;
  197. }
  198. }
  199. else //在对角线上,必定有[8,x]
  200. {
  201. int i = * (number_N - ) - iCount;
  202. for (int j = number_N - , k = number_N - - i; j >= number_N - - i; j--, k++)
  203. {
  204. _totle += _Matrix[j, k];
  205. }
  206. if (_totle == _winTotle)
  207. {
  208. Winner(); return true;
  209. }
  210. else if (_totle == - * _winTotle)
  211. {
  212. Winner(); return true;
  213. }
  214. }
  215.  
  216. //check right xie
  217. _totle = ;
  218. if (column >= row) //对角线下方
  219. {
  220. int i = number_N - (column - row);
  221. for (int j = ; j < i; j++)
  222. {
  223. _totle += _Matrix[j, j + column - row];
  224. }
  225. if (_totle == _winTotle)
  226. {
  227. Winner(); return true;
  228. }
  229. else if (_totle == - * _winTotle)
  230. {
  231. Winner(); return true;
  232. }
  233. }
  234. else //对角线上方
  235. {
  236. int i = number_N + (column - row);
  237. for (int j = ; j < i; j++)
  238. {
  239. _totle += _Matrix[j - column + row, j];
  240. }
  241.  
  242. if (_totle == _winTotle)
  243. {
  244. Winner(); return true;
  245. }
  246. else if (_totle == - * _winTotle)
  247. {
  248. Winner(); return true;
  249. }
  250. }
  251. //检查是不是和局
  252. TotleStep++;
  253. if (TotleStep == BoxHeight * BoxWidth)
  254. {
  255. Winner();return true;
  256. }
  257.  
  258. return false;
  259. }
  260.  
  261. void Winner(int player)
  262. {
  263. if (player==)
  264. {
  265. ShowLable.GetComponent<UILabel>().enabled = true;
  266. ShowLable.GetComponent<UILabel>().text = "winner 1";
  267. }
  268. else if (player == )
  269. {
  270. ShowLable.GetComponent<UILabel>().enabled = true;
  271. ShowLable.GetComponent<UILabel>().text = "winner 2";
  272. }
  273. else
  274. {
  275. ShowLable.GetComponent<UILabel>().enabled = true;
  276. ShowLable.GetComponent<UILabel>().text = "no winner";
  277. }
  278. }
  279. }

项目下载地址:http://pan.ceeger.com/viewfile.php?file_id=1823&file_key=0KzsoygG

unity3d游戏开发(一)——圈圈叉叉的更多相关文章

  1. Unity3D游戏开发初探—2.初步了解3D模型基础

    一.什么是3D模型? 1.1 3D模型概述 简而言之,3D模型就是三维的.立体的模型,D是英文Dimensions的缩写. 3D模型也可以说是用3Ds MAX建造的立体模型,包括各种建筑.人物.植被. ...

  2. 从一点儿不会开始——Unity3D游戏开发学习(一)

    一些废话 我是一个windows phone.windows 8的忠实粉丝,也是一个开发者,开发数个windows phone应用和两个windows 8应用.对开发游戏一直抱有强烈兴趣和愿望,但奈何 ...

  3. Unity3D游戏开发之连续滚动背景

    Unity3D游戏开发之连续滚动背景 原文  http://blog.csdn.net/qinyuanpei/article/details/22983421 在诸如天天跑酷等2D游戏中,因为游戏须要 ...

  4. Unity3D游戏开发从零单排(四) - 制作一个iOS游戏

    提要 此篇是一个国外教程的翻译,尽管有点老,可是适合新手入门. 自己去写代码.debug,布置场景,能够收获到非常多.游戏邦上已经有前面两部分的译文,这里翻译的是游戏的最后一个部分. 欢迎回来 在第一 ...

  5. [Unity3D]Unity3D游戏开发之飞机大战项目解说

    大家好,我是秦元培,欢迎大家继续关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 首先感谢大家对我博客的关注,今天我想和大家分享的是一个飞机大战的项目.这是一个比較综合的 ...

  6. [Unity3D]Unity3D游戏开发《反对》说到游戏(上)——目标跟踪

    朋友,大家好.我是秦培,欢迎关注我的博客.我的博客地址blog.csdn.net/qinyuanpei. 首先博主要自我反省,过了这么久才来更新博客,这段时间主要是在忙着写期末的作业,所以博主基本上没 ...

  7. [Unity3D]Unity3D游戏开发3D选择场景中的对象,并显示轮廓效果强化版

    大家好,我是秦培,欢迎关注我的博客,我的博客地址blog.csdn.net/qinyuanpei. 在上一篇文章中,我们通过自己定义着色器实现了一个简单的在3D游戏中选取.显示物体轮廓的实例. 在文章 ...

  8. [Unity3D]Unity3D游戏开发之跑酷游戏项目解说

    大家好,我是秦元培.我參加了CSDN2014博客之星的评选,欢迎大家为我投票,同一时候希望在新的一年里大家能继续支持我的博客. 大家晚上好.我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.c ...

  9. [Unity3D]Unity3D游戏开发之异步记载场景并实现进度条读取效果

    大家好,我是秦元培.欢迎大家关注我的博客,我的博客地址是:blog.csdn.net/qinyuanpei.终于在各种无语的论文作业中解脱了,所以立即抓紧时间来这里更新博客.博主本来计划在Unity3 ...

  10. [Unity3D]Unity3D游戏开发之伤害数值显示

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.众所周知,在RPG游戏策划中最为重要的一个环节是数值策划.数值策划是一个关于游戏平衡方面的概念 ...

随机推荐

  1. mysql中的第三范式

    ※多表操作 (凡是多表,都要用到关联技术(把多表合并成一个新表): 左关联.右关联.内关联.还有一个外(全)关联,MySQL不支持,为考虑软件兼容,我们开发一般不用.) ※表与表之间的关系:1对1,1 ...

  2. UILabel 自动换行 和支持换行符

    这个主要是 lable对\n换行符号的支持,有的时候我们从网页或者后台拿到的数据需要处理一下: 这里没什么要说的,注意两点,一个是label的numofline属性的值要为0 或者不能为1  这样la ...

  3. HashMap、HashSet源代码分析其 Hash 存储机制

    集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象的引用放入数组中,每个数组元素都是一个引用变量. 实际上,HashSet ...

  4. 301页面转向 php

    新建301.php页面,在程序入口文件index.php引用301.php页面 301.php内容如下,仅用于参考: <?php$the_host = $_SERVER['HTTP_HOST'] ...

  5. JAXB - XML Schema Types, Defining Types for XML Elements With Content

    Content: A Value The content of an XML element may be some value, or one or more subordinate element ...

  6. ASP保存远程图片文件到本地代码

    <% Function SaveRemoteFile(LocalFileName,RemoteFileUrl) SaveRemoteFile=True dim Ads,Retrieval,Get ...

  7. php文件上传限制

    PHP默认的上传限定是最大2M,想上传超过此设定的文件,需要调整PHP.apache等的一些参数.下面,我们简要介绍一下PHP文件上传涉及到的一些参数: file_uploads :是否允许通过HTT ...

  8. Operation not allowed for reason code "7" on table 原因码 "7"的解决

    对表进行任何操作都不被允许,提示SQLSTATE=57016 SQLCODE=-668 ,原因码 "7"的错误:SQL0668N Operation not allowed for ...

  9. Linux 网络相关命令

    1.修改ip,dns相关:sudo vi /etc/sysconfig/network-scripts/ifcfg-eth0 2.ifconfig 查找ip,mac地址 3.重启网络:sudo ser ...

  10. 关于修改tabbar的颜色的问题

    首先,项目是在故事板中搭建的,所以遇到这个问题的时候,首先是想到在故事板中找到相关的属性,确实是有一个Selected Image,但是设置了这个图片以后,运行的效果是,点击选择后,本身的image就 ...