当前位置: 首页 > news >正文

扫雷游戏制作过程(C#描述):第三节、雷区绘制

前言

这里给出教程原文地址
该项目已经放在github上托管。

绘制雷区

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

按照下图对它进行设置,设置完成后按Ctrl + S进行保存。
1219808-20170828123509874-1896017653.png

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

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

  • 我们需要定义三个基本变量行数、列数、地雷的数量,并初始化。
  • 我们需要一个二重的循环来绘制雷区,我们假定雷区为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编译运行,得到最终结果:
1219808-20170828123541171-354804741.png

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

我们需要定义新的变量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编译运行,得到最终结果:
1219808-20170828123616546-1818950554.png

转载于:https://www.cnblogs.com/pengpeng123/p/7443270.html

相关文章:

  • 使用SQL中的ROW_NUMBER()和while循环对每一行执行操作
  • 关于FPGA随笔
  • 取得所有DB的名称, 形成一行, 并以逗号分隔
  • windows下安装JDK1.8和eclipse
  • LightOJ 1414 February 29(闰年统计+容斥原理)
  • C++ 日志类库 log4cplus
  • Spark Mllib里如何将trainDara训练数据的分类特征字段转换为数值字段(图文详解)...
  • 给Eclipse安装eUML2插件以及可能出现的依赖错误解决方案
  • junit import org.junit.Test 报错
  • SQL Server2005与SQLServer2008并存时, 怎样连接到2008
  • 微信小程序开发之带搜索记录的搜索框
  • 怎样启用sa用户登录
  • (接口自动化)Python3操作MySQL数据库
  • 自动在多个DB上执行同一条sql语句 ( 存储过程版 )
  • 判断是否是子串
  • Google 是如何开发 Web 框架的
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • download使用浅析
  • laravel 用artisan创建自己的模板
  • MySQL主从复制读写分离及奇怪的问题
  • Python中eval与exec的使用及区别
  • SQLServer之索引简介
  • Swoft 源码剖析 - 代码自动更新机制
  • Vue.js-Day01
  • 初识MongoDB分片
  • 仿天猫超市收藏抛物线动画工具库
  • 复杂数据处理
  • 好的网址,关于.net 4.0 ,vs 2010
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 微信小程序填坑清单
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 正则学习笔记
  • Spring第一个helloWorld
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​ssh免密码登录设置及问题总结
  • # Java NIO(一)FileChannel
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #Java第九次作业--输入输出流和文件操作
  • #pragma预处理命令
  • #微信小程序:微信小程序常见的配置传值
  • (14)Hive调优——合并小文件
  • (二)构建dubbo分布式平台-平台功能导图
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Core 中的路径问题
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .net访问oracle数据库性能问题
  • .NET下的多线程编程—1-线程机制概述
  • .NET与 java通用的3DES加密解密方法
  • .sh
  • ?php echo ?,?php echo Hello world!;?