首页 > 代码库 > 也来山寨一个2048

也来山寨一个2048

2048最近似乎热度已过,但是并不影响我山寨一个它。周末闲来无事,终于付诸实现,包含winform和js版本。有图有真相

 实现思路:

1、通过二维数组data=http://www.mamicode.com/int[4][4]来存储游戏数据,初始全部为0

2、游戏初始在4X4布局中随机位置产生2个随机数(只随机2,4)

//初始化游戏数据        void InitGame()        {            ClearGame();            Random rand = new Random();            int pos1 = Convert.ToInt32(rand.Next(16));            SetData(pos1, rand.NextDouble() < 0.8 ? 2 : 4);            int pos2 = GetRandPos();            SetData(pos2, rand.NextDouble() < 0.8 ? 2 : 4);         }
View Code

分解:

  a、随意位置产生一个随机数

  b、在剩下的随机空白位置产生一个随机数,此方法在游戏移动后产生一个随机数时也要用到。随机空白位置的产生:遍历数据数组data,取得所有位置为空的集合pos,data中数据为0的即对应位置为空,可产生随机数;在pos中产生随机位置。

//随机产生空格处的坐标位置        int GetRandPos()        {            List<int> pos = new List<int>();            for (int i = 0; i < 4; i++)            {                for (int j = 0; j < 4; j++)                {                    if (data[i,j] == 0)                        pos.Add(4 * i + j);//数组坐标刚好可以通过pos/4,pos%4得到                }            }            Random r = new Random();            int rand = r.Next(pos.Count);            return pos[rand];        }
View Code

   这里要注意data[i][j]和布局位置的对应关系:data[i][j]=>pos[4*i+j],pos[i]=>data[i/4][i%4];

3、移动操作:先合并再移动,以左移为例

  a)、查找可合并的元素合并,以一次合并为例:

0123

 

  1) data1=从左到右第一个不为0的元素,假设是第j位置pos[j]

  2) data2=pos[j+1]

  3) a.  data1==data2则进行合并操作

    b.  data2==0,data2下移一个

    c. data2!=0&&data1!=data2,不能合并

//先合并元素            for (int i = 0; i < 4; i++)            {                for (int j = 0; j < 4; j++)                {                    int tb = data[i,j];//取一个元素值                    if (tb != 0)                    {                        for (int k = j + 1; k < 4; k++)                        {                            int nexttb = data[i,k];//下一元素值                            if (nexttb != 0)                            {                                if (tb == nexttb)                                {//相等合并,计算分数,设置移动状态                                    data[i,j] = tb * 2;                                    data[i,k] = 0;                                    totalscore += tb * 2;                                    moveflag = true;                                }                                break;                            }                        }                    }                }            }
View Code

  b)、合并完成后移动元素至最左端

  前面的元素为空就依次把后面不为空的元素往前移,移动后后面元素置为空

//合并之后移动元素            for (int i = 0; i < 4; i++)            {                for (int j = 0; j < 4; j++)                {                    int tb = data[i,j];//取一个元素值                    if (tb == 0)                    {//取得元素值为0表示当前位置为空                        for (int k = j + 1; k < 4; k++)                        {                            int nexttb = data[i,k];//下一个元素值                            if (nexttb != 0)                            {//下一元素值不为0移动,设置移动标志                                data[i,j] = nexttb;                                data[i,k] = 0;                                moveflag = true;                                break;                            }                        }                    }                }            }
View Code

4、判断游戏是否结束,未结束则产生一个随机数

  判断游戏是否结束:有元素为0或者有可合并的元素可继续,否则结束

//产生单个随机数        void GetRandNum()        {            if (IsGameOver()) {                if (MessageBox.Show("失败,是否重新开始?", "GameOver", MessageBoxButtons.YesNo)== DialogResult.Yes)                                {                    InitGame();                }                else return;            }            Random rand=new Random ();            if(moveflag)                SetData(GetRandPos(), rand.NextDouble() < 0.8 ? 2 : 4);            moveflag = false;//重置是否移动标识        }
View Code

5、通过data数据更新界面

//根据data更新td内容,并设置样式        void InitData()        {            for (int i = 0; i < 4; i++)            {                for (int j = 0; j < 4; j++)                {                    var td = btns.Find(m => m.Name == "btn" + (4 * i + j).ToString()); //btns[4 * i + j];                    string tdval = td.Text.Length == 0 ? "0" : td.Text;                    if (data[i, j].ToString() != tdval)                        td.Text = data[i, j] == 0 ? "" : data[i, j].ToString();                    //此处可设置数字样式                }            }            lblscore.Text = totalscore.ToString();        }
View Code

其他方向移动操作依葫芦画瓢,至此,一个简略山寨版2048完成。

需要注意的是Winform版本中要注意键盘上下左右事件方法要重写:

//重写上下左右键响应方法        protected override bool ProcessDialogKey(Keys keyData)        {            switch (keyData)            {                case Keys.Up:                    MoveUp();                    break;                case Keys.Down:                    MoveDown();                    break;                case Keys.Left:                    MoveLeft();                    break;                case Keys.Right:                    MoveRight();                    break;                default:                    break;            }            return base.ProcessDialogKey(keyData);        }
View Code

通过下面的KeyDown事件监控没有效果,本人对winform不熟悉,期待大神解答原因

private void Form1_KeyDown(object sender, KeyEventArgs e)        {            if (e.KeyCode == Keys.Left)                MoveLeft();        }
View Code

 

废话不多说了,代码见附件,另附js版本。

参考文章:http://blog.csdn.net/touchsnow/article/details/22985527