• unity3d游戏开发(一)——圈圈叉叉


    参考: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 ==棋盘大小,则和局  游戏结束 
    这里说得好简单   其实真正写起来这个好复杂.... 
    —————————— 

    完整代码:

    using UnityEngine;
    using System.Collections;
    using System;
    
    /**
     * by:KuKu小夭
     * email:djy2130@qq.com
     */
    
    public class QuanQuan : MonoBehaviour {
        public GameObject gamePanel;
        public GameObject ShowLable;
        public GameObject _Qizi;
        public int number_N = 3;//行列数
        public int TwohengWidth = 50;//两个横边之间的间隔
    
        private int BoxHeight;
        private int BoxWidth;
        private int[,] BoxMatrix;
        private Vector3 OriginPoint;//左下角原点的位置
        private int TotleStep = 0;//总共下的次数,如果次数等于棋盘的大小则和局
        private int _winTotle = 4; //几个子连一起为赢。
    
        enum GameState
        {
            MyAction,
            AiAction,
            GameOver,
        }
        GameState gameState = GameState.MyAction;
    
        void Start()
        {
            
            BoxHeight = number_N;
            BoxWidth = number_N;
    
            BoxMatrix = new int[BoxHeight, BoxWidth];
            //0 表示空,1表示圈,-1表示叉
            //创建一个和棋盘等数量的int数组
            OriginPoint = new Vector3(-(BoxWidth - 1) * 0.5f * TwohengWidth, -(BoxHeight - 1) * 0.5f * TwohengWidth, 0);
            /*
            if (number_N%2==0)
            {
                OriginPoint = new Vector3(-(BoxWidth-1) * 0.5f * TwohengWidth, -(BoxHeight-1) * 0.5f * TwohengWidth, 0);
            }else{
                OriginPoint = new Vector3(-(BoxWidth-1) * 0.5f * TwohengWidth, -(BoxHeight-1) * 0.5f * TwohengWidth, 0);
            }
             */ 
    
            //最重要的部分
            GameObject[,] mQizi = new GameObject[BoxWidth,BoxHeight];
            for (int i = 0; i < BoxWidth; i++)
            {
                for (int j = 0; j < BoxHeight; j++)
                {
                    BoxMatrix[i, j] = 0; 
                    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);
                }
            }
            _Qizi.transform.localPosition = new Vector3(-1000, 0, 0);//这个东西移到屏幕外
            //Destroy(_Qizi);
        }
    
        //动作
        void ButtonPress(GameObject o)
        {
            if (gameState == GameState.MyAction)
            {
                string[] _strArr = (o.name).Split(new char[]{'_'});
                int _row = Convert.ToInt32(_strArr[1]);
                int _column = Convert.ToInt32(_strArr[2]);
                //Debug.Log(_row + "," + _column);
                if (isNullStep(BoxMatrix , _row, _column))
                {
                    BoxMatrix[_row, _column] = 1;
                    o.transform.FindChild("Quan").GetComponent<UISprite>().enabled = true;
                    bool isGameover = Logic(BoxMatrix, _row, _column);
                    if (isGameover) { gameState = GameState.GameOver; }
                    else{  gameState = GameState.AiAction;}
                }
            }
            else if (gameState == GameState.AiAction)
            {
                string[] _strArr = (o.name).Split(new char[] { '_' });
                int _row = Convert.ToInt32(_strArr[1]);
                int _column = Convert.ToInt32(_strArr[2]);
                //Debug.Log(_row + "," + _column);
                if (isNullStep(BoxMatrix , _row, _column))
                {
                    BoxMatrix[_row, _column] = -1;
                    o.transform.FindChild("Chacha").GetComponent<UISprite>().enabled = true;
                    bool isGameover = Logic(BoxMatrix, _row, _column);
                    if (isGameover) { gameState = GameState.GameOver; }
                    else { gameState = GameState.MyAction; }
                }
            }
        }
    
        bool isNullStep(int[,] _Matrix, int row, int column)
        {
            if (_Matrix[row, column] == 0)
            {
                return true;
            }
            return false;
        }
    
        bool Logic(int[,] _Matrix,int row, int column)
        {
            //check row
            int _totle =0 ; 
            for(int i=0; i < number_N;i++)
            {
                _totle += _Matrix[i,column];
            }
            if (_totle == _winTotle)
            {
                Winner(1); return true;
            }
            else if (_totle == -1 * _winTotle)
            {
                Winner(2); return true;
            }
    
            //check column
            _totle = 0;
            for(int i=0; i < number_N;i++)
            {
                _totle += _Matrix[row,i];
            }
            if (_totle == _winTotle)
            {
                Winner(1); return true;
            }
            else if (_totle == -1 * _winTotle)
            {
                Winner(2); return true;
            }
    
            ////check left xie 这里只判断最长的斜对角线
            //if(row ==column){
            //    _totle = 0;
            //    for (int i = 0; i < number_N; i++)
            //    {
            //        _totle += _Matrix[i, i];
            //    }
            //    if (_totle == number_N)
            //    {
            //        Winner(1); return true;
            //    }
            //    else if (_totle == -1 * number_N)
            //    {
            //        Winner(2); return true;
            //    }
            //}
    
            ////check right xie  这里只判断对角线
            //if(row == number_N - 1 - column)
            //{
            //    _totle = 0;
            //    for (int i = 0; i < number_N; i++)
            //    {
            //        _totle += _Matrix[i, number_N - i-1];
            //    }
            //    if (_totle == number_N)
            //    {
            //        Winner(1); return true;
            //    }
            //    else if (_totle == -1 * number_N)
            //    {
            //        Winner(2); return true;
            //    }
            //}
    
            int iCount = row + column;
            //check left xie
            _totle = 0;
            //把棋盘分成两部分,沿对角线分
            if (iCount < number_N)      //在对角线下部分,必定有[x,0]
            {
                for (int j = 0; j < iCount + 1; j++)
                {
                    _totle += _Matrix[iCount - j, j];
                }
                if (_totle == _winTotle)
                {
                    Winner(1); return true;
                }
                else if (_totle == -1 * _winTotle)
                {
                    Winner(2); return true;
                }
            }
            else    //在对角线上,必定有[8,x]
            {
                int i = 2 * (number_N - 1) - iCount;
                for (int j = number_N - 1, k = number_N - 1 - i; j >= number_N - 1 - i; j--, k++)
                {
                    _totle += _Matrix[j, k];
                }
                if (_totle == _winTotle)
                {
                    Winner(1); return true;
                }
                else if (_totle == -1 * _winTotle)
                {
                    Winner(2); return true;
                }
            }
    
            //check right xie
            _totle = 0;
            if (column >= row) //对角线下方
            {        
                int i = number_N - (column - row);
                for (int j = 0; j < i; j++)
                {
                    _totle += _Matrix[j, j + column - row];
                }
                if (_totle == _winTotle)
                {
                    Winner(1); return true;
                }
                else if (_totle == -1 * _winTotle)
                {
                    Winner(2); return true;
                }
            }
            else    //对角线上方
            {
                int i = number_N + (column - row);
                for (int j = 0; j < i; j++)
                {
                    _totle += _Matrix[j - column + row, j];
                }
    
                if (_totle == _winTotle)
                {
                    Winner(1); return true;
                }
                else if (_totle == -1 * _winTotle)
                {
                    Winner(2); return true;
                }
            }
            //检查是不是和局
         TotleStep++;
         if (TotleStep == BoxHeight * BoxWidth)
         {
            Winner(3);return true;
         }
            
            return false;
        }
    
        void Winner(int player)
        {
            if (player==1)
            {
                ShowLable.GetComponent<UILabel>().enabled = true;
                ShowLable.GetComponent<UILabel>().text = "winner 1";
            }
            else if (player == 2)
            {
                ShowLable.GetComponent<UILabel>().enabled = true;
                ShowLable.GetComponent<UILabel>().text = "winner 2";
            }
            else
            {
                ShowLable.GetComponent<UILabel>().enabled = true;
                ShowLable.GetComponent<UILabel>().text = "no winner";
            }
        }
    }

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

  • 相关阅读:
    背包九讲
    最小生成树 prime + 队列优化
    最小生成树 prime poj1287
    树状数组--转载
    O(n)求1-n的逆元
    数据结构--线段树
    博弈
    RMQ 数据结构
    BZOJ3687 计算子集和的异或和
    Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined)D Dense Subsequence
  • 原文地址:https://www.cnblogs.com/martianzone/p/3368392.html
Copyright © 2020-2023  润新知