C# 扫雷程序设计

发布时间: 更新时间: 总字数:5751 阅读时间:12m 作者: IP上海 分享 网址

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();
}

略大量代码。。。

自定义窗体

  • 通过单击项目,添加Windows窗体,添加一个Windows窗体,命名为Form2(可能程序中有点问题,因为我改过的),把其text属性改为:自定义. . .,并在icon中添加图片。

  • 添加一个groupbox窗体,把其text属性改为:请自定义难度. . .,在其中添加3个label控件和3个textbox控件,按如图所示布局,再添加2个button按钮,分别把其属性改为:确定、取消。

  • 在Form1的Load属性中添加如下代码:

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;
}

英雄榜窗体

  • 同上添加Form3窗体,改变其中的Image和text属性,设计好其大小:

  • 在From3中添加label,textbox,button按钮各一个。在Form3的Load的事件中添加如下代码:

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属性中添加图片

胜利女神像:

  • 在button1_Click事件下添加如下代码:
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控件的大小。

总之:不经过实践就不知道自己有多少东西不会,自己有多少东西需要继续学习,相信我会继续努力,继续前行,继续在未知中求索。

参考

  1. 源码-github
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数