• unity 2048Game


    将游戏分为四个脚本,将数据和界面分开,这是开发模式常用的类似于mvc模式,但由于我们只用一个二位数组就可以保存数据,所以讲m省略

    GameControllor 控制游戏数据的脚本,

    using UnityEngine;
    using System.Collections;
    
    public enum DIR_TYPE
    {
        TOP,
        LEFT,
        RIGHT,
        BOTTOM
    }
    public class GameControllor : MonoBehaviour {
    
        public int[,] datas; //游戏数据
        public int row = 4;
        public int col = 4;
        bool isOver;
        bool isWin;
        int score;
        int emptyNumber; // 空格子数
        int[] temp;//一个临时数组,存放十六个位置数据
        DIR_TYPE type = DIR_TYPE.TOP; 
        void Awake()
        {
            datas = new int[row,col];
            isOver = false;
            isWin = false;
            emptyNumber = row * col ;
            score = 0;
            temp = new int[row+1];//一个临时数组,存放十六个位置数据
            RandomNumber();
        }
        void RandomNumber()
        {
            
            if( emptyNumber == row * col )
            {
                for(int i = 0; i < 2; ++i)
                {
                    RandomCell();
                }
                
            }
            else if( emptyNumber > 0 )
            {
                RandomCell();
            }
            IsOver();
            IsWin();
        }
        
        void RandomCell()
        {
            int r = Random.Range(0,row);
            int c = Random.Range(0,col);
            if( 0 == datas[r,c] )
            {
                datas[r,c] = 2;
                emptyNumber--;
            }
            else{
                RandomCell ();
            }
        }
        // Update is called once per frame
        void Update () {
            KeyboardListenEvt();
        }
        void KeyboardListenEvt()
        {
            if( Input.GetKeyDown(KeyCode.W) )
            {
                GameRun(DIR_TYPE.TOP );
            }
            if( Input.GetKeyDown(KeyCode.S) )
            {
                GameRun( DIR_TYPE.BOTTOM );
            }
            if( Input.GetKeyDown(KeyCode.A) )
            {
                GameRun( DIR_TYPE.LEFT );
            }
            if( Input.GetKeyDown(KeyCode.D) )
            {
                GameRun( DIR_TYPE.RIGHT );
            }
            
        }
        void Swap(ref int a, ref int b)
        {
            a = (a + b) - (b = a);
        }
        //玩家可以选择上下左右四个方向,若棋盘内的数字出现位移或合并,视为有效移动
        public int GameMove( )
        {
            int change = 0;
            int i = 0;
            int j = 0;
            do //去掉中间的0
            {  
                for (i = 0; i < 4; ++i )
                {
                    if (0 == temp[i])//玩家选择的方向行或列前方有空格则出现位移
                    {
                        if (temp[i] != temp[i + 1])//不相等移动
                        {
                            change = 1;//有效移动
                        }
                        temp[i] = temp[i + 1];
                        temp[i + 1] = 0;
                    }
                }
                j++;
            } while (j < 4);
            
            for (i = 1; i < 4; ++i )
            {
                //玩家选择的方向上若有相同的数字则合并,每次有效移动可以同时合并,但不可以连续合并
                if (temp[i] == temp[i - 1])//相同的数字则合并
                {
                    if (0 != temp[i])
                    {
                        change = 1;
                        score += temp[i];
                        emptyNumber++;
                    }
                    temp[i - 1] += temp[i - 1];//前一个数字乘自己
                    temp[i] = 0;// 后一个位置 置0    
                }
                
            }
            
            do //去掉中间的0
            {  
                for (i = 0; i < 4; ++i )
                {
                    if (0 == temp[i])//玩家选择的方向行或列前方有空格则出现位移
                    {
                        if (temp[i] != temp[i + 1])//不相等移动
                        {
                            change = 1;//有效移动
                        }
                        temp[i] = temp[i + 1];
                        temp[i + 1] = 0;
                    }
                }
                j++;
            } while (j < 4);
            return change;
        }
        void GameRun(DIR_TYPE type)
        {
            
            int i = 0;
            int j = 0;
            int change = 0;/*判断格子中的数是否改变,0不变*/
            
            if (type == DIR_TYPE.LEFT || type == DIR_TYPE.RIGHT)
            {
                for (i = 0; i < row; ++i)
                {
                    for (j = 0; j < col; ++j)
                    {
                        if (type == DIR_TYPE.LEFT)
                        {
                            temp[j] = datas[i, j];//把每一行数据放到临时数组中
                        }
                        else
                        {
                            temp[j] = datas[i, 3 - j];
                        }
                    }
                    //temp[4] = 0;
                    
                    change += GameMove();//处理每一行数据,进行移除中间的0,合并相同数字,根据change的值可以产生随机数
                    
                    for (j = 0; j < col; ++j)
                    {
                        if (type == DIR_TYPE.LEFT)
                        {
                            datas[i, j] = temp[j];// 把每一行处理完的数据在放回到地图中
                        }
                        else
                        {
                            datas[i, 3 - j] = temp[j];
                        }
                    }
                }
            }
            else
            {
                
                for (i = 0; i < row; ++i)
                {
                    for (j = 0; j < col; ++j)
                    {
                        
                        if (type == DIR_TYPE.TOP)
                        {
                            temp[j] = datas[j, i];//把每一列数据存进去
                        }
                        else if (type == DIR_TYPE.BOTTOM)
                        {
                            temp[j] = datas[3 - j, i];
                        }
                        
                    }
                    temp[row] = 0;
                    change += GameMove();
                    
                    for (j = 0; j < col; ++j)
                    {
                        if (type == DIR_TYPE.TOP)
                        {
                            datas[j, i] = temp[j]; //把处理好的中间变量移回来
                        }
                        else if (type == DIR_TYPE.BOTTOM)
                        {
                            datas[3 - j, i] = temp[j];
                        }
                    }
                }
            }
            
            
            if (change > 0)
            {
                RandomNumber();
            }
        }
        public bool IsOver()
        {
            if(0 == emptyNumber) 
            {
                bool shoultOver = true;
                for (int i = 0; i < row - 1; i++) {
                    for (int j = 0; j < col - 1; j++) {
                        if( datas[i,j] == datas[i + 1,j] ){
                            shoultOver = false;
                            break;
                        }
                        if( datas[i,j] == datas[i,j + 1] ){
                            shoultOver = false;
                            break;
                            }
                    }
                    if(!shoultOver)
                    break;
                }
                isOver = shoultOver;
            }
            return isOver;
        }
        public int GetScore()
        {
            return score;
        }
        public bool IsWin()
        {
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    if(datas[i,j] >= 2048)
                    {
                        isWin = true;
                    }
                }
            }
            return isWin;
        }
    }

    将单元格图片 绘制到背景图片上

    using UnityEngine;
    using System.Collections;
    
    public class BackGroundScript : MonoBehaviour {
        
        public GameObject cell; //单元格
        static Vector2 startPos = new Vector2(-1.65f, 1.65f); // 起始位置
        static float offetX = 1.1f;    // 左右单元格的间隔
        static float offsetY = 1.1f;    // 上下两个单元的间隔
        
        //public Sprite sprite;
        // 在这之前把摄像机调整为正交模式(Orthographic)并且把bg层级调整为-1 Order in layer
        void Awake()
        {
            DrawMapCell();
        }
        
        // 绘制地图格子
        void DrawMapCell()
        {
            // 排列出背景单元格
            for( int i = 0; i< 4; ++i )
            {
                for (int j = 0; j < 4; j++) {
                    // 从预设体实例化游戏对象
                    GameObject c = Instantiate(cell, GetPos(i,j), Quaternion.identity) as GameObject;
                    // 设置游戏对象的父对象
                    c.transform.parent = transform; 
                }
            }
        }
        // 获取位置
        public static Vector2 GetPos(int r, int c)
        {
            // 计算每个单元个位置
            float x = startPos.x + c * offetX ;
            float y = startPos.y - r * offsetY ;
            Vector2 pos = new Vector2(x, y);
            return pos;
        }
    }

    控制显示界面,直接调用GameControl里的数据,在Update里每帧刷新一次界面,来检测数据是否需要更新

    using UnityEngine;
    using System.Collections;
    
    public class ViewControllor : MonoBehaviour {
    
        public GameObject cell;// 单元格预设体文件
        GameObject[,] cells;// 保存所有界面上cell
        GameControllor gameControl;
        // 
        void Awake()
        {
            // 获取游戏控制器的脚本组件
            gameControl = GameObject.FindGameObjectWithTag("GameController").GetComponent<GameControllor>() ;
            cells = new GameObject[gameControl.row,gameControl.col];
        }
        
        // Update is called once per frame
        void Update () {
            RefreshView();
        }
        // 刷新界面
        void RefreshView()
        {
            // 检测数据变化来刷新界面
            for (int i = 0; i < gameControl.row; i++) {
                for (int j = 0; j < gameControl.col; j++) {
                    // 遍历数据数组中的每一个元素的值
                    int data = gameControl.datas[i,j];
                    // 判断是否要创建一个cell
                    // 数据本身不是0 
                    if( 0 != data && cells[i,j] == null )
                    {
                        // 在具体位置创建新的游戏对象 创建新的cell 并保存起来
                        GameObject c = Instantiate(cell, BackGroundScript.GetPos(i,j), Quaternion.identity) as GameObject;
                        c.transform.parent = transform;// viewControl shi tade 
                        cells[i,j] = c;
                    }
                    // 判断界面上以显示的cell
                    else if( null != cells[i,j] && cells[i,j].GetComponent<CellScript> ().num != data )    
                    {
                        cells[i,j].GetComponent<CellScript> ().ChangeNumber(data);
                    }    
                }
            }
            
        }
        void OnGUI()
        {
            GUI.skin.label.fontSize = 40;
            GUI.color = Color.red;
            if(gameControl.IsOver())
                GUI.Label(new Rect(Screen.width >> 1,Screen.height >> 1,100,100),"Game over!");
            if(gameControl.IsWin())
                GUI.Label(new Rect(Screen.width >> 1,Screen.height >> 1,100,100),"Game Win!");
            GUI.Label(new Rect(100f,20,100,100),gameControl.GetScore().ToString());
        }
    }

    这个类的作用是给预设体添加一个脚本,预设体里的精灵数组保存的用到的十张数字图

    using UnityEngine;
    using System.Collections;
    // 这个类的作用是给预设体添加一个脚本,预设体里的精灵数组保存的用到的十张数字图
    public class CellScript : MonoBehaviour {
    
        public Sprite[] sprites; // 精灵数组
        public int index; // 当前下标
        public int num; // 当前cell显示的数字
        void Awake()
        {
            num = 2;
        }
        // 改变cell当前显示的数字
        public void ChangeNumber(int number)
        {
            num = number;
            // 如果是0就干掉cell
            if( 0 == number )
            {
                Destroy(transform.gameObject);
            }
            // 如果不是0 就替换图片
            else{
                // 该数字是 数组对应的下标  2 的 number 次方
                index = (int)Mathf.Log(number , 2) - 1;
                transform.GetComponent<SpriteRenderer> ().sprite = sprites[index];
            }
            
        }
    }
  • 相关阅读:
    Basic knowledge of html (keep for myself)
    科学技术法转成BigDemcial
    SimpleDateFormat
    log4j 配置实例
    R 实例1
    yield curve
    if-else的优化举例
    十二、高级事件处理
    十一、Swing
    十、输入/输出
  • 原文地址:https://www.cnblogs.com/lihonglin2016/p/4330920.html
Copyright © 2020-2023  润新知