C#扫雷游戏详细介绍
2014-01-14 11:05
387 查看
可有可无的废话
刚接触一门语言,做一个小游戏,不仅有利于你对这门语言的产生浓厚的兴趣,同时也能摆脱总是记不住的方法,单词。
我刚接触C#也总喜欢找一些源码的小项目来自我研究,但是总会遇到以下问题。
1,一些源码下载过后,莫名其妙在自己电脑无法运行,
2,因为不懂其中的一个知识点,而项目中又多次出现,导致自己无法继续研究下去。
3,别人的注释总是看不懂。
4,别人写了博客,没有放上自己的源码。自己跟着敲,运行的效果总是出不来。
当然这些问题可能你没有遇到过,你也可能很快就能解决。但对于小白们来说,任何一个小问题,都可能是致命的,可能花上几个小时,甚至几天解决也说不定。
废话不多说了,下面直接和大家一起做扫雷这个经典游戏。
游戏两个阶段
我将游戏分为两个层次
扫雷实例下载地址
一共包括两个阶段,和一个双缓冲的小实例。
基本功能实现(没有标旗)2. 图片效果展示
1.1基本功能实现,展示图
1.2 代码展示
1.3代码解析
游戏规则是:第一次点击,是不能踩到雷的,应该随机产生一定数量的雷,雷附近的格子会显示相应数量的地雷数目,玩家根据格子数量分析,排雷。当排出的格子数=总格子数-地雷数,就算玩家胜利。
•DrawMap(),用来画出游戏界面
•public struct Box,表示界面上的每一个格子。
分别有三个属性,IsMineI:是否为地雷;IsShow:是否显示;MineNum;周围地雷的数量
在其他方法中分别设置每个Box中的这三个属性,然后通过DrawMap()方法,就能画出不同的游戏界面了。
其他方法设置Box属性,只有执行DrawMap()方法,才能在窗体界面上显示。
•Clear(),递归实现;当点击的格子周围没有地雷时,游戏自动寻找四周(上,下,左,右,左上,右上,左 下,右下)没有地雷数的格子,然后显示出来。即把这些Box的IsShow设置为true;
•IsSuccess(),判断游戏是否结束,当排出的格子数=总格子数-地雷数,就算玩家胜利(当然还有其他方法去
判断,由自己喜好决定)
•FirstClick(),表示第一次点击扫雷,此处一定不会是雷,然后随机产生不同坐标的地雷数量。
地雷的Box,属性为IsMineI=true;另外两个属性在其他地方设置。
实现图片显示效果(有标旗)
这个实例代码和上面的基本代码区别不大,所以也不用一一分析。源码在上面也给出了连接。
这都是我用美图秀秀亲自弄的,没什么美术功底,可能看起来不协调,先凑合着用。
因为牵扯到了图片,所以我用的是双缓冲(不懂得可以百度下,我也为大家提供了一个小实例,上面的下载连接有)做的,避免画地图时出现闪烁现象。(这个游戏小,闪烁效果不明显)
3、 代码解析
3.1、基础阶段
a.方法有:
DrawMap:画游戏界面
FirstClick:第一次点击,保证不能点到雷,然后随机生成所有地雷的位置。
panGame_MouseClick:鼠标点击事件
Clear:点击到空白处,则清空周围无雷格子
trmTime_Tick:计时器
IsSuccess:判断是否将雷扫完
b. public struct(结构) Box表示游戏界面的每一个格子,
public bool IsMine;//是否为地雷
public bool IsShow;//格子是否显示
public int MineNum;//周围地雷数(1-8)
每一个格子,都有这三个属性。方便操作地雷的状态。
在源码中的注释很多,基本上一看就懂。
3.2、用图片显示地图和地雷
方法与基础方法类似,只是多了个双缓冲。
附上几张图,给大家看看。
过些时间我想做个,局域网的五子棋对战,感兴趣的朋友,可以关注下我哦。
可有可无的废话
刚接触一门语言,做一个小游戏,不仅有利于你对这门语言的产生浓厚的兴趣,同时也能摆脱总是记不住的方法,单词。
我刚接触C#也总喜欢找一些源码的小项目来自我研究,但是总会遇到以下问题。
1,一些源码下载过后,莫名其妙在自己电脑无法运行,
2,因为不懂其中的一个知识点,而项目中又多次出现,导致自己无法继续研究下去。
3,别人的注释总是看不懂。
4,别人写了博客,没有放上自己的源码。自己跟着敲,运行的效果总是出不来。
当然这些问题可能你没有遇到过,你也可能很快就能解决。但对于小白们来说,任何一个小问题,都可能是致命的,可能花上几个小时,甚至几天解决也说不定。
废话不多说了,下面直接和大家一起做扫雷这个经典游戏。
游戏两个阶段
我将游戏分为两个层次
扫雷实例下载地址
一共包括两个阶段,和一个双缓冲的小实例。
基本功能实现(没有标旗)2. 图片效果展示
1.1基本功能实现,展示图
1.2 代码展示
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace MineGame { public partial class FrmMain : Form { Graphics gra; //画板 Brush mine_no; //无雷画刷 Brush mine_default; //初始化界面画刷 Brush mine_color; //地雷画刷 public FrmMain() { InitializeComponent(); gra = panGame.CreateGraphics(); mine_no = Brushes.White; mine_default = Brushes.Gray; mine_color = Brushes.Red; } public struct Box //表示每一个格子 { public bool IsMine;//是否为雷 public bool IsShow;//被点击时,是否显示 public int MineNum;//雷周围8格地雷数 } private Box[,] m_Boxs = new Box[20, 20]; //地图大小 private int mineCount; //炸弹数 private Point mousePoint; //鼠标当前位置 private bool bFirstClick; //是否第一次点击 private bool IsStart; //判断游戏是否开始 private bool IsOver=true; //判断是否踩雷 private int countTime = 0; //开始后计时用 private int ShowCount = 0; //显示的box格子数量 //加载事件 private void FrmMain_Load(object sender, EventArgs e) { bFirstClick = true; //第一次点击 mineCount = int.Parse(txtMineCount.Text); //炸弹的数目 } //panle的paint事件 private void panGame_Paint(object sender, PaintEventArgs e) { DrawMap(); //画地图 } //画游戏界面事件 private void DrawMap() { int showCount2 = 0;//显示格子数量 int i, j; for (i = 0; i < m_Boxs.GetLength(0); i++)//行数 { for (j = 0; j < m_Boxs.GetLength(1); j++)//列数 { if (bFirstClick) { m_Boxs[i, j].MineNum = 0; //初始化格子周围的地雷数 m_Boxs[i, j].IsShow = false; m_Boxs[i, j].IsMine = false; gra.FillRectangle(mine_default, j * 25, i * 25, 24, 24); //初始化游戏界面 } if (m_Boxs[i, j].IsShow) { if (m_Boxs[i, j].IsMine) { gra.FillRectangle(mine_color, i * 25, j * 25, 24, 24);//地雷显示红色 } else { showCount2++; gra.FillRectangle(mine_no, i * 25, j * 25, 24, 24); //无雷区 if (m_Boxs[i, j].MineNum > 0) {//画出周围地雷数量 Rectangle rect = new Rectangle(i * 25, j * 25, 24, 24); StringFormat sf = new StringFormat(); sf.LineAlignment = StringAlignment.Center; sf.Alignment = StringAlignment.Center; Brush[] brushes = new Brush[] { Brushes.Blue, Brushes.DarkCyan, Brushes.Red, Brushes.Fuchsia, Brushes.DarkTurquoise, Brushes.DarkGoldenrod, Brushes.DarkViolet, Brushes.Black }; gra.DrawString(m_Boxs[i, j].MineNum.ToString(), this.Font, brushes[m_Boxs[i, j].MineNum - 1], rect, sf); } } } } ShowCount = showCount2; if (!IsOver && i == m_Boxs.GetLength(0) - 1) MessageBox.Show("踩雷了"); } } //鼠标在panle上的移动事件 private void panGame_MouseMove(object sender, MouseEventArgs e) { mousePoint = e.Location; } //鼠标在pnale上的点击事件 private void panGame_MouseClick(object sender, MouseEventArgs e) { if (!IsStart) return; //游戏没点击开始,则返回 int x = mousePoint.X / 25; int y = mousePoint.Y / 25; if (bFirstClick) { FirstClick(x, y); } if (m_Boxs[x, y].IsMine)//点到雷了 { //显示全地图 for (int i = 0; i < m_Boxs.GetLength(0); i++) { for (int j = 0; j < m_Boxs.GetLength(1); j++) { m_Boxs[i, j].IsShow = true; } } IsStart = false; //游戏结束,鼠标无法继续点击 IsOver = false; //表示踩雷了 trmTime.Stop(); //计时停止 } if (!m_Boxs[x, y].IsShow) { Clear(x,y); } DrawMap(); //判断是否扫完雷 if (IsSuccess() && IsOver) { MessageBox.Show("恭喜你胜利了"); trmTime.Stop(); IsStart = false; return; } } //判断游戏是否结束 private bool IsSuccess() { int count = m_Boxs.GetLength(0) * m_Boxs.GetLength(1); return count - ShowCount == mineCount ? true : false; } //第一次点击事件 private void FirstClick(int x, int y) { bFirstClick = false; //下次不再是第一次点击 #region 给每个格子赋值 #endregion Random ran = new Random(); int count = 0; while (count < mineCount) //随机生成不一样的地雷坐标 { int rx = ran.Next(m_Boxs.GetLength(0)); //列 int ry = ran.Next(m_Boxs.GetLength(1)); //行 if (rx == x && ry == y || m_Boxs[rx, ry].IsMine) continue; m_Boxs[rx, ry].IsMine = true; #region 将雷周围8个格子的数字加1 if (rx - 1 >= 0) m_Boxs[rx - 1, ry].MineNum++; if (ry - 1 >= 0) m_Boxs[rx, ry - 1].MineNum++; if (rx + 1 < m_Boxs.GetLength(0)) m_Boxs[rx + 1, ry].MineNum++; if (ry + 1 < m_Boxs.GetLength(1)) m_Boxs[rx, ry + 1].MineNum++; if (rx - 1 >= 0 && ry - 1 >= 0) m_Boxs[rx - 1, ry - 1].MineNum++; if (rx + 1 < m_Boxs.GetLength(0) && ry - 1 >= 0) m_Boxs[rx + 1, ry - 1].MineNum++; if (rx + 1 < m_Boxs.GetLength(0) && ry + 1 < m_Boxs.GetLength(1)) m_Boxs[rx + 1, ry + 1].MineNum++; if (rx - 1 >= 0 && ry + 1 < m_Boxs.GetLength(1)) m_Boxs[rx - 1, ry + 1].MineNum++; #endregion count++; } Clear(x,y); } //找出无雷区事件 private void Clear(int x, int y) { if (m_Boxs[x, y].IsMine) return; //如果是炸弹,不要显示 if (m_Boxs[x, y].IsShow) return; //如果已经被显示,不需要再显示 m_Boxs[x, y].IsShow = true; //显示此格 if (m_Boxs[x, y].MineNum == 0) //表示周围没有地雷,则自动清除周围的格子 { if (y + 1 < m_Boxs.GetLength(1)) Clear(x, y + 1); //下 if (x + 1 < m_Boxs.GetLength(0)) Clear(x + 1, y); //右 if (y - 1 >= 0) Clear(x, y - 1); //上 if (x - 1 >= 0) Clear(x - 1, y); //左 //斜着的方向 if (x - 1 >= 0 && y - 1 >= 0) Clear(x - 1, y - 1); if (x + 1 < m_Boxs.GetLength(0) && y - 1 >= 0) Clear(x + 1, y - 1); if (x + 1 < m_Boxs.GetLength(0) && y + 1 < m_Boxs.GetLength(1)) Clear(x + 1, y + 1); if (x - 1 >= 0 && y + 1 < m_Boxs.GetLength(1)) Clear(x - 1, y + 1); } } //开始事件 private void btnStart_Click(object sender, EventArgs e) { IsStart = true; //游戏开始,panel可以点击了 trmTime.Start(); } //游戏开始后,计时开始 private void trmTime_Tick(object sender, EventArgs e) { countTime++; if (countTime.ToString().Length == 1) lbTime.Text ="00"+ countTime.ToString(); else if (countTime.ToString().Length == 2) lbTime.Text = "0" + countTime.ToString(); else lbTime.Text = countTime.ToString(); } //重新开始 private void btnReset_Click(object sender, EventArgs e) { bFirstClick = true; //第一次点击 mineCount = int.Parse(txtMineCount.Text) ; //炸弹的数目 IsStart = true; //游戏界面可以点击 IsOver = true; //表示没踩雷 lbTime.Text = "000"; //计时清空 countTime = 0; //计时累加清空 trmTime.Start(); //计时器 打开 DrawMap(); } } }
1.3代码解析
游戏规则是:第一次点击,是不能踩到雷的,应该随机产生一定数量的雷,雷附近的格子会显示相应数量的地雷数目,玩家根据格子数量分析,排雷。当排出的格子数=总格子数-地雷数,就算玩家胜利。
•DrawMap(),用来画出游戏界面
•public struct Box,表示界面上的每一个格子。
分别有三个属性,IsMineI:是否为地雷;IsShow:是否显示;MineNum;周围地雷的数量
在其他方法中分别设置每个Box中的这三个属性,然后通过DrawMap()方法,就能画出不同的游戏界面了。
其他方法设置Box属性,只有执行DrawMap()方法,才能在窗体界面上显示。
•Clear(),递归实现;当点击的格子周围没有地雷时,游戏自动寻找四周(上,下,左,右,左上,右上,左 下,右下)没有地雷数的格子,然后显示出来。即把这些Box的IsShow设置为true;
•IsSuccess(),判断游戏是否结束,当排出的格子数=总格子数-地雷数,就算玩家胜利(当然还有其他方法去
判断,由自己喜好决定)
•FirstClick(),表示第一次点击扫雷,此处一定不会是雷,然后随机产生不同坐标的地雷数量。
地雷的Box,属性为IsMineI=true;另外两个属性在其他地方设置。
实现图片显示效果(有标旗)
这个实例代码和上面的基本代码区别不大,所以也不用一一分析。源码在上面也给出了连接。
这都是我用美图秀秀亲自弄的,没什么美术功底,可能看起来不协调,先凑合着用。
因为牵扯到了图片,所以我用的是双缓冲(不懂得可以百度下,我也为大家提供了一个小实例,上面的下载连接有)做的,避免画地图时出现闪烁现象。(这个游戏小,闪烁效果不明显)
3、 代码解析
3.1、基础阶段
a.方法有:
DrawMap:画游戏界面
FirstClick:第一次点击,保证不能点到雷,然后随机生成所有地雷的位置。
panGame_MouseClick:鼠标点击事件
Clear:点击到空白处,则清空周围无雷格子
trmTime_Tick:计时器
IsSuccess:判断是否将雷扫完
b. public struct(结构) Box表示游戏界面的每一个格子,
public bool IsMine;//是否为地雷
public bool IsShow;//格子是否显示
public int MineNum;//周围地雷数(1-8)
每一个格子,都有这三个属性。方便操作地雷的状态。
在源码中的注释很多,基本上一看就懂。
3.2、用图片显示地图和地雷
方法与基础方法类似,只是多了个双缓冲。
附上几张图,给大家看看。
过些时间我想做个,局域网的五子棋对战,感兴趣的朋友,可以关注下我哦。
相关文章推荐
- C#中的多线程编程原理与实现例子
- C#怎么判断一个Socket是否连接
- C# socket编程原理及实现
- C# 如何关闭,释放Excel进程
- C#设计模式——工厂方法
- C#中的值传递和引用传递详细解析
- c#可空类型的作用说明
- C#项目打开/保存文件夹/指定类型文件,获取路径
- [转]C# 文本框只能输入数字
- C#几种截取字符串的方法小结
- ocx控件的注册
- C#基础知识系列六(静态类和静态类成员)
- c# 用dataset读取xml也很方便
- [C#]將數字前面補0,補足設定的長度
- [C#]將數字前面補0,補足設定的長度
- c# winform登录路由器的方法
- C#非托管内存的应用(一)――基本数据的拷贝
- C# Socket 文件传输
- c# 改键-之魔兽改键(Hook)
- 反编译C#的dll文件并修改,再重新生成dll