学校实训最后布置的一个答辩作业,周围同学都是在用资源做简单动画,突然想起大一的时候想用C语言模拟的扫雷,虽然做H5游戏比较少,但是还是较完美的复刻了WIN7扫雷的大部分算法和UI。
简单扫雷本身的实现难度不算太高,若是想要完美复刻win7的扫雷,还是需要费一番功夫的,这份无聊之作(装逼之作)是用两天时间写出来的,某些地方略有缺陷,但无伤大雅。
虽然本作是用JS语言实现逻辑,但是其他语言仍有互通之处,可以作为参考
同时推荐各位注重于代码的构架和算法本身的实现,下面我将讲述我的构架和算法实现过程与想法,希望各位能有自己的想法,不要参考他人过多
这是本作扫雷共计实现的功能和UI
- 首次点击鉴定
- 鼠标左右键同时点击展示周围雷区,并在满足一定条件下展开雷区
- 雷域全随机
- 参照win版扫雷的加载动画(渐变加载)
- 爆炸动画
首先让我们明确扫雷本质到底是什么:
扫雷是一个N*M的矩阵下发生状态转移的过程,每次对矩阵内元素点击的过程,都是一次发生状态转移的判断条件,先通过算法修改矩阵中的状态码,再用可视的界面表示这个矩阵中的内容,其中可以用动画作为过渡,这就是扫雷的本质。
其中,矩阵可以用二维数组表示,可视界面可以用canvans或者div绘制,其区别只在于canvans的动画与div不一样,canvans由于其动画需要清屏的特性,不仅效率不够高,而且想要实现一些UI的算法会变得非常复杂,所以本作选用div块进行模拟。
绘制初始可视界面:
其中sBlock是初始方块,game-ctn($ctn)是方块容器。
for(var i = 0; i < $num; i++) {
for(var j = 0; j < $num; j++) {
(function(i, j) {
var $sBlock = $("<div class='Block sBlock'></div>");
$ctn.append($sBlock);
$sBlock.animate({
'opacity': '0.9'
}, 50 * (100 - i * 3 - j * 4));
})(i, j);
}
}
css不再赘述,可以直接参考我git里的代码,注意容器需要留出border的宽度,不然会导致方块溢出。
这里实现了渐变加载,本质是使每一个方块的透明度从0至0.9进行变化,通过设置不同的动画时间,来实现整体的加载动画
这里实现的是从末尾开始两边成三角蔓延加载的动画,通过50*(100-i*3-j*4)的算法,i与j越小的方块显示的速度也就越慢,同时若偏移量相同(设偏移量为N),map[x][0]与map[0][x]的动画加载速度相同(皆是50*(100-Nx)),同时他们连成一条线的方块,如map[x-1][1],加载速度同理相同,这样就造成了三角渐变的视觉效果,而这里 j(y轴)造成的速度偏移量比 i(x轴)大,导致方块在y轴上的加载速度比x轴上快,所以加载动画的渐变效果是倾斜的。
(加载过程中截图)
首次点击鉴定
为判断是否为第一次点击,可以使用标志变量进行鉴定,向所有Block绑定点击事件,若标志变量为false则执行首次点击算法并设其为true,反之不执行。
明确需求如下:
- 每一局游戏的第一次点击展开的区域大小,样子都不同
- 第一次点击的周围8个方块一定不是雷,不然扫雷游戏将难以进行
- 延展初次禁雷区时不应该通过斜角延展,不然会导致其展开的时候很丑(想象一下两个矩形只有一个角连接,不符合扫雷的UI)
第一次点击后,初始化地图矩阵,首先设置点击处周围的禁雷域,这里用-2的状态码表示禁雷域(本质是空白地区),0表示初始值
_randomClickArray: function _randomClickArray(numX, numY, arrayNum) {
var randomNumX = numX;
var randomNumY = numY;
var $firstFlag = this.$firstFlag;
var $squareNum = void 0;
if(arrayNum < 0) return;
//越过边界
if(!(numX < 0 || numX > 17 || numY < 0 || numY > 17)) {
//重复遍历
if(map[numX][numY]