Win7扫雷的H5完整复刻实现(三) / 鼠标左右键同时按下事件与收尾工作的实现

鼠标左右键同时按下展开 提示雷区

js不自带监听鼠标左右键同时按下的事件,需要用mousedown进行模拟。

空白区(eBlock)不会触发这个事件

	_bindEvent: function _bindEvent() {
		var _this = this;
		$('.Block').on("mousedown", function(e) {
			//重设标志
			_this.$checkFlag = false;
			//阻止默认
			$(e.target).bind("contextmenu", function() {
				return false;
			});
			//二次点击判定
			if(_this.$firstClick != null) {
				_this.$secondClick = e.which;
				if(_this.$secondClick === _this.$firstClick) {
					_this.$secondClick = null;
					_this.$firstClick = null;
					return;
				} else {
					_this.$checkFlag = true;
					//点击是文字
					if(e.target.nodeName === "SPAN") {
						var $spanValue = $(e.target).text();
						e.target = e.target.parentNode;
					}
					//不接受空白块
					if($(e.target).hasClass("eBlock")) return;
					//得到位置
					var $index = $('.Block').index($(e.target));
					var $clickX = Math.floor($index / 18);
					var $clickY = $index % 18;
					var $indexItem;
					var $indexItemCtn = [];
					var $flagAns = 0;
					var setColor = function(index) {
						if($($('.Block')[index]).hasClass("eBlock") || $($('.Block')[index]).hasClass("enBlock")) return;
						if($($('.Block')[index]).hasClass("fBlock")) {
							$flagAns++;
							return;
						}
						$indexItemCtn.push(index);
						$($('.Block')[index]).addClass("Block-judge");
					}
					//边界鉴定
					setColor($index);
					if($clickX != 0) {
						$indexItem = ($clickX - 1) * 18 + $clickY;
						setColor($indexItem);
					}
					if($clickY != 0) {
						$indexItem = $clickX * 18 + $clickY - 1;
						setColor($indexItem);
					}
					if($clickX != 17) {
						$indexItem = ($clickX + 1) * 18 + $clickY;
						setColor($indexItem);
					}
					if($clickY != 17) {
						$indexItem = $clickX * 18 + $clickY + 1;
						setColor($indexItem);
					}
					if($clickY != 0 && $clickX != 0) {
						$indexItem = ($clickX - 1) * 18 + $clickY - 1;
						setColor($indexItem);
					}
					if($clickY != 17 && $clickX != 0) {
						$indexItem = ($clickX - 1) * 18 + $clickY + 1;
						setColor($indexItem);
					}
					if($clickY != 17 && $clickX != 17) {
						$indexItem = ($clickX + 1) * 18 + $clickY + 1;
						setColor($indexItem);
					}
					if($clickY != 0 && $clickX != 17) {
						$indexItem = ($clickX + 1) * 18 + $clickY - 1;
						setColor($indexItem);
					}
					//数值鉴定
					$indexItemCtn.forEach(function(item, index) {
						//只接受带值块
						if($flagAns != $spanValue) return;
						if(!$(e.target).hasClass("enBlock")) return;
						if($spanValue == null) return;

						var $checkX = Math.floor(item / 18);
						var $checkY = item % 18;
						//展开
						if(map[$checkX][$checkY] == -1) {
							//雷
							_this._clickMines(null, item);
						} else if(map[$checkX][$checkY] == 0) {
							//空白区
							_this._clickEmpty(null, $checkX, $checkY);
						} else {
							//雷域
							_this._clickMinesArray(null, $checkX, $checkY);
						}
					});
				}
			} else {
				_this.$firstClick = e.which;
			}
		});

	},

当第一次点击触发mousedown时记录e.which(左键为1 右键为3),在不触发mouseup的过程中再次触发mousedown,记录第二次的e.which 若两次点击的值相同,则是双击左键或右键,不予处理,反之触发逻辑:通过算法演算点击值的八向坐标(同样需要边界鉴定),将其标黑(提示UI),并设置checkFlag为true,当checkFlag为true的情况下触发mouseup,取消标黑并进行演算,若八向的旗方块数量等于Block中的数值,则模拟点击周围未被点击的方块(会触发炸弹方块或者空白方块)。


收尾

其他的需求

- 计时器

- 炸弹数量提示

这部分不作赘述,计时器触发在第一次点击之后,用setTimeout进行模拟,炸弹数量变化触发在设置flag之后。


总结

若将扫雷的所有的算法实现,可能过程并不简单,甚至算法比较复杂。

但是实际上这个项目比起算法更考验的是项目的构架,如何让事件互相触发而不冲突,又如何模拟一些UI的操作,对基础的要求并不低。

项目的构架在文章中并不能体现出来,各位可以参考我的github源码,至此扫雷的核心实现方法已经全部详述了,希望各位对这个练手项目有兴趣的可以试试,因为他并不算简单,非常适合基础和进阶的锻炼,若本文对你有所帮助,记得去github给我加颗星星噢。


扫雷完整项目github地址  https://github.com/xxx407410849/MinesSweeper

若本文对您有帮助请给我的git项目加个星星哦

你可能感兴趣的:(前端,javascrpit,H5游戏,算法)