2048游戏规则比较简单,玩家通过上、下、左、右四个方向来控制方块的移动,每一次移动,所有的方块都会朝这个方向进行移动,而此时则会在某个随机空的地区产生一个新的数字方块,在移动过程中,若方块上的数字与移动方向后一个的方块上的数字相同,则会碰撞成一个新的方块,数字为两个方块数字之和。若所有地方都被填满方块,且每个方块与相邻方块之间的数字均不相同,则游戏结束。
运行结果:
所需控件:一个button用于重置游戏,两个label来显示分数,一个panel容器来装16个textbox用于显示实时数字。
如出现上图情况,将每个textbox的TabStop属性改为false,也可以用label来代替textbox。
本程序使用W、A、S、D四个键来操作方块的移动。记得将Form1的KeyPreview属性改为true。
首先,定义变量
public class Variables
{
public static int score; //分数
public static int[] Num = new int[16];
public static int[,] TempNum = new int[4, 4]; //移动
public static int[] num = new int[16];
}
本程序是采用一个长度为16的数组来存放每个方块(即每个textbox)的数字。
移动方法:
public void MovingW()
{
for (int i = 0; i < 4; i++)
{
ArrayList arr = new ArrayList();
//将某一列所有不为0的元素的索引找出来
for (int j = 0; j < 4; j++)
{
if (Num[i+j*4] != 0)
{
arr.Add(j);
}
}
if (arr.Count == 1)
{
TempNum[0, i] = Num[i+Convert.ToInt32(arr[0])*4];
TempNum[1, i] = 0;
TempNum[2, i] = 0;
TempNum[3, i] = 0;
}
if (arr.Count == 2)
{
if (Num[Convert.ToInt32(arr[0])*4+i] == Num[Convert.ToInt32(arr[1])*4+i])
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+i] + Num[Convert.ToInt32(arr[1])*4+i];
TempNum[1, i] = 0;
TempNum[2, i] = 0;
TempNum[3, i] = 0;
score += (TempNum[0, i]) / 2;
}
else
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+i];
TempNum[1, i] = Num[Convert.ToInt32(arr[1])*4+i];
TempNum[2, i] = 0;
TempNum[3, i] = 0;
}
}
if (arr.Count == 3)
{
if (Num[Convert.ToInt32(arr[0])*4+i] == Num[Convert.ToInt32(arr[1])*4+i])
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+i] + Num[Convert.ToInt32(arr[1])*4+i];
TempNum[1, i] = Num[Convert.ToInt32(arr[2])*4+ i];
TempNum[2, i] = 0;
TempNum[3, i] = 0;
score += (TempNum[0, i]) / 2;
}
else
{
if (Num[Convert.ToInt32(arr[1])*4+i] == Num[Convert.ToInt32(arr[2])*4+i])
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[1])*4+ i] + Num[Convert.ToInt32(arr[2])*4+ i];
TempNum[2, i] = 0;
TempNum[3, i] = 0;
score += (TempNum[1, i]) / 2;
}
else
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[1])*4+ i];
TempNum[2, i] = Num[Convert.ToInt32(arr[2])*4+ i];
TempNum[3, i] = 0;
}
}
}
if (arr.Count == 4)
{ if (Num[Convert.ToInt32(arr[0])*4+ i] == Num[Convert.ToInt32(arr[1])*4+ i])
{
if (Num[Convert.ToInt32(arr[2])*4+ i] == Num[Convert.ToInt32(arr[3])*4+ i])
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i] + Num[Convert.ToInt32(arr[1])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[2])*4+ i] + Num[Convert.ToInt32(arr[3])*4+ i];
TempNum[2, i] = 0;
TempNum[3, i] = 0;
score += (TempNum[0, i] + TempNum[1, i]) / 2;
}
else
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i] + Num[Convert.ToInt32(arr[1])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[2])*4+ i];
TempNum[2, i] = Num[Convert.ToInt32(arr[3])*4+ i];
TempNum[3, i] = 0;
score += (TempNum[0, i]) / 2;
}
}
else
{
if (Num[Convert.ToInt32(arr[1])*4+ i] == Num[Convert.ToInt32(arr[2])*4+ i])
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[1])*4+ i] + Num[Convert.ToInt32(arr[2])*4+ i];
TempNum[2, i] = Num[Convert.ToInt32(arr[3])*4+ i];
TempNum[3, i] = 0;
score += (TempNum[1, i]) / 2;
}
else
{
if (Num[Convert.ToInt32(arr[2])*4+ i] == Num[Convert.ToInt32(arr[3])*4+ i])
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[1])*4+ i];
TempNum[2, i] = Num[Convert.ToInt32(arr[2])*4+ i] + Num[Convert.ToInt32(arr[3])*4+ i];
TempNum[3, i] = 0;
score += (TempNum[2, i]) / 2;
}
else
{
TempNum[0, i] = Num[Convert.ToInt32(arr[0])*4+ i];
TempNum[1, i] = Num[Convert.ToInt32(arr[1])*4+ i];
TempNum[2, i] = Num[Convert.ToInt32(arr[2])*4+ i];
TempNum[3, i] = Num[Convert.ToInt32(arr[3])*4+ i];
}
}
}
}
}
}
此为向上运动的方法,即W。根据方阵每一列的非0的个数以及相互之间的相等情况来计算移动的结果,只有在有方块进行相加时才有分数产生。其余三个方向与其类似,就不赘述。
判断是否游戏结束
public bool GameOver()
{
bool over1 = false;
//判断格子是否已满
for (int i = 0; i < Num.Length; i++)
{
if (Num[i] == 0)
over1 = true;
}
//判断是否有相邻相同的
//四个角
if (Num[0] == Num[1] || Num[0] == Num[4] || Num[3] == Num[2] || Num[3] == Num[7]
|| Num[12] == Num[8] || Num[12] == Num[13] || Num[15] == Num[14] || Num[15] == Num[11])
over1 = true;
//四条边
int[] lines1 = { 1, 2, 4, 8, 7, 11, 13, 14 };
foreach (int i in lines1)
{
switch (i)
{
case 1:
case 2:
if (Num[i] == Num[i - 1] || Num[i] == Num[i + 1] || Num[i] == Num[i + 4])
over1 = true;
break;
case 4:
case 8:
if (Num[i] == Num[i - 4] || Num[i] == Num[i + 1] || Num[i] == Num[i + 4])
over1 = true;
break;
case 7:
case 11:
if (Num[i] == Num[i - 4] || Num[i] == Num[i - 1] || Num[i] == Num[i + 4])
over1 = true;
break;
case 13:
case 14:
if (Num[i] == Num[i - 1] || Num[i] == Num[i - 4] || Num[i] == Num[i + 1])
over1 = true;
break;
default:
break;
}
}
//中间四块
if (Num[5] == Num[6] || Num[6] == Num[10] || Num[5] == Num[9] || Num[9] == Num[10])
over1 = true;
return over1;
}
游戏结束的规则就是方阵被填满,且没有两个相邻的数字。
首先判断是否方阵被填满,只有Num中有一个数字为0,则游戏继续。
再来判断相邻情况。由于方阵中每个位置的相邻情况都不一样,所以需要分开来讨论。
首先看四个角的相邻情况,每个角均与两个方块相邻。然后是每条边的中间两个均与三个方块相邻。最后是中间四个都与四个方块相邻。只有这些相邻情况中有一个为真,即返回值为true,游戏没有结束。
程序加载时
private void Form1_Load(object sender, EventArgs e)
{
label2.Text = "0";
//随机赋初值
Random r = new Random();
int k = r.Next(0, Num.Length);
Num[k] = 2;
timer1.Start();
MessageBox.Show("开始!");
}
程序加载时,初始化分数为0,并随机在方阵中产生一个数字“2”。计时器是用来将Num数组的值赋给textbox并实时刷新显示。此处可以根据textbox不同值来设定不同的背景色,以便于区分。
private void timer1_Tick(object sender, EventArgs e)
{
#region 数字显示
if (Num[0] != 0)
textBox1.Text = Num[0].ToString();
if (Num[1] != 0)
textBox2.Text = Num[1].ToString();
if (Num[2] != 0)
textBox3.Text = Num[2].ToString();
if (Num[3] != 0)
textBox4.Text = Num[3].ToString();
if (Num[4] != 0)
textBox5.Text = Num[4].ToString();
if (Num[5] != 0)
textBox6.Text = Num[5].ToString();
if (Num[6] != 0)
textBox7.Text = Num[6].ToString();
if (Num[7] != 0)
textBox8.Text = Num[7].ToString();
if (Num[8] != 0)
textBox9.Text = Num[8].ToString();
if (Num[9] != 0)
textBox10.Text = Num[9].ToString();
if (Num[10] != 0)
textBox11.Text = Num[10].ToString();
if (Num[11] != 0)
textBox12.Text = Num[11].ToString();
if (Num[12] != 0)
textBox13.Text = Num[12].ToString();
if (Num[13] != 0)
textBox14.Text = Num[13].ToString();
if (Num[14] != 0)
textBox15.Text = Num[14].ToString();
if (Num[15] != 0)
textBox16.Text = Num[15].ToString();
#endregion
#region 设置字体及颜色
foreach (Control ctr in panel1.Controls)
{
if (ctr is TextBox)
{
ctr.Font = new Font("宋体", 12, ctr.Font.Style);
ctr.ForeColor = Color.Black;
switch (ctr.Text)
{
case "":
ctr.BackColor = Color.White;
break;
case "2":
ctr.BackColor = Color.Blue;
break;
case "4":
ctr.BackColor = Color.Pink;
break;
case "8":
ctr.BackColor = Color.Orange;
break;
case "16":
ctr.BackColor = Color.Gray;
break;
case "32":
ctr.BackColor = Color.Green;
break;
case "64":
ctr.BackColor = Color.Brown;
break;
case "128":
ctr.BackColor = Color.Goldenrod;
break;
case "256":
ctr.BackColor = Color.LightBlue;
break;
case "512":
ctr.BackColor = Color.Violet;
break;
case "1024":
ctr.BackColor = Color.Yellow;
break;
case "2048":
ctr.BackColor = Color.MediumTurquoise;
break;
}
}
}
#endregion
label2.Text = score.ToString();
}
把方阵移动前后进行比较,即Num在Moving方法调用前后进行比较,如果不同则在方阵移动完以后,随机在此时方阵空的,即值为0的地方生成一个2或者4,如果相同则不会生成新的数。
public int[] NewNumber()
{
Random a = new Random();
int i;
ArrayList arr = new ArrayList { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, }; //生成数的范围,2多4少
int[] Select;
Select = ArraylistToInt(arr); //list转int数组
i = GetOneIndex(Num); //在Num中随机得到一个索引即生成的位置
if (i != 99)
Num[i] = GetOneNumber(Select);
return Num;
}
public int GetOneNumber(int[] arr) //在数组中随机获得一个数
{
Random index = new Random();
int i;
if (arr.Length == 1)
i = 0;
else
i = index.Next(0, arr.Length);
return arr[i];
}
public int GetOneIndex(int[] a) //在数组中随机得到一个为0的索引
{
ArrayList arr = new ArrayList();
for (int i = 0; i < a.Length; i++)
{
if (a[i] == 0)
{
arr.Add(i);
}
}
Random r = new Random();
int k;
if (arr.Count == 0)
{ k = 99; }
else
{
if (arr.Count == 1)
k = 0;
else
k = r.Next(0, arr.Count);
}
return (int)arr[k];
}
public int[] ArraylistToInt(ArrayList arr)
{
int[] s = new int[arr.Count];
for (int i = 0; i < arr.Count; i++)
{
s[i] = Convert.ToInt16(arr[i]);
}
return s;
}
//判断运动前后是否相同
for(int i=0;i
每次运动完成之后需要再进一个新的计时器,其中跟上面那个计时器内容差不多,只需要在每次进该计时器时需要将文本框内容清零一下,再进行显示。再加上一个判断游戏是否结束就OK了。
//清空文本框内容
foreach (Control ctrl in panel1.Controls)
{
if (ctrl is TextBox)
{
ctrl.Text = "";
}
}
//
//跟timer1中的显示和颜色字体设置一样
//
//判断游戏是否结束
if (quiit== false)
{
quiit = true;
MessageBox.Show("gameover", "失败");
}