Windows 自带的扫雷是一代经典的游戏,本文介绍如何采用 C# 重写经典的扫雷程序,一起试试吧。
实验目的
- 掌握窗体设计步骤、窗体调用
- 学习Form窗体中控件的灵活使用,能基本理解所学代码的基本含义
- 会使用button、panel、label、textbox、menestrip等按钮,并会使用二维数组的定义与使用二维数组定义雷区,通过enable按钮控制器可使用性
- 能通过Loction、size等控制界面的合理大方
- 能使用imagebox、timer等控件的加入,并能通过属性按钮来完成所需要的结果
- 自学制作过程中不会控件的使用。
实验内容
- 通过一学期所学的C#知识来完成基本的可视化程序设计需求
- 仿Windows系统扫雷,完善扫雷游戏:添加菜单(包含快捷键、热键等)、实现初级、中级、高级及自定义扫雷;添加扫雷英雄榜;实现各方块中标识周边雷数量的文字采用不同颜色的数字显示
程序开发操作步骤
说明:以下共分为4各部分来介绍,分别为:扫雷主界面、自定义窗体、请输入窗体、英雄榜窗体等.
主界面
- 打开Microsoft Visual Studio 2008,选择c#编译环境,创建一个项目,使用Windows窗体应用程序,并命名为“扫雷_xxb”
- 点击Form1,从text属性栏中的Form1改为扫雷,icon属性中加入mine.ico图片。再将Font属性改为新宋体,9pt,加粗。并向其中添加一个timer1控件其属性中的Interval属性改为1000.添加一个imageList1控件,添加图片。
- 界面设计。根据扫雷要求,设计所需界面,(下图不全,详情请看压缩包—附加图片)
- 按照如上设计分别加入menestrip控件,设计好菜单为:游戏(&G):新游戏、初级、中级、高级、自定义…、英雄榜…、退出;帮助(&H):游戏说明、关于扫雷…、关于版权…等。按顺序先把前者属性栏中的ShowShortcutKeys属性设置为True,ShortcutKeys 分别设置为Ctrl+N、Ctrl+L、Ctrl+M、Ctrl+H、Ctrl+D、Ctrl+C、Ctrl+E;后者分别设置为Ctrl+I、Ctrl+F、Ctrl+B。
- 向Form1中拖入一个menuStrip控件,Loction和size属性按上图设计,分别向其中加入1个button控件和2个label控件。设置label控件的Font属性为宋体,12pt,加粗,其中ForeColor设置为Red。并在buttion窗体的text设置为空,Image加入face.bmp图片。
- 再向Form1窗体中拖入一个button控件,其Text属性改为标示出雷,Font属性设置为新宋体,9pt,加粗。其中各个控件的位置是一定的。
- 选中Form1在其属性事件中单击Load,添加如下代码:
private void Form1_Load(object sender, EventArgs e) //Form1_Load,用于基本开始界面的设置
{
string path; //定义字符串,用于存放“扫雷英雄榜.txt”的位置
path = System.Windows.Forms.Application.StartupPath; // bin路径
if (!File.Exists(path + "\\扫雷英雄榜.txt")) //if语句,主要是通过检测是否有扫雷英雄榜.txt,如果没有。。。
File.Create(path + "\\扫雷英雄榜.txt"); //创建扫雷英雄榜.txt
初级ToolStripMenuItem.Checked = true; //使菜单中的初级可用
Load_Mine(); //用于解决开始时单击任意按钮均胜利的问题
GameInit(); //游戏初始化
timer1.Enabled = true; //开启时钟计时
}
- 设置button1按钮:在点击事件下加入如下代码:
private void button1_Click(object sender, EventArgs e) //这是一个开始按钮,单击即开始游戏
{
button1.Image = Image.FromFile("face.bmp"); //用于控制开始按钮的图标,开始时位笑脸
DelAllMines(); //删除所有的雷区控件(很重要,用于不让其改变等级时有参与)
RestMine = MineNum; //用于记录雷数,开始时剩余雷数为总雷数
CostTime = 0; //用于记录从开始到现在游戏用时,开始为0
label1.Text = CostTime.ToString(); //label1窗体中用于显示所用的时间
GamesBegin(); //开始游戏
GameInit(); //游戏初始化
timer1.Enabled = true; //触发计时器
}
- 设置button2按钮:在点击事件下加入如下代码:
private void button2_Click(object sender, EventArgs e) //显示所有的雷数
{
show(); //将地图中所有雷标识出来
}
private void show()//将地图中所有雷标识出来
{
for (int i = 0; i < XNum; i++)
for (int j = 0; j < YNum; j++)
if (Convert.ToInt16(Mines[i, j].Tag) == 1)
{
//==1时,代表这个位置是地雷
Mines[i, j].BackgroundImage = Image.FromFile("mine.bmp");
}
}
private void 新游戏ToolStripMenuItem_Click(object sender, EventArgs e) //新游戏按钮的定义
{
button1.Image = Image.FromFile("face.bmp"); //开始时,让button1按钮的Image设为face.bmp
DelAllMines(); //删除所有的雷区控件(很重要,用于不让其改变等级时有参与)
RestMine = MineNum; //计数剩余的雷数
CostTime = 0; //计数所用时间
label1.Text = CostTime.ToString(); //用于在开始界面显示所用的时间
GamesBegin(); //开始游戏
GameInit();//游戏初始化
timer1.Enabled = true; //触发计时器
}
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e) //定义退出
{
Application.Exit(); //单击退出
}
private void 自定义ToolStripMenuItem_Click(object sender, EventArgs e) //自定义按钮的定义
{
button1.Image = Image.FromFile("face.bmp"); //开始时,让button1按钮的Image设为face.bmp
初级ToolStripMenuItem.Checked = false; //初级按钮不可用
中级ToolStripMenuItem.Checked = false; //中级按钮不可用
高级ToolStripMenuItem.Checked = false; //高级按钮不可用
自定义ToolStripMenuItem.Checked = true; //自定义按钮可用
Form zdy = new Form2(); //通过定义调用新的Form窗体
zdy.ShowDialog(); //显示自定义窗体
if (zdy.DialogResult == DialogResult.OK) //如果在自定义窗体中单击 确定
zdyGames(); //开始自定义游戏
}
private void zdyGames() //自定义游戏
{
DelAllMines(); //删除残余雷片
XNum = zdyXNum; //定义雷区的列数
YNum = zdyYNum; //定义雷区的行数
MineNum = zdyMineNum; //定义总雷数
label1.Text = CostTime.ToString(); //用于在开始界面显示所用的时间
GamesBegin(); //开始游戏
GameInit();//游戏初始化
timer1.Enabled = true; //触发计时器
}
private void 关于扫雷ToolStripMenuItem1_Click(object sender, EventArgs e)
{
MessageBox.Show("游戏简介:\r\n\r\n------------------------------------------\r\n\r\n扫雷是单人计算机游戏,游戏的用户界面十分友好!\r\n\r\n------------------------------------------\r\n\r\n当游戏方格组成的战场构成开始时,计算机将固定的地雷数随机的放到战场的方格。\r\n\r\n------------------------------------------\r\n\r\n此游戏还允许玩家指定雷区中的地雷数,让您尽情玩到底!!\r\n\r\n------------------------------------------\r\n\r\n 据有关调查显示:此游戏具有开发智力少儿的功能!! ", " 说 明:"); //显示游戏简介
}
private void 关于游戏ToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("关于版权:\r\n\r\n本游戏是防Micosoft软件扫雷游戏 由\r\n\r\n 郑州轻工业学院 \r\n 计算机与通信工程学院\r\n 计算机科学与技术10-01班\r\n 谢先斌\r\n\r\n改编用于C#作业使用!特此声明!\r\n\r\n 辅导老师:李灿林\r\n\r\n声明:因版权问题敬请访问个人网站: http://www.xiexianbin.co.co \r\n\r\n 谢谢合作!!\r\n\r\n 如有雷同,纯属巧合", "版权声明:"); //显示游戏版本及版权说明
}
private void 关于扫雷ToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("游戏说明:\r\n\r\n ▲在“游戏”菜单上,单击“开局”;\r\n ▲要启动计时器,请单击游戏区中的任何方块;\r\n\r\n注意:\r\n\r\n ▲ 单击就可以揭开方块,如果揭开的是地雷,您便输掉游戏;\r\n ▲ 如果方块上出现数字,则表示在它周围的八个方块中共有多少颗地雷(0-8)如有都可将用不同的图片标示;\r\n ▲ 要标记您认为可能有地雷的方块,请右键单击它;\r\n ▲ 游戏区包括菜单、雷区、地雷计数器、计时器和开始按钮,请按游戏规则游戏!\r\n ▲本游戏的英雄榜是记录游戏者的成绩使用,因能力有限仅支持初中高级的游戏记录。并设置了重置功能,方便玩家。\r\n\r\n 谢谢您对本游戏的支持 小谢 祝 您游戏愉快!", "游戏说明:"); //游戏的使用说明,简介游戏使用问题
}
private void 扫雷英雄榜ToolStripMenuItem_Click(object sender, EventArgs e)
{
Form herof = new Form3(); //定义新的窗体,通过关联调用
herof.Show(); //显示扫雷英雄棒的窗体
}
private bool IsInMineArea(int row, int col) //判断是否已出雷区
{
return (row >= 0 && row < XNum && col >= 0 && col < YNum); //返回true or false
}
private void button1_Click(object sender, EventArgs e) //这是一个开始按钮,单击即开始游戏
{
button1.Image = Image.FromFile("face.bmp"); //用于控制开始按钮的图标,开始时位笑脸
DelAllMines(); //删除所有的雷区控件(很重要,用于不让其改变等级时有参与)
RestMine = MineNum; //用于记录雷数,开始时剩余雷数为总雷数
CostTime = 0; //用于记录从开始到现在游戏用时,开始为0
label1.Text = CostTime.ToString(); //label1窗体中用于显示所用的时间
GamesBegin(); //开始游戏
GameInit(); //游戏初始化
timer1.Enabled = true; //触发计时器
}
private void DelAllMines() //删除所有的雷区
{
for (int i = 0; i < XNum; i++)
for (int j = 0; j < YNum; j++) //二维数组逐个删除
{
Button n = new Button(); //定义一个新的button
n = (Button)Mines[i,j]; //强制类型转换
this.Controls.Remove(Mines[i, j]); //删除所指雷区
}
}
private void GamesBegin() //用于开始游戏,主要是定义雷区
{
Turn = new int[XNum, YNum]; //定义新的二维数组
Mines = new Button[XNum, YNum]; //定义按钮
for (int x = 0; x < XNum; x++)
for (int y = 0; y < YNum; y++) //通过二维数组,逐个定义初始化button按钮
{
Mines[x, y] = new Button();
this.Controls.Add(Mines[x, y]); //增加新按钮
Mines[x, y].Left = 10 + MineWidth * x; //定义雷区开始在Form窗体中的左边界
Mines[x, y].Top = 65 + MineWidth * y; //定义雷区开始在Form窗体中的上边界
Mines[x, y].Width = MineWidth; //定义雷块的宽度
Mines[x, y].Height = MineWidth; //定义雷块的高度
Mines[x, y].Font = new Font("宋体", 10.5F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(134))); //定义字体
Mines[x, y].BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; //定义backgroundimageLayout
Mines[x, y].Name = "Mines" + (x + y * XNum).ToString(); //定义雷区的名字
Mines[x, y].MouseUp += new MouseEventHandler(bt_MouseUp); //定义单击事件
Mines[x, y].Visible = true; //控制Mines按钮的可见
}
detform();
}
略大量代码。。。
自定义窗体
private void Form2_Load(object sender, EventArgs e)
{
textBox1.Text = "";
textBox2.Text = "";
textBox3.Text = "";
}
通过button1和button2按钮的点击属性添加如下代码:
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text == "" || textBox2.Text == "" || textBox3.Text == "")
{
MessageBox.Show("不要激动!请输入完整!!", "提示", MessageBoxButtons.OK);
return;
}
int h, w, m;
h = Convert.ToInt16(textBox1.Text);
w = Convert.ToInt16(textBox2.Text);
m = Convert.ToInt16(textBox3.Text);
if (m > h * w)
{
MessageBox.Show("雷量太大,请重新输入!", "提示", MessageBoxButtons.OK);
return;
}
if (h < 9 || h > 24 || w < 9 || w > 40 || m < 10 || m > 668)
{
MessageBox.Show("系统错误,请按要求填写!谢谢!!", "提示", MessageBoxButtons.OK);
return;
}
扫雷_xxb.Form1.zdyXNum = w;
扫雷_xxb.Form1.zdyYNum = h;
扫雷_xxb.Form1.zdyMineNum = m;
this.Close();
DialogResult = DialogResult.OK;
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
DialogResult = DialogResult.Cancel;
}
英雄榜窗体
private void Form3_Load(object sender, EventArgs e)
{
string path1, mr1 = "名字\t\t成绩\r\n", mystr1 = "";
path1 = System.Windows.Forms.Application.StartupPath;
FileStream fs1 = File.OpenRead(path1 + "\\扫雷英雄榜.txt");
StreamReader sr1 = new StreamReader(fs1);
fs1.Seek(0, SeekOrigin.Begin);
while (sr1.Peek() > -1)
{
mystr1 += sr1.ReadLine() + "\t\t";
mystr1 += sr1.ReadLine() + "\r\n";
}
sr1.Close();
fs1.Close();
textBox1.Text = mr1 + mystr1;
}
在button1_click事件中添加如下代码:
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
请输入窗体:
- 添加窗体Form4,如图改变Icon属性和text属性,在分别添加一个label控件,一个textbox控件和一个button控件,把label的text改为:江山代有人才出,各领风骚数百年!!,button1的text属性改为确定。并在picturebox属性中添加图片
胜利女神像:
private void button1_Click(object sender, EventArgs e)
{
string path = System.Windows.Forms.Application.StartupPath; // bin路径
string name;
name = textBox1.Text;
if (name == "")
{
this.Close();
return;
}
string mystr = "";//mr = "名字\t\t成绩\r\n",
path = System.Windows.Forms.Application.StartupPath; // bin路径
FileStream fs = File.OpenRead(path + "\\扫雷英雄榜.txt");
StreamReader sr = new StreamReader(fs);
fs.Seek(0, SeekOrigin.Begin);
while (sr.Peek() > -1)
{
mystr += sr.ReadLine() + "\t\t";
mystr += sr.ReadLine();
}
sr.Close();
fs.Close();
mystr += name + "\r\n" + 扫雷_xxb.Form1.CostTime.ToString() + "\r\n";
FileStream fsa = File.OpenWrite(path + "\\扫雷英雄榜.txt");
StreamWriter sw = new StreamWriter(fsa);
sw.WriteLine(mystr);
sw.Close();
fsa.Close();
this.Close();
}
程序运行结果与分析
实验心得
本次在做C#扫雷的过程中使我明白了,只要努力的不断接受新知识才能适应时代的发展,才能掌握更多的知识去迎接新的挑战。
从接到C#作业的那一刻,到现在我成扫雷的完整版的整个过程中自己遇到啦很多的困难,也不止一次的向老师,同学们求助,在此表示感谢!!谢谢他们对我的支持。
在第一次的考虑雷区的重载问题,即队已经定一定二维数组的在此初始化,经过向老师求助,明白只要通过 this.Controls.Remove(Mines[i, j]);,从界面上删掉在初级时加进来的雷方块控件。
当然,在其中还有很多的问题,如怎么调用不同的窗体,怎么在程序的运行过程中改变图片,如何通过Loction、Size、ActiveForm等来控制所需控件在Form窗体中的位置,大小,和控制Form控件的大小。
总之:不经过实践就不知道自己有多少东西不会,自己有多少东西需要继续学习,相信我会继续努力,继续前行,继续在未知中求索。