练手WPF(二)——2048游戏的简易实现(上)
1、创建游戏界面
编辑mainwindow.xaml,修改代码如下:
<window.resources> <style targettype="label"> <setter property="height" value="105" /> <setter property="width" value="105" /> <setter property="horizontalcontentalignment" value="center"/> <setter property="verticalcontentalignment" value="center" /> <setter property="fontweight" value="bold"/> <setter property="opacity" value="0.7" /> </style> <style targettype="rectangle"> <setter property="width" value="105"/> <setter property="height" value="105"/> <setter property="fill" value="#ccc0b2"/> </style> </window.resources> <grid horizontalalignment="left"> <grid.rowdefinitions> <rowdefinition height="100"/> <rowdefinition height="500"/> <rowdefinition height="*"/> </grid.rowdefinitions> <grid.columndefinitions> <columndefinition width="20"/> <columndefinition width="500"/> <columndefinition width="*"/> </grid.columndefinitions> <image grid.row="0" grid.column="1" source="/images/title2048.png"/> <canvas x:name="mycanvas" grid.row="1" grid.column="1" width="495" height="495" background="#b8af9e"/> <stackpanel grid.row="0" grid.column="2" orientation="horizontal" verticalalignment="bottom" horizontalalignment="center"> <button x:name="btnnewgame" content="新的起点" width="80" margin="8" height="30" click="btnnewgame_click" focusable="false" /> <button x:name="btnoldgame" content="旧的征程" width="80" margin="8" height="30" focusable="false"/> </stackpanel> <grid grid.row="1" grid.column="2" margin="10" > <grid.rowdefinitions> <rowdefinition height="0.5*"/> <rowdefinition height="*"/> <rowdefinition height="0.5*"/> <rowdefinition height="*"/> <rowdefinition height="0.5*"/> <rowdefinition height="*"/> <rowdefinition height="*"/> </grid.rowdefinitions> <textblock text="当前得分: " width="210" fontsize="20" verticalalignment="bottom"/> <label x:name="lblcurrscore" grid.row="1" content="2048" width="210" fontsize="40" foreground="maroon" opacity="1" /> <label x:name="lbladdscore" grid.row="1" content="0" width="210" fontsize="20" foreground="chocolate" opacity="0" > <label.rendertransform> <translatetransform x:name="tt" x="0" y="0"/> </label.rendertransform> </label> <textblock text="最高记录: " grid.row="2" width="210" fontsize="20" verticalalignment="bottom"/> <label x:name="lblbastscore" grid.row="3" content="0" width="210" fontsize="35" foreground="darkgray" opacity="1" /> <button x:name="btnshowtopscore" grid.row="4" content="排行榜" width="80" margin="8" height="25" horizontalalignment="right" focusable="false"/> <button x:name="btnexitgame" grid.row="5" content="退出游戏" width="80" margin="8" height="30" horizontalalignment="right" verticalalignment="bottom" focusable="false" click="btnexitgame_click"/> </grid> </grid>
(1)在window资源区分别定义了label和rectangle的样式,因为接下游戏区的4宫格中使用的主要是对lebel控件进行显示显示和移动操作的。
(2)另外还添加一个命名为lbladdscore的lebel控件(其初始透明度为0,即完全透明),用于增加成绩时的动画效果,其中定义了命名为tt的translatetransform变换效果。
(3)游戏主区控件为canvas,命名为mycanvas。
(4)其他可以根据自己的喜好进行调整。
2、定义几个字段变量
毕竟是小游戏,直接从mainwindow.xaml.cs开始下手了。
int lblwidth = 105; // 方块大小 int lblpadding = 15; // 方块间隙 int[,] griddata = null; // 游戏主数据数组 label[,] lblarray = null; // 用于显示成方块的label数组 int currscore = 0; // 当前成绩 bool isstarted = false; // 游戏是否已开始 random rnd = new random(); // 随机数
3、几个开始需要调用的方法
3.1 游戏开始数字板
界面中的16个游戏数字为0时,只显示空的16块小板面,其颜色比背景色稍浅。
/// <summary> /// 显示背景矩形块 /// </summary> private void showbackrect() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { rectangle rect = new rectangle(); rect.setvalue(canvas.leftproperty, (double)((x + 1) * lblpadding + x * lblwidth)); rect.setvalue(canvas.topproperty, (double)((y + 1) * lblpadding + y * lblwidth)); mycanvas.children.add(rect); } } }
3.2 生成新数
游戏开始后,需要随机生成值为2或4的两个新数字。之后,每上、下、左、右移动其中一次界面中的数字后,如果还有空位,又需要随机生成一个2或4的新数字。
/// <summary> /// 重载生成新数 /// </summary> /// <returns></returns> private bool newnum() { int num = rnd.next(0, 9) > 2 ? 2 : 4; int nullnum = 0; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (griddata[y, x] == 0) nullnum++; } } if (nullnum < 1) { return false; } int index = rnd.next(1, nullnum); nullnum = 0; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (griddata[y, x] == 0) { nullnum++; if (nullnum != index) continue; griddata[y, x] = num; } } } return true; }
先统计出界面中剩余空格数,再从空格数中获取随机数作为新数位置,赋值2或4之一。
3.3 设置label板背景色和前景字体大小
根据griddata元素值的高低,显示不同的背景色和字体大小
/// <summary> /// 根据数值生成方块背景色值 /// </summary> /// <param name="num"></param> /// <returns></returns> private brush setbackground(int num) { brush backcolor; switch (num) { case 2: backcolor = new solidcolorbrush(color.fromrgb(0xee, 0xe4, 0xda)); break; case 4: backcolor = new solidcolorbrush(color.fromrgb(0xec, 0xe0, 0xc8)); break; case 8: backcolor = new solidcolorbrush(color.fromrgb(0xf2, 0xb1, 0x79)); break; case 16: backcolor = new solidcolorbrush(color.fromrgb(0xf5, 0x95, 0x63)); break; case 32: backcolor = new solidcolorbrush(color.fromrgb(0xf5, 0x7c, 0x5f)); break; case 64: backcolor = new solidcolorbrush(color.fromrgb(0xf6, 0x5d, 0x3b)); break; case 128: backcolor = new solidcolorbrush(color.fromrgb(0xed, 0xce, 0x71)); break; case 256: backcolor = new solidcolorbrush(color.fromrgb(0xed, 0xcc, 0x61)); break; case 512: backcolor = new solidcolorbrush(color.fromrgb(0xec, 0xc8, 0x50)); break; case 1024: backcolor = new solidcolorbrush(color.fromrgb(0xed, 0xc5, 0x3f)); break; case 2048: backcolor = new solidcolorbrush(color.fromrgb(0xee, 0xc2, 0x2e)); break; case 4096: backcolor = new solidcolorbrush(color.fromrgb(0xef, 0x85, 0x9c)); break; default: backcolor = new solidcolorbrush(color.fromrgb(0xcc, 0xc0, 0xb2)); break; } return backcolor; } /// <summary> /// 根据数值设置方块字体大小 /// </summary> /// <param name="num"></param> /// <returns></returns> private int setfontsize(int num) { int ifontsize; switch (num) { case 2: case 4: case 8: ifontsize = 55; break; case 16: case 32: case 64: ifontsize = 50; break; case 128: case 256: case 512: ifontsize = 40; break; case 1024: case 2048: case 4096: ifontsize = 33; break; default: ifontsize = 30; break; } return ifontsize; }
3.4 显示游戏区的所有label控件
如果griddata元素值不为0的话,生成label控件并添加到游戏板中。
/// <summary> /// 重新显示所有label /// </summary> private void showalllabel() { mycanvas.children.clear(); showbackrect(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (griddata[y, x] != 0) { lblarray[y, x] = new label(); lblarray[y, x].setvalue(canvas.leftproperty, lblpadding * (x + 1) + (double)(x * lblwidth)); lblarray[y, x].setvalue(canvas.topproperty, lblpadding * (y + 1) + (double)(y * lblwidth)); lblarray[y, x].setvalue(label.contentproperty, griddata[y, x].tostring()); lblarray[y, x].setvalue(label.backgroundproperty, setbackground(griddata[y, x])); lblarray[y, x].setvalue(label.fontsizeproperty, (double)setfontsize(griddata[y, x])); mycanvas.children.add(lblarray[y, x]); } } } }
4、初始化游戏数据
/// <summary> /// 初始化数据 /// </summary> private void initdata() { if (griddata != null) // 初始化主数据数组 griddata = null; griddata = new int[4, 4] { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; if (lblarray != null) // 初始化显示用label数组 lblarray = null; lblarray = new label[4, 4]; if (mycanvas.children.count > 0) mycanvas.children.clear(); // 清除界面 newnum(); // 生成两个新数 newnum(); showalllabel(); // 刷新游戏方块 isstarted = true; currscore = 0; // 初始化当前成绩为0 lblcurrscore.content = currscore.tostring();// 更新当前成绩显示 }
将initdata()方法添加到btnnewgame_click按钮事件方法中。
现在运行游戏,不断点击开始新游戏按钮,会在不同位置生成两个2或4的数字,并显示出来。
5、判断游戏是否结束
判断每一行是否存在空位,如果有则未结束。如果该行已满,则看看是否存在相邻是否有相同的数字,如果有则说明可以合并出新空位,即未结束。
列判断方式相同。
/// <summary> /// 游戏是否结束 /// </summary> /// <returns></returns> private bool isgameover() { for (int row = 0; row < 4; row++) { for (int i = 0; i < 4; i++) { if (griddata[row, i] == 0) // 是否有空位 { return false; } } for (int i = 0; i < 3; i++) { if (griddata[row, i] == griddata[row, i + 1]) { return false; } } } for (int col = 0; col < 4; col++) { for (int i = 0; i < 4; i++) { if (griddata[i, col] == 0) { return false; } } for (int i = 0; i < 3; i++) { if (griddata[i, col] == griddata[i + 1, col]) { return false; } } } return true; } /// <summary> /// 显示动画结束对话框 /// </summary> private void showgameover() { messagebox.show("游戏已经结束。", "game over", messageboxbutton.ok, messageboximage.information); isstarted = false; }
上一篇: 和珅最值钱的宝物,皇帝想拿却拿不走
下一篇: JAVA 时间的使用