先看看《扫雷》 的思维导图,再看动画演示。

部分功能的动画演示,下面有更全的。

本文为《C#扫雷游戏开发实战》系列文章第三

1、C#,扫雷游戏(Minesweeper)之壹——作弊手段大曝光

2、C#,扫雷游戏(Minesweeper)之贰——世界排名的规则知识

3、C#,扫雷游戏(Minesweeper)之叁——扫雷软件的需求分析与软件设计

4、C#,扫雷游戏(Minesweeper)之肆——扫雷软件的核心代码

5、C#,扫雷游戏(Minesweeper)之伍——扫雷软件的改进与实践

下载《扫雷》:百度网盘 提取码:g4y7http://xn--https-bl8js66z7n7i//pan.baidu.com/s/1Kg54GDCuXP3wIQMQbNrgyA?pwd=g4y7

这是一篇关于《扫雷》游戏的近技术文章。

一、《扫雷》游戏的需求

因为家人年纪大、视力差、保守与恋旧、不喜欢(通过微软商店才能下载安装的)新版本的微软《扫雷》,也无法适应竞技版本的《扫雷》。牢子 平时狂傲惯了,便被下了战书,要求编一个特制的《扫雷》游戏,只好硬着头皮边学边干。

期间遇到了一些小小的问题,发布出来与大家分享与交流。

吾乃一介超级懒虫,接到任务后,想来这么简单的事,一定有人干得不错了。先bing再bai后goo,看看哪位大咖的代码能用,直接改改就得以交差了。

当然,如果这么简单,就无需写本文了。搜索后,惊奇而失望地发现:

  1. 很久很久以前,曾经少量玩过《扫雷》,规则稍微看了一下,瞎按一通,好像从来未过关。反正不提神,不如啃数学书有意思,就再没碰过。今天才发现《扫雷》游戏居然已经火了30年了,依然经久不衰,真是一个奇迹!
  2. 特意写了个爬虫,满宇宙地爬。爬到的《扫雷》代码,java/C/C++/HTML5+js/php/python/C#/...,很多很多,粗粗地都看了一遍,可惜都太烂了,完全不叫编程。
  3. 竞技型《扫雷》软件不好写;微软的《MineSweeper》就因为“被”作弊手段太多而被踢出了竞技赛场;
  4. 任何功能要做到极致,均非易事。记得,曾经为了写两个数的加法,累计起来达到5000多行代码,想起来那是癫而不是狂。何苦来斋?

《扫雷》软件具体来看都有什么需求呢?与家人、邻居与热衷于游戏的邻居孩子聊聊之后,稀稀拉拉记录下来,五花八门。包括但不限于下面这些:

(01)严格遵守微软制定的《扫雷》规则;

(02)设计风格要严格遵守经典版本(指的是 Windows 3.1);

(03)第一挖,不要触雷哈;这个新版本才有哈。

(04)能随意放大、缩小窗口;满足视力差的需求;

(05)时间精确到毫秒;邻居孩子的竞技练习需求;

(06)记录所有玩的过程并用图表显示,查看进步?退步?

(07)纯绿色软件,一个exe文件解决所有问题;发给好朋友省事;
(08)有点音效,比如爆炸,但不要太多,别太吵;

(09)字体好看一点;这个可以有!

(10)如果干得凑合,以后还要六边形的、异型的挖雷游戏;去去去!

(11)邻居是挖雷的好手,提出来说不能“被”作弊!天哪,这个难哪。

(13)不吉利,跳过;

(14)。。。

二、《扫雷》游戏的需求分析

1、《扫雷》的规则

网上爬了大量的《扫雷》的规则,想抄一份。可惜没有一个说透的,只好自己写:

游戏主旨:游戏区分布着大量的格子,其中的一些格子随机埋设了地雷,玩家(使用鼠标左键)点击格子扫描(挖),查看是否有地雷,成功扫(挖)开“除了有地雷之外的所有格子”即为胜利。

扫描地雷:玩家(使用鼠标左键)点击格子挖开:a如果没有地雷,则格子变成平地。b如果遇到地雷,则直接爆炸牺牲(GAME OVER)。c如果不是地雷,而周边有地雷,显示数字。d挖开格子的同时,系统可以自动挖开周边连续的、可能很多的空格子(很爽!)。

地雷信息:挖开的格子,如果有数字显示,则该数字即是周边3x3区域8个(边上的少)格子内的地雷数。其他异型《扫雷》,原理一样,统计与显示的数字不同。

地雷标记:依据格子及已知地雷的分布,认定有地雷的格子,可以使用鼠标右键单击,a做个标志(插上小旗子)。b再次点击转为怀疑。c再次点击取消。

表示怀疑:如果某个未挖开的格子,怀疑其可能是地雷,a可以鼠标右键双击(或两次鼠标右键单击)做出问号(?)标记。b再次点击可以取消。

自动挖开:如果“某个格子显示的数字 = 已经标记的周边地雷数”,鼠标左右键双击(或左键双击)可以自动打开周边相关的格子。自动挖开是算法问题。

2、《扫雷》游戏主界面

游戏主界面分为三个区域。

2.1 菜单区

本文的《扫雷》有三列菜单。第一列包括:开始新游戏;初级;中级;高级;记录与退出等等;第二列是趣味扫雷,有各种地图为底图的异型《扫雷》;第三列是帮助与关于。

Visual Studio + C# 搭界面的效率、开发的效率都无与伦比,省下很多时间可专注于算法与数据,并用于其他部分的编程。真佩服30年前的程序员,调细节是多么辛苦!

2.2 信息区

信息区左侧为显示未挖开的地雷数(不一定是真的哈!玩家认为的);中间是表情显示;右侧是时间显示。表情显示区可以点击,等于重开游戏。

2.3 游戏区

游戏区一般都是矩形的。

如果格子(地砖,地板,地块,以下称格子Grid)是异型的,比如六边形的,那么主界面可以是其他形状;不过,即使是方形(或长方形)格子,游戏区也可以是任意形状的哈。比如,东东市地图、米国地图、袋鼠国地图等等。开始用湾湾岛地图的,后来想都是一家人呢,再不听话也是兄弟姐妹。

3、需求总结

需求不少,用编程语言总结一下,主要是:

  1. 游戏区的设计:满足矩形与非矩形的部署;
  2. 布雷:满足各难度系数(按密度系数换算)的地雷布设;
  3. 规则:鼠标事件的处理,满足规则要求;
  4. 显示:格子各种状态;周边地雷的统计;地雷数、时间LED显示;表情;
  5. 自动挖雷:无向图的深度优先遍历算法(DFS for Graph);
  6. 防作弊手段:含扫雷过程细节的记录与加密存储;伪视频;
  7. 游戏历史记录、统计与图示。

三、《扫雷》游戏的界面设计

1、菜单区

菜单区没什么可说的。

2、信息区

需要但没用的资源。

2.1字体问题

2.1.1 字体显示问题

信息区的字体,比较特殊,属于LED字体;而且有背景字  RGB(128,0,0)。

(1)简单方法:用 Label 控件,设置  LED字体,显示地雷 与 时间。

(2)原始方法:使用事先保存的 字图片(0--9),显示于 PictureBox 控件;需要分别计算每个数字的位置等等,大小不可(不方便)调整;

(3)较好办法:使用 LED 字体;并绘制 DrawString于 PictureBox 控件;支持暗红色背景字及大小调整(照样清晰);

2.1.2 字体文件问题

LED字体文件一般都随着软件发布,这不符合 纯绿色软件 的要求。

前面说了,要求一个 exe 文件解决所有问题,不要另外的文件。当然也不能用远程下载的方式。

一般可以用资源的方式。本文的做法更极端,甚至不用资源,避免被再次利用!

实现的方法:将二进制的 TTF 文件,转为base64字符串,再转为 .cs 代码文件,嵌入工程。运行的时候,再反转为 byte 数组,通过  AddMemoryFont 方法直接加载内存字体,极快又省事。

坑(Mud puddle):最早想省事,直接加载内存字体 AddMemoryFont,用于 Label 显示。但在用于 Label 控件的时候就不稳定了,按要求设置 Label 的 UseCompatibleTextRendering 为 true,也经常报内存修改的错误!后来改为 PictureBox 显示,就没有问题了。

2.2时间显示

2.2.1 时间格式问题

参与竞技的孩子们要求显示到毫秒。因而时间显示是秒+毫秒的格式。其中秒不能超过1000,需要取余数,以免显示超过界限。

软件允许玩家选择时间显示格式。

2.2.2 时钟周期问题

这是微软 Minesweeper 早期的一个 bug。MInesweeper是按计时器 Timer ,而 Timer 都是在一个周期(Interval)后在进入程序节点。正确的话,需要扣除 Timer Interval 的第一个时钟周期。

本文不用这个办法,直接记录第一次点击的时间。

2.3地雷显示

左端的地雷显示区,显然不能显示真实的剩余地雷数。有一些代码直接显示真实的剩余地雷数,这不是作弊吗?应该显示“玩家认为的剩余的地雷数,也就是实际地雷总数,扣除已经标记的地雷数(可能标错哈)。

2.4表情显示

表情显示区有两个功能:

(1)反馈玩家的操作;

(2)点击重新开始新游戏;

表情有四个:

  1. 笑脸;一般场合;
  2. 哭脸;挖错了;失败;
  3. 惊讶,张嘴;左右双击自动挖雷;
  4. 得意,带墨镜,成功!

表情显示可以用两种方式。一是用预先存好的图片;二是直接画。

因为要适应随意放大缩小的需求,本文选择第二种。

画法:

笑脸:两个小圆+一段圆弧;

哭脸:两个交叉线+一段圆弧;

惊讶:两个稍微大一点的圆+一个椭圆;

得意:两个稍微大的椭圆+一段圆弧+三条直线(眼睛架);

3、格子

格子,也称为地砖、地块、地,组成了游戏界面。

3.1 格子的形状

格子的形状一般都是正方形的。

异型的《扫雷》支持六边形、三角形及其他可无限重复拼接的结合形状。

玩过之后发现,正方形 与 六边形 比较有意思一些。

3.2 格子的状态

格子的状态与显示效果有:

一般的扫雷代码都使用事先保存的图片,这不适合可以任意放大缩小的需求。

本文的做法是按不同的状态,设计不同的绘制方法。包括格子区绘制、台阶绘制、旗帜绘制、地雷绘制、错误(叉)绘制及爆炸(流血)格子的绘制等等。

3.3 格子的数字

3.3.1 字体问题

格子的数字可以用两种方式显示。

一是用实现保存的图片。二是用TrueTypeFont(TTF)字体。

因为要满足可以随意放大缩小的需求,用图片显然不行了。

尝试了很多种字体,请家人一一过目,最终发现选择 Arial Black 比较好。

字体的大小 fontHeight = GridHeight * 0.5 看起来比较舒服。经典版本的字体稍微有些大了。

3.3.2 数据问题

格子里面的数字是统计周围格子地雷数得到。

一般的代码通过统计二维数字中当前格子周边 3x3区块的地雷数得到。这个只能用于矩形的游戏区与正方形的格子。

本文的代码中,游戏区保存的是格子之间的邻接矩阵,因而可以支持任意形状的格子与任意分布的游戏区。

计算地雷的高级算法:

无向图的单步深度优先遍历算法(One-step DFS Algorithm for un-direction graph)

单步深度优先遍历?没听说过?

当然。别当真啊,逗着玩呢,只需要循环即可得到,不需要什么算法!

4、鼠标事件

4.1 鼠标事件分析

如果用键盘《扫雷》,一定会失去兴趣与乐趣。

搜索历史文件,发现《扫雷》可能大大促进了小老鼠的改良。

鼠标事件及其逻辑看下图比较清楚,不再赘述。

4.2 鼠标事件的问题

鼠标事件的处理有一些细节,也是一些坑。

4.2.1 双击的时间问题

先问一个问题:鼠标键两次点击之间“间隔多少时间”算“双击”?

解决之道:通过 Windows API 获取系统设置的鼠标双击时间间隔。

仅仅用这个时间是不够的,需要按玩家的操作过程之统计数据进行适当的智能修正。

高龄玩家点击速度慢,间隔时间要长一点。

竞技选手手速快,间隔时间要短很多。

4.2.2 左右键双击的问题

Visual Studio C# 开发库只提供了 MouseDown 与 MouseUp 的事件,怎么判别“左右键双击”?

这里要用到 堆栈Stack(列表List也可以),因为还有更全面的考虑,使用堆栈是比较理想的。实现方法:MouseDown时,Push压栈;MouseUp 时,Pop出栈,因而只有在 LeftStack 与 RightStack 之 Count 均 >0 的情况,才是左右键双击。

总体上需要考虑与跟踪 MouseDown,MouseUp,MouseLeave,MouseMove 的所有情况。

5、游戏区的要点

5.1 级别设置

扫雷的级别设置,有两个关键数字:网格大小 和 密度系数。

5.1.1 网格大小

网格的大小是指格子的数量。

竞技扫雷的网格是8x8,9x9,16x16,16x30,24x30。

一般的《Minesweeper》软件也支持用户自定义。个人觉得用户自定义没有什么意义。

异型《扫雷》的网格大小评价方式不同。

5.1.2 密度系数

扫雷的级别设置关键参数是密度系数 Density。

密度系数 = 地雷数 / 格子数 %

一般的设置是:

8x8,8个雷,密度系数:12.50%;

9x9,10个雷,密度系数:12.35%;

16x16,40个雷,密度系数:15.63%;

16x30,99个雷,密度系数:20.62%;

24x30,164个雷,密度系数:22.78%。

密度系数越高,难度越高。

密度系数高,意味着地雷多,空隙少!

空隙少,是最致命的难度。

5.2绘制方法

游戏区的格子,可以设计为独立的Text, Button, Panel, PictureBox 等等。

但测试后,发现效率最高、效果最好的应该是整体的 PictureBox。

5.3闪烁问题

设置

this.DoubleBuffered = true;

即可,省事。

6 音效问题

音效的要求是:

  1. 效果要好,不能断断续续的;
  2. 纯绿色软件,不能从外部加载音效文件;

本文代码只保留了爆炸的音效。

一开始试了 MP3 的文件及播放器,发现有时滞。

遂将 MP3 转为 WAV 。

为了符合 纯绿色软件 的要求,不从文件加载。先将 WAV 文件,压缩,byte[] 转为 base64 字符串,拆分到 cs 文件。并入 project,后续再解压,base64,并反转 byte 成为 stream ,进入时被一次加载。后面播放的时候,只需要 play 即可。

7 数据统计

数据统计及图表是低档的东西,上不了台面,不提了。

写这部分代码最鼓噪乏味。

三、《扫雷》游戏的数据设计

数据结构的设计最能体现程序员的层次,网上所有的《扫雷》游戏代码之数据设计都一塌糊涂,完全不是编程的思路与感觉。

1、格子数据

格子需要保存的数据有:

  1. 编码Id;
  2. 形状编码;默认为矩形,可以支持六边形、三角形等等;
  3. 位置x,y:相对于游戏区左上角的相对位置;
  4. 尺寸Width,Height及其他;
  5. 行Row,列Column编号:适用于矩形游戏区的数据;
  6. 是否为地雷格子IsMine?
  7. 存储周边地雷数Surrounding Mines;

2、游戏区数据

游戏区存储的核心数据是格子数据。

网络代码几乎无一例外都是按 二维数组 Bricks[,] 设计的。

而,划重点了!格子之间的关系是“图Graph”,因而游戏区的数据必须是按图数据设计的。

3、游戏区数据

(1)游戏区Id;

(2)形状编码;默认为矩形,可以支持六边形、三角形等等;

(3)行数Row,列数Column编:适用于矩形游戏区的数据;

(4)形状参数Size;

(5)格子之间的关系数据:邻接矩阵 Adjacency;

(6)地雷总数;

评判标准:未用邻接矩阵的代码基本上是30年前的水平。

自动挖开算法的深度优先遍历(DFS)算法需要基于邻接矩阵的数据。

4、游戏数据

4.1 普通数据(历史数据)

需要保存玩家游戏的各种数据。

  1. 记录成绩;
  2. 鼓励进步;
  3. 参与分享;
  4. 不亦乐乎?

数据项,包括但不限于:

(1)鼠标点击X坐标

(2)鼠标点击Y坐标

(3)操作的格子Id

(4)操作的格子(行)位置

(5)操作的格子(列)位置

(6)时间戳Ticks

(7)操作编码

4.2 细节数据(防作弊数据)

保存玩家扫雷过程的细节数据,主要用于区分是“人”或是机器人(程序)扫雷。

数据项,包括但不限于:

(1)行数

(2)列数

(3)地雷总数

(4)密度系数

(5)总耗时(毫秒)

(6)左键单击数

(7)全部点击数

(8)本地开始时间戳(Ticks)

(9)结束时间戳(Ticks)

(10)布雷矩阵信息(01)

(11)挖出地雷数

(12)步数(移动次数)

后续的处理包括(但不限于):

  1. 玩家鼠标轨迹数据分析;
  2. 玩家操作记录分析;
  3. 玩家行为分析;

目的就是一个:看看到底是“人”在玩,还是“机”在玩!

后记:

花了几天时间,家人已经玩的不亦乐乎了。

邻居孩子正在与他认为非常简单的六边形斗争呢,似乎不太顺利。

本来想这么简单的事,几句话就可以说清楚了,稀稀拉拉居然写了这么多文字,关键是榨干了也没几句话是有用的。既然写了,就发出来吧。请大家不要嫌弃。

谢谢您耐心的阅读!

下载软件:

下载软件,提取码 c4huhttps://pan.baidu.com/s/1mVddqQ8oBN-6Ea2rFxvBaw?pwd=c4hu%20%20%E6%8F%90%E5%8F%96%E7%A0%81%EF%BC%9Ac4hu

C#,桌面游戏编程,编写制作《扫雷》游戏代码的实现——需求分析与总体架构设计相关推荐

  1. python3扫雷代码_GitHub - pantaduce/minesweeper: Python代码编写的扫雷游戏

    Minesweeper(扫雷) 这是一个由Python编写的扫雷游戏,基于tkinter/Tkinter开发,支持python2和python3. 功能 概述 基本功能:左键扫雷,右键标记 记录游戏步 ...

  2. c++扫雷游戏代码_C语言学习教程,用C语言编写扫雷游戏

    本文实例为大家分享了C语言实现扫雷游戏及其优化的具体代码,供大家参考,具体内容如下 关于扫雷优化 1.核心思想:使用两个二维数组进行设计,一个用于显示,一个用于后台雷的布置. 2.使用宏常量,后期可以 ...

  3. 使用Tableau制作扫雷游戏和三维地图

    一种利用低代码可视化工具处理复杂逻辑的有益尝试. 可视化作品的复杂度无外乎两种: 模型处理层的复杂度 和 可视化设计层的复杂度 模型处理层的复杂度 当计算逻辑异常复杂,无法直接通过线性计算获取计算结果 ...

  4. 编写一个扫雷游戏,我们首先要清楚游戏规则

    编写一个扫雷游戏,我们首先要清楚游戏规则:         扫雷就是要把所有非地雷的格子揭开即胜利:踩到地雷格子就算失败.游戏主区域由很多个方格组成.使用鼠标左键随机点击一个方格,方格即被打开并显示出 ...

  5. 【180720】微软Windows扫雷游戏代码

    源码简介   本源码是一个微软Windows扫雷游戏代码,可选择难度级别:初级.中级.高级. 注意事项: 1.开发环境为Visual Studio 2010,使用.net 2.0开发. 源码下载地址: ...

  6. C语言编程练习,扫雷游戏

    编程记录,关于B站上鹏哥C语言课程中的练习记录 记录内容:C语言实现扫雷(关于数组) 思路 test.c 测试逻辑 game.h 存储声明 game.c 编写运行函数 用循环使游戏多次执行(do-wh ...

  7. Java扫雷游戏项目-1小时编写出扫雷游戏

    <扫雷>是一款大众类的益智小游戏,想必有很多人都玩过这款小游戏,但是我们如何用代码编写出这款小游戏呢? 小编整理了[Java扫雷游戏项目]视频教程,只要90分钟就可以完成一个你自己亲手开发 ...

  8. python编写猜数游戏代码、如果不是整数、显示输入错误_数字炸弹游戏程序 用python来实现...

    相信许多小伙伴都玩过数字炸弹游戏,就是指在一定数字范围(一般是整数,不包含边界)里,一个玩家选中一个数字当作炸弹,其余玩家在这个范围含数字,每次只要没猜中炸弹数字,则根据玩家猜的数字缩小范围,直至其中 ...

  9. python编写猜数游戏代码、如果不是整数、显示输入错误_python编写猜数游戏代码、如果不是整数、显示输入错误_数字炸弹游戏程序 用python来实现......

    相信许多小伙伴都玩过数字炸弹游戏,就是指在一定数字范围(一般是整数,不包含边界)里,一个玩家选中一个数字当作炸弹,其余玩家在这个范围含数字,每次只要没猜中炸弹数字,则根据玩家猜的数字缩小范围,直至其中 ...

最新文章

  1. DPU(Data Processing Unit)数据处理器
  2. bzoj 1863 二分+dp check
  3. 你也能与AlphaGo谈笑风生:AlphaGo教学工具上线,2万多变化,37万多步棋
  4. SAP Fiori Elements - how facet is loaded for my productive POC
  5. java中编译类型的方法 和 运行时的类型方法 有什么区别
  6. 备案php代码,备案查询API PHP代码
  7. Windows 11 将使 AMD 芯片性能下降 15%!
  8. matlab+adst,SPC572L64E3 - 用于汽车动力系统应用的32位Power Architecture MCU - STMicroelectronics...
  9. 最受欢迎web前端技术总结
  10. Android 9.0 Framwork Wifi源码学习目录
  11. android time计时器,android 计时器的三种实现(Chronometer、Timer、handler)
  12. 1995-2020年国泰安并购重组数据库
  13. 旋转变换公式详细推导
  14. Ubuntu个人笔记
  15. 使用Heartbeat实现双机热备
  16. 新概念英语(第三册)复习(原文)——Lesson 21 - Lesson 30
  17. jdk11手动安装jre
  18. 论文摘要和引言的区别
  19. uni-app小程序如何获取视频时长
  20. 设置计算机的启动顺序CDROM.C.A,bios如何设置光驱启动顺序?三种BIOS设置光驱第一启动的方法详细图解...

热门文章

  1. 我的世界1.13 mod制作——制作一个Item(二)
  2. Unity3D学习笔记——RigidBody(刚体)
  3. 争议南科大 何须尽责朱清时
  4. 程序员新人面临最尴尬的事:需要工作积累经验,需要有经验才能找到工作!到底怎么办?...
  5. 微服务网关soul搭建
  6. Java中字符与字节常识
  7. JavaFX店铺管理软件
  8. 12米数字高程DEM现已上线!附DEM专题图制作教程
  9. js 中的this指针
  10. c语言 json 请求_JSON的简单介绍以及C语言的JSON库使用