HTML5实现经典Windows扫雷游戏

56 篇文章 5 订阅
4 篇文章 0 订阅

上周末突然想尝试着做一个扫雷游戏。扫雷游戏我是很喜欢玩的,更年轻时候,晚上晚上几点钟的时候都有。。。

虽然之前没有写过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)];
	}


//获取坐标:
function getEventPosition(ev){   
	    var x, y;   
	    if (ev.layerX || ev.layerX == 0) {   
		        x = ev.layerX;   
		        y = ev.layerY;   
    }else if (ev.offsetX || ev.offsetX == 0) { // Opera   
	        x = 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();


演示地址:http://runningls.com/demos/2016/mine/mine.html

github:https://github.com/liusaint/games/tree/master/mine

欢迎留言讨论。

转载注明出处:http://blog.csdn.net/liusaint1992/article/details/50531186

  • 11
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值