将游戏分为四个脚本,将数据和界面分开,这是开发模式常用的类似于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]; } } }