李虹霖

 

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

 

posted on 2015-03-11 20:48  lol霖  阅读(796)  评论(0编辑  收藏  举报

导航