前言

这里给出教程原文地址

该项目已经放在github上托管。

绘制雷区

这一节我们主要涉及界面中雷区的绘制。绘制雷区需要三个变量来保存雷区行数、列数、以及地雷的数量。而且我们希望能够自动获取上次游戏的设置(初级,中级,高级,雷区的三个变量值不同)。因此这三个变量的值需要保存下来。我们在这里采用Setting文件来保存这些数据。工程创建的时候,系统会自动生成一个Setting文件。因此我们不需要自己创建,只需要使用原有的Setting文件即可。在右方解决方案资源管理器面板中展开Properties,右击Settings.settings,选择打开即可。

按照下图对它进行设置,设置完成后按Ctrl + S进行保存。

我们需要一个paint事件来进行绘制雷区,选中主窗口,在左边的属性面板中,单击事件按钮,并找到Paint事件,双击该条目,系统会自动创建一个事件,我们将在这里绘制雷区。如下图所示:

绘制雷区时我们需要考虑以下几点:

  • 我们需要定义三个基本变量行数、列数、地雷的数量,并初始化。
  • 我们需要一个二重的循环来绘制雷区,我们假定雷区为32×32的小方块,并且四周有一圈宽度为1的留白,用于与其它雷区区别,这样,每个雷区的实际大小为34×34。
  • 整个雷区距离上下左右边缘都应该有个间距,所以需要一个偏移量。
  • 我们需要Form窗口自动调整大小,来适应这个雷区的绘制。
private int Sweep_width;      //雷区中的列数
private int Sweep_high; //雷区中的行数
private int Sweep_num; //雷区中的地雷数量
private int nOffsetX; //雷区绘制时的偏移量,距离窗口左边缘的距离
private int nOffsetY; //雷区绘制时的偏移量,距离窗口上边缘的距离 public Form_Main()
{
//初始化操作
InitializeComponent();
nOffsetX = 6; //初始化偏移量
nOffsetY = 6 + UpMenu.Height; //初始化偏移量,UpMenu是菜单栏控件
Sweep_num = Properties.Settings.Default.Sweep_num; //初始化,从Settings读取地雷数量
Sweep_high = Properties.Settings.Default.Sweep_high; //初始化,从Settings读取行数
Sweep_width = Properties.Settings.Default.Sweep_width; //初始化,从Settings读取列数
UpdateSize(Sweep_width,Sweep_high); //自适应窗口大小
}
private void Form_Main_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics; //绘制句柄
for (int i = 0; i < Sweep_width; i++)
{
for (int j = 0; j < Sweep_high; j++)
{
g.FillRectangle(Brushes.Violet, new Rectangle(nOffsetX + 34 * i, nOffsetY + 34 * j + 1, 32, 32)); //绘制每一个小方块
}
}
}
private void UpdateSize(int width_temp, int high_temp)
{
//根据雷区行数,列数,来设置整个Form窗口的大小
int width_update = width_temp * 34 + 12;
int high_update = high_temp * 34 + 12;
Width = width_update + (this.Size.Width - this.ClientSize.Width);
Height = high_update + UpMenu.Height + TableLayoutPanel_Main.Height + (this.Size.Height - this.ClientSize.Height);
}

最后按Ctrl + F5编译运行,得到最终结果:

下面我们为了使鼠标移动到雷区上时,能有高亮的效果做一些修改。首先我们需要能找到鼠标当前所在的位置,因此我们需要MouseMove事件,找到MouseMove事件,双击该条目:

我们需要定义新的变量Point来方便我们标记鼠标的位置,鼠标的每次移动并不是都要重新刷新界面,当鼠标从某个32x32的小雷区移动到另一个32x32的小雷区时,我们就需要更改高亮的位置。我们需要采集的是当前鼠标处于哪一个32x32的小雷区,代码如下:

应增加变量:

 private Point mousefocus_new; //鼠标新位置
private Point mousefocus_old; //鼠标旧位置

应对这两个变量初始化,在public Form_Sweeper(){ }中增加如下代码:

mousefocus_new.X = mousefocus_old.X = 0;            //初始化鼠标位置
mousefocus_new.Y = mousefocus_old.Y = 0;

记录鼠标位置,其中变量mousefocus_new是此刻位置、moursefocus_old是上一时刻位置,两者进行对比,来判断当前鼠标处于的32x32的小雷区是否发生改变。代码如下:

private void Form_Main_MouseMove(object sender, MouseEventArgs e)
{
//x,y相当于雷区二维数组中的第几行,第几列。
int x = (e.X - nOffsetX) / 34 + 1;
int y = (e.Y - nOffsetY) / 34 + 1;
mousefocus_new.X = x;
mousefocus_new.Y = y;
if (e.X < nOffsetX || e.Y < nOffsetY)
{
//鼠标位置不在雷区时
mousefocus_new.X = mousefocus_new.Y = -1;
Refresh();
}
else if (mousefocus_new != mousefocus_old)
{
mousefocus_old = mousefocus_new;
Refresh();
}
}

Paint事件应做修改,代码如下:

for (int i = 0; i < Sweep_width; i++)
{
for (int j = 0; j < Sweep_high; j++)
{
if (i + 1 == mousefocus_new.X && j + 1 == mousefocus_new.Y)
{
g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Violet)), new Rectangle(nOffsetX + 34 * i, nOffsetY + 34 * j + 1, 32, 32)); //产生高亮
}
else
{
g.FillRectangle(Brushes.Violet, new Rectangle(nOffsetX + 34 * i, nOffsetY + 34 * j + 1, 32, 32));
}
}
}

此时,按Ctrl + F5编译运行,发现屏幕会闪屏,在初始化模块增加如下代码:

this.DoubleBuffered = true;                         //双缓冲技术,减少屏幕闪屏

最后按Ctrl + F5编译运行,得到最终结果:

扫雷游戏制作过程(C#描述):第三节、雷区绘制的更多相关文章

  1. 扫雷游戏制作过程(C#描述):第二节、界面设计

    前言 这里给出教程原文地址. 该项目已经放在github上托管. 扫雷界面设计 界面的设计,首先需要创建一个菜单栏.具体方法在左边找到工具箱窗口,展开其中的菜单和工具栏,找到MenuStrip选项,双 ...

  2. 扫雷游戏制作过程(C#描述):第五节、菜单操作(续)

    前言 这里给出教程原文地址. 该项目已经放在github上托管. 发布版已经分享到百度网盘 菜单操作(续) 接着节前一章节的内容,我们继续完善菜单栏的功能. 我们首先,先完善Rank的选项,我们希望我 ...

  3. 扫雷游戏制作过程(C#描述):第四节、菜单操作

    前言 这里给出教程原文地址. 该项目已经放在github上托管. 菜单操作 我们现在的程序单击菜单的时候不会有任何反应,这一节我们主要介绍菜单的相关代码,使得菜单能够正常使用. 现在我们希望在对应级别 ...

  4. 扫雷游戏制作过程(C#描述):第一节、创建项目

    前言 起初做扫雷是同学在做,我也跟着做了.做的比较low,其实第一次做这种东西,自己对自己的要求也不高,注重在了解一下,一个app应用程序是怎么产生的..net开发平台,用c#敲的.建议大家一些不懂的 ...

  5. Unity3D_(游戏)2D简单游戏制作过程:捕获高空掉落保龄球

      游戏介绍:通过鼠标的左右移动,可以控制帽子的移动,当帽子接到下落的保龄球时,会出现火花效果.没有接到保龄球时,保龄球落到草地上,过10S后会自动消失. 实现效果: 素材+Unity3D源代码:传送 ...

  6. [NOIP2015 普及组] 扫雷游戏

    [NOIP2015 普及组] 扫雷游戏 难度:入门 题目描述 扫雷游戏是一款十分经典的单机小游戏.在nn行mm列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格).玩家翻开 ...

  7. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  8. 洛谷 P2670 扫雷游戏==Codevs 5129 扫雷游戏

    题目描述 扫雷游戏是一款十分经典的单机小游戏.在n行m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格).玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有 ...

  9. 关于Cocos2d-x开发一个游戏的过程自述

    我在2016年12月6号完成了我的第一个自己独立完成的游戏,期间遇到各种各样的问题和困难,但是幸运的是问题都一一被解决了,现在我想总结一个整个的制作游戏的过程 使用的环境是VS2013+cocos2d ...

随机推荐

  1. Linux 粘着位(sticky bit)

    当设置粘着位时只有root或者owner才能删除.重命名文件. 示例: 用户apple默认组为fruit. [root@titan ~]# id apple uid=1001(apple) gid=1 ...

  2. python之禅 the zen of python

    >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is ...

  3. Java微信公众平台开发之扫码支付模式二

    官方文档点击查看 准备工作:已通过微信认证的公众号,域名可以不通过ICP备案借鉴了很多大神的文章,在此先谢过了大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款模式二支付的流程 ...

  4. Jmeter==HTTP信息头管理器的作用

    HTTP信息头管理器在Jmeter的使用过程中起着很重要的作用,通常我们在通过Jmeter向服务器发送http请求(get或者post)的时候,往往后端需要一些验证信息,比如说web服务器需要带过去c ...

  5. Oracle impdp通过network_link不落地方式导入数据

    --Oracle impdp通过network_link不落地方式导入数据 -----------------------------------------------------2014/01/1 ...

  6. iostat磁盘IO命令详解

    Linux IO 实时监控iostat命令详解 简介: 对于I/O-bond类型的进程,我们经常用iostat工具查看进程IO请求下发的数量.系统处理IO请求的耗时,进而分析进程与操作系统的交互过程中 ...

  7. C# foreach循环较for循环的优势与劣势

    一.foreach循环的优势 C#支持foreach关键字,foreach在处理集合和数组相对于for存在以下几个优势: 1.foreach语句简洁 2.效率比for要高(C#是强类型检查,for循环 ...

  8. js中的访问器属性中的getter和setter函数实现数据双向绑定

    嗯,之前在读js红宝书的时候,在对象那一章有介绍属性类型.第一种数据类型指的是数据属性,第二种是访问器属性.在初识vue的时候,其双向数据绑定也是基于访问器属性中的getter和setter函数原理来 ...

  9. 关于tomcat的Unsupported major.minor version 51.0问题记录

    今天在构建一个应用时使用了注解的方式,可能是别的原因,正常访问一个servlet的时候报了一个从来没见过的错误. 2017-5-12 15:54:52 org.apache.catalina.core ...

  10. Servlet知识点

    如果请求采用Get方式,则重写doGet()方法,如果请求采用Post方式,则重写doPost()方法. 下面是重写doGet()方法的servlet例子. servlet继承如下类: 整体结构: 在 ...