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];

        }

        

    }

}

 

你可能感兴趣的:(unity)