上周末突然想尝试着做一个扫雷游戏。扫雷游戏我是很喜欢玩的,更年轻时候,晚上晚上几点钟的时候都有。。。
虽然之前没有写过HTML5游戏,不过我感觉肯定能写出来的。虽然对于写H5游戏有哪些步骤什么的都不是很明了。
另外一点,写这个游戏,所有的算法都必须是自己思考出来,不能在写之前去参考别人的思路。
因为一旦参考了,就会受到别人思路左右,永远没有机会从无到有地去思考这个自己喜欢过的游戏了。
然后上周末完成了基本雏形,上周闲的时候又断断续续地完善。一个功能一个功能地实现。 中间还抽空做了一个贪吃蛇。 相比扫雷而言,贪吃蛇的逻辑就相当简单了。
先看几个过程中的版本:
完成版本,已经像模像样了呢!用了网上下的图片扫雷资源,数字,旗子之类的。
实现的功能,按完成步骤。
1.根据格子数量,初始化canvas画布。绘制格子。 初始化所需要的数组。包含格子信息的格子数组。
2.鼠标划过每一个格子改变格子。 需要判断鼠标在画布上的坐标。然后根据画布坐标判断格子。
3.随机生成雷。 do while循环,生成不重复的格子坐标保存到地雷数组和格子数组。
4.点击打开雷。显示周围雷的数量。如果雷的数量为0。则用一个递归计算这个雷周围8个格子里有没有周边雷数量为0的格子,如果有,再计算这个格子周围。。。直到把相连的所有周边雷数量为0的格子找出来,放入一个数组。然后再把这个数组里所有格子以及它们周围的8个格子显示出来,显示每个格子周围雷的数量 。雷的数量用不同颜色。
不过我感觉这个算法效率还不是很高。要优化。
5.被打开过的格子或被标记过的格子,没有hover事件。
6.标记格子。用旗子或问号。 屏蔽网页原本的右键事件。
7.加上时间,以及雷的数量的标记。以及点击的时候才生成雷。避免第一次点击 就点到雷。
8.双键同击事件。如果周边雷的数量等于周边标记的数量,就把周边没有打开没有标记的点开。不等于就动态展现周边剩下哪几个没打开的。
9.点中的雷以记错误的标记用不同的图像表达出来。
10.用网上下的资源美化。增加级别选择。高级,中级,初级,以及自定义。优化界面效果。
部分代码:
var Mine = function (ele,panewidth,paneheight,minenum,tagele,timeele) {this.PANE_SIZE = 16;//每个格子的像素px大小。this.paneheight = paneheight;//有几行this.panewidth = panewidth;//有几列this.minenum = minenum;//有几个雷this.ele = document.getElementById(ele);this.cxt = this.ele.getContext("2d");this.tagele = tagele;this.timeele = timeele;}
init:function(){//画格子this.ele.width = this.PANE_SIZE * this.panewidth;this.ele.height = this.PANE_SIZE * this.paneheight;this.oldPos = [0,0];//鼠标上一个停留的位置。默认值。用于处理hover事件。this.cellArr=[];//格子信息保存数组。保存每个格子是不是雷,当前是否有标记。this.mineArr=[];//地雷位置数组。this.time = 0;//操作时间this.notTaged = this.minenum;//未标记数量this.numToImage(this.notTaged,this.tagele);//将标记数字转成图片this.numToImage(this.time,this.timeele);//将时间数字转成图片this.mousedownArr='';//鼠标点下事件,是为了双键同击事件。this.createCells();//初始化cellArr数组,并涂上颜色。this.inited = false;//是否初始化过。clearInterval(this.timer);//时间跳动//绑定事件this.onmousemove();//鼠标在上面移动,触发每个格子的this.onmouseout();//鼠标移出canvas的事件。this.onmousedown();//鼠标点下事件,是为了双键同击事件。this.onclick();//点击方格事件this.preRightMenu();//阻止右键菜单。}
createMines:function(pos){//生成雷的位置。保存到一个数组[[2,3],[4,6]];var minenum = this.minenum;var mineArr = this.mineArr;var mineItem='';var cellArr = this.cellArr;for (var i = 0; i < minenum; i++) {//如果生成的重复了就重新生成。do{mineItem = [getRandom(this.panewidth),getRandom(this.paneheight)];}while(in_array(mineItem,mineArr)||pos.toString()== mineItem.toString());cellArr[mineItem[0]][mineItem[1]].isMine = true;mineArr.push(mineItem);};}
getCellArea:function(pos){//根据格子坐标返回一个格子左上角的像素坐标[32,666];return [(pos[0]-1)*this.PANE_SIZE+1,(pos[1]-1)*this.PANE_SIZE+1];},getCellPos:function(coordinate){//根据像素坐标返回格子坐标。[3,5];return [Math.ceil(coordinate.x/this.PANE_SIZE),Math.ceil(coordinate.y/this.PANE_SIZE)];}
//获取坐标:functiongetEventPosition(ev){varx,y;if(ev.layerX||ev.layerX==0){x=ev.layerX;y=ev.layerY;}elseif(ev.offsetX||ev.offsetX==0){//Operax=ev.offsetX;y=ev.offsetY;}return{x:x,y:y};}
drawCell:function(pos,type){//绘制不同种类的格子。var area = this.getCellArea(pos);var cxt = this.cxt;var image = new Image();var src;var srcArr = ["res/blank.bmp","res/0.bmp","res/flag.bmp","res/ask.bmp","res/mine.bmp","res/blood.bmp","res/error.bmp"];//1正常格 2mouseover格子 3旗子格 4问号格 5正常雷格 6点中雷格 7.错误标记var index = type -1;image.src =srcArr[index];image.onload = function(){cxt.drawImage(image,area[0],area[1],16,16);}},drawNum:function(pos,num){//绘制数字var area = this.getCellArea(pos);var cxt = this.cxt;var image = new Image();image.src = "res/"+num+".bmp";image.onload = function(){cxt.drawImage(image,area[0],area[1],16,16);}}
calZeroMine:function(pos,zeroArr){//使用递归求出周围所有的全为0的区域。算法效率还不是很高。var cellArr = this.cellArr;// var aroundArr = [[pos[0]-1,pos[1]],[pos[0],pos[1]-1],[pos[0],pos[1]+1],[pos[0]+1,pos[1]]];//只保留上下左右 好像还是会有一点问题。var aroundArr = [[pos[0]-1,pos[1]-1],[pos[0]-1,pos[1]],[pos[0]-1,pos[1]+1],[pos[0],pos[1]-1],[pos[0],pos[1]+1],[pos[0]+1,pos[1]-1],[pos[0]+1,pos[1]],[pos[0]+1,pos[1]+1]];var aroundMineNum = 0;for (var i = 0; i < aroundArr.length; i++) {aroundMineNum = this.calAround(aroundArr[i]);//附近雷的数量if(aroundMineNum == 0 && this.checkCell(aroundArr[i]) && cellArr[aroundArr[i][0]][aroundArr[i][1]].isMine == false &&!in_array(aroundArr[i],zeroArr)){zeroArr.push(aroundArr[i]);this.calZeroMine(aroundArr[i],zeroArr);//调用自己,递归。}};return zeroArr;}
var mine1 = new Mine("mine1",30,16,99,"game-tag-images","game-time-images");mine1.init();
演示地址:/demos//mine/mine.html
github:/liusaint/games/tree/master/mine
欢迎留言讨论。
转载注明出处:/liusaint1992/article/details/50531186