web版扫雷小游戏(三)
~~~接上篇,上篇介绍了游戏实现过程中第一个比较繁琐的地方,现在展现在玩家面前的是一个有血有肉的棋盘,从某种意义上说玩家已经可以开始游戏了,但是不够人性化,玩家只能一个一个节点的点开,然后判断,然后标记等等,程序暂不能人性化的辅助玩家将游戏进行下去,趣味性不够强,接下来就来完善这些辅助功能。
二、空节点点击触发其周围所有空节点展开
此过程主要是辅助玩家快速标记雷点,增强游戏趣味性,即当游戏进行中,玩家点击棋盘中某个未展开的节点M时,如果该节点是空节点(对应的数值为0),则展开该节点的同时,需要遍历其周围8个方向上的节点,如果某个方向上的节点也是空节点,则再以该点为中心重复上述过程,直到遍历完所有相邻节点M的空节点为止。这个过程值得注意的是:
1. 游戏开始后(玩家第一次点击),如果第一个节点是非雷点,则程序开始监听空节点点击事件。
2. 节点M是空节点,即其周围没有雷点存在,用户点击后该点周围8个方向上的节点均需要展开。
3. 遍历节点M周围节点时,如果遇到新的空节点,则立即以该节点为中心重复遍历过程,此处我们采用递归处理,默认从北方节点顺时针方向依次遍历。
4. 递归遍历时,节点M与其周围节点互为方位节点,为了避免陷入重复循环,提高效率,则过滤掉已经遍历过的节点,这里定义一个栈,压入已经遍历过的节点,每次进入递归时判断节点是否已经在栈中,如果在,则忽略。
5. 遍历时,如果节点非空(一定不是雷点),则只需展开即可,接着判断并遍历下一个方位节点。
6. 一次递归完成后,程序会自动清除或重置当前次递归遍历产生的临时数据和变量,开始监听下一次空节点的点击事件。
功能效果及遍历路径见下例:
如上图,节点M点击后,程序会按照黄色箭头(只画出部分)的顺序依次遍历并展开节点,直到由M节点触发的所有相邻的空节点遍历完毕,则递归完成。
这个过程需要在棋盘控制类(BombObjectList)中实现:
首先,需要定义两个对外的类的属性,标记为BombObjectList.fire_X和BombObjectList.fire_X,这两个属性默认初始化值为-1,一旦玩家触发了空节点,则分别赋值为空节点在棋盘中的x、y坐标。
其次,在类中定义一个定时器,随时监听上面两个属性值的变化,一旦值均不为-1,表示玩家触发了空节点的点击事件,程序需要响应这个事件,我们定义一个响应函数,标记为CheckAroundBomb。
最后,遍历该空节点,必要时进行递归,递归过程见上述描述,递归函数标记为checkBomb。
类的对外属性定义如下:
BombObjectList.fire_X = -1; //触发空节点弹开时节点的x坐标 BombObjectList.fire_Y = -1; //触发空节点弹开时节点的y坐标
定时器定义如下(黑色阴影部分为空节点点击事件监听过程),50毫秒监听一次:
1 //开启对空节点的监听 2 var ListenFire = null; 3 me.ListenKong = function() { 4 if (ListenFire === null || ListenFire === undefined) { 5 ListenFire = setInterval(function() { 6 if (BombObjectList.fireFlag === 2) { 7 //游戏结束,关闭定时器 8 clearInterval(ListenFire); 9 ListenFire = null; 10 } 11 else if (BombObjectList.fireFlag === 1) { 12 //游戏进行中,检测空节点的点击事件 13 if (BombObjectList.fire_X !== -1 && BombObjectList.fire_Y !== -1) { 14 //根据x、y坐标找到该节点在节点集合中的对象 15 var tempObjEx = me.CheckObjItem(BombObjectList.fire_X, BombObjectList.fire_Y).obj; 16 if (tempObjEx !== null) { 17 me.CheckAroundBomb(tempObjEx); 18 } 19 } 20 //游戏进行中,监测双击事件 21 if (BombObjectList.DC_X !== -1 && BombObjectList.DC_Y !== -1) { 22 //根据x、y坐标找到该节点在节点集合中的对象 23 var tempObjEx = me.CheckObjItem(BombObjectList.DC_X, BombObjectList.DC_Y).obj; 24 if (tempObjEx !== null) { 25 if (BombImgObject.MouseType === 3) { 26 //双击按下事件 27 me.CheckAroundBombDC_Down(tempObjEx); 28 } 29 else { 30 //双击弹起事件 31 me.CheckAroundBombDC_Up(tempObjEx); 32 } 33 } 34 } 35 } 36 }, 50);
事件响应函数CheckAroundBomb和递归函数定义如下:
1 //递归函数 2 function checkBomb(obj) { 3 //对当前空区进行八方位踩点,递归查询相连的所有空区,并全部打开 4 for (var i = 0; i < me.enmbVal.length; i++) { 5 var _Obj = eval("obj." + me.enmbVal[i]); 6 //判断该方位是否存在,存在则展开节点 7 if (_Obj != null) { 8 var _X = _Obj.X; 9 var _Y = _Obj.Y; 10 var tempObjEx = me.CheckObjItem(_X, _Y).obj; 11 if (tempObjEx.DisplayNum === 0) { 12 //如果为空,递归查询空节点,并展开其8个方位的所有节点 13 tempObjEx.ImgObj.ShowNumImg(); 14 //将当前节点入栈,以免后续再次将其作为空节点进入递归流程 15 var isIn = (function() { 16 for (var s = 0; s < stackObj.length; s++) { 17 if (stackObj[s].Equals(tempObjEx)) { 18 return true; 19 } 20 } 21 return false; 22 } ()); 23 if (!isIn) { 24 stackObj.push(tempObjEx); 25 //进入递归流程 26 checkBomb(tempObjEx); 27 } 28 } 29 else { 30 tempObjEx.ImgObj.ShowNumImg(); 31 } 32 } 33 } 34 } 35 //存储遍历过的节点 36 var stackObj = []; 37 me.CheckAroundBomb = function(that) { 38 if (!(that instanceof BombObject) || that.constructor !== BombObject || that == null) { 39 throw new Error("the obj is not allowed."); 40 return; 41 } 42 else { 43 stackObj.push(that); 44 //进入递归调度,查找并展开8个方向上的节点 45 checkBomb(that); 46 //重置触自动发展现时监听的节点坐标,准备监听下一个 47 BombObjectList.fire_X = -1; 48 BombObjectList.fire_Y = -1; 49 //清空遍历过的堆栈对象列表 50 stackObj.length = 0; 51 } 52 };
三、鼠标左键和右键一起按下时的事件响应
这个过程是这三个里面最繁琐的一个,不过它的实现可以大大增强游戏的趣味性,在扫雷游戏过程中,这个功能是用的最频繁的,对脚本程序的检测和判断及效率要求较高,总体来说,主要基于节点数值和其周围雷点个数一直的原则进行判断,分析得出存在以下几种情况:
1. 玩家双击的对象是未展开的节点,此时系统并不需要过多的判断,因为玩家还没有标记出该点周围的雷点,程序只需闪烁提示该点周围的节点即可,鼠标事件后复原到按下前的状态。
2. 玩家双击的对象是已展开的节点,此时有两种情况,比如改节点的数值为N,而玩家在其周围标记的雷点个数为M:
如果N!=M,则提示用户进行修改,闪烁提示同上一条;
如果M=N,接下来要判断该点周围的未标记节点的类型,记未标记雷点的个数为C,若C>0,则用户标记错误,鼠标按下后游戏结束,提示用户标记错误;若C=0,则用户标记正确,展开所有周围未标记节点,当这些节点中有空节点时,则需要递归展现所有相邻的空节点,过程同上述处理过程。
上述几种情况的示例见下图:
对于这一过程的实现,我们分两步进行:
第一步:响应鼠标左右键一起按下事件,函数标记为CheckAroundBombDC_Down,此过程记录点击节点周围的游戏上下文,如该点周围已经标记的雷点个数markRoundNum,未标记节点中是否有雷点标记位hasBomb。
第二步:响应鼠标左右键一起提起事件,函数标记为CheckAroundBombDC_Up,如果该点未展开,则复原图片对象,什么也不做;如果该点已展开,若其周围有雷点,则复原图片,什么也不做,否则展开其周围的非雷点,必要时进行递归展现。
此外,棋盘控制类中需要定义个定时器,随时监听左右键一起按下事件,并将事件触发对象节点的x、y坐标记录到棋盘类的两个对外属性BombObjectList.DC_X和BombObjectList.DC_Y,就像监听空节点点击事件一样。
属性定义如下:
1 BombObjectList.DC_X = -1; //左右键一起按下时节点的x坐标 2 BombObjectList.DC_Y = -1; //左右键一起按下时节点的y坐标
定时器定义如下(黑色阴影部分为空节点点击事件监听过程),50毫秒监听一次:
1 //开启对空节点的监听 2 var ListenFire = null; 3 me.ListenKong = function() { 4 if (ListenFire === null || ListenFire === undefined) { 5 ListenFire = setInterval(function() { 6 if (BombObjectList.fireFlag === 2) { 7 //游戏结束,关闭定时器 8 clearInterval(ListenFire); 9 ListenFire = null; 10 } 11 else if (BombObjectList.fireFlag === 1) { 12 //游戏进行中,检测空节点的点击事件 13 if (BombObjectList.fire_X !== -1 && BombObjectList.fire_Y !== -1) { 14 //根据x、y坐标找到该节点在节点集合中的对象 15 var tempObjEx = me.CheckObjItem(BombObjectList.fire_X, BombObjectList.fire_Y).obj; 16 if (tempObjEx !== null) { 17 me.CheckAroundBomb(tempObjEx); 18 } 19 } 20 //游戏进行中,监测双击事件 21 if (BombObjectList.DC_X !== -1 && BombObjectList.DC_Y !== -1) { 22 //根据x、y坐标找到该节点在节点集合中的对象 23 var tempObjEx = me.CheckObjItem(BombObjectList.DC_X, BombObjectList.DC_Y).obj; 24 if (tempObjEx !== null) { 25 if (BombImgObject.MouseType === 3) { 26 //双击按下事件 27 me.CheckAroundBombDC_Down(tempObjEx); 28 } 29 else { 30 //双击弹起事件 31 me.CheckAroundBombDC_Up(tempObjEx); 32 } 33 } 34 } 35 } 36 }, 50);
鼠标左右键一起按下和弹起事件定义如下:
1 var tempAroundObj = []; //存储双击时遍历的8方位节点对象 2 var hasBomb = false; //标记上一变量存储的对象是否包含雷点 3 //双击按下时事件处理程序 4 me.CheckAroundBombDC_Down = function(obj) { 5 if (!(obj instanceof BombObject) || obj.constructor !== BombObject || obj == null) { 6 throw new Error("the obj is not allowed."); 7 return; 8 } 9 else { 10 var markRoundNum = 0; 11 for (var i = 0; i < me.enmbVal.length; i++) { 12 var _Obj = eval("obj." + me.enmbVal[i]); 13 //判断该方位是否存在,存在则展开节点 14 if (_Obj != null) { 15 var _X = _Obj.X; 16 var _Y = _Obj.Y; 17 var tempObjEx = me.CheckObjItem(_X, _Y).obj; 18 var tempImgPic = tempObjEx.ImgObj; 19 if (!tempImgPic.ImgObj.flag) { 20 //该节点尚未展开,此时需更改该图片 21 tempImgPic.ShowNumImg(1); 22 tempAroundObj.push(tempObjEx); 23 //如果是雷点,且未标记 24 if (tempObjEx.IsBomb && tempImgPic.ImgObj.src.indexOf("flag") < 0) hasBomb = true; 25 //统计核心点旁边被标记的雷点个数 26 if (tempObjEx.IsBomb && tempImgPic.ImgObj.src.indexOf("flag") >= 0) markRoundNum++; 27 } 28 } 29 } 30 //判断自己 31 if (!obj.ImgObj.ImgObj.flag) { 32 //该节点尚未展开,此时需更改该图片 33 obj.ImgObj.ShowNumImg(1); 34 tempAroundObj.push(obj); 35 } 36 else { 37 //如果核心点是展开的,则需要比较核心点的数值和其周围已经标记处的雷点个数 38 if ((markRoundNum === parseInt(obj.DisplayNum)) && hasBomb) { 39 //标记错误,游戏结束 40 hasBomb = false; 41 } 42 else { 43 //允许用户修改,什么也不做 44 } 45 } 46 } 47 } 48 //双击弹起时事件处理程序,检测当前点周围的节点,必要时进行递归 49 me.CheckAroundBombDC_Up = function(obj) { 50 if (!(obj instanceof BombObject) || obj.constructor !== BombObject || obj == null) { 51 throw new Error("the obj is not allowed."); 52 return; 53 } 54 else { 55 //如果核心节点是未展开的或者遍历列表中包含雷点,则复原遍历列表中对象对应的图片对象 56 if (!obj.ImgObj.ImgObj.flag || hasBomb) { 57 for (var i = 0; i < tempAroundObj.length; i++) { 58 //复原节点图片 59 tempAroundObj[i].ImgObj.ShowNumImg(2); 60 } 61 } 62 else { 63 //如果核心点是展开的,没有雷点,则自动展开,空节点需要递归 64 for (var j = 0; j < tempAroundObj.length; j++) { 65 //展开节点 66 tempAroundObj[j].ImgObj.ShowNumImg(); 67 //如果节点为空,则需要递归遍历展开 68 if (tempAroundObj[j].DisplayNum === 0) { 69 checkBomb(tempAroundObj[j]); 70 } 71 } 72 } 73 //复原监听变量 74 BombObjectList.DC_X = -1; 75 BombObjectList.DC_Y = -1; 76 //删除遍历的临时节点对象列表 77 tempAroundObj.length = 0; 78 hasBomb = false; 79 } 80 }
至此,游戏的三个难点基本解决,看到这里,还有两个东西没有介绍,一个是雷点类(即节点信息类)BombObject,另一个是节点对应的图片对象类BombImgObject,下篇将揭开其神秘的面纱。
接下篇~~~~
转载于:https://www.cnblogs.com/freshfish/p/3388329.html
web版扫雷小游戏(三)相关推荐
- web版扫雷小游戏(一)
作为一名程序猿,平时的爱好也不多,说起游戏,我不太喜欢大型的网游,因为太耗时间,偶尔玩玩经典的单机小游戏,比如windows下自带的游戏扫雷(秀一下,高级下最高纪录110s). 现阶段正在致力于web ...
- c语言小游戏 精简_C语言开发简易版扫雷小游戏
C 语言开发简易版扫雷小游戏 本文给大家分享的是一个使用 C 语言开发的命令行下的简易版扫雷小游戏, 本身没有什么太 多的技术含量, 只不过是笔者的处女作, 所以还是推荐给大家, 希望对大家学习 C ...
- C实现扫雷小游戏(简易版)
你知道,有些鸟儿是注定不会被关在牢笼里的,它们的每一片羽毛都闪耀着自由的光辉.--<肖申克的救赎> 目录 1.设计框架 2.设计流程 2.1菜单 2.2初始化雷阵 2.3生成雷 2.4玩家 ...
- 用C语言实现扫雷小游戏(附上思路+项目展示+源代码)
文章目录 前言 一.扫雷小游戏整体思路讲解. 二.game.c各游戏功能函数的讲解 1.InitBoard 初始化数组函数讲解 2.DisplayBoard 打印格子函数讲解 3.Setmine 电脑 ...
- 如何开发一个扫雷小游戏?
如何用C#开发一个扫雷小游戏? 十分自豪的说,计算机编程就是变魔术,每一个coder都是一个魔术师. 初学C#的时候,我相信很多人都和我一样,学会了基本语法,掌握了基本的数据结构,也见过了不少微软提供 ...
- C语言实现扫雷小游戏 纯小白 非黑窗口
C语言实现一个普通的扫雷小游戏 纯小白所编(含代码非黑窗口!) 扫雷 主要功能 1.创建一个图形界面 2.了解扫雷游戏的原理 3.随机生成雷的位置 4.为整个数组加密,并在雷周围的位置加一 5.导入图 ...
- 用c语言实现扫雷小游戏。
相信小伙伴在学习c语言的时候想做一些小趣事,下面就是用c语言来实现一个扫雷小游戏,不过是简单的实现扫雷(只是通过数组的方式来实现),适合新手学习. 我用的是vs敲的这个代码,大家可以用vs运行(可能有 ...
- c语言字符游动程序,C语言实现扫雷小游戏详解
本文实例为大家分享了C语言实现扫雷小游戏的具体代码,供大家参考,具体内容如下 一.实现功能 首先显示一个小菜单,选择是否玩游戏.当用户选择退出时,程序运行结束,当用户选择玩游戏时,将提示用户输入扫雷位 ...
- JS扫雷小游戏(DOM (html+css+js))
一:效果图: 二:资源 js扫雷小游戏源代码下载地址 js贪吃蛇小游戏链接 python小黄脸大战小游戏链接 vue高仿网易云音乐app 三:源代码: html部分: <!DOCTYPE htm ...
最新文章
- php与nginx链接,Nginx与PHP的交互
- 大数运算(5)——大数除法(取模、取余)
- poj 2516(最小费用最大流)
- document.getElementById() 的作用
- android如何局域网通信,android局域网怎么通信
- unity球体添加光源_Unity 3D光源-Point Light点光源详解/灯泡、模拟灯光效果教程
- storm风暴英雄 tempo_《风暴英雄》Tempo Storm天梯环境速报
- pythonai人脸识别_AI的强大!用Python实现一个简单的人脸识别
- android 停止服务方法,Android编程实现开始及停止service的方法
- 拍卖程序员,100offer这样的程序员招聘方式靠谱吗
- draft伦理——第七章
- 重装Win10系统其他盘的东西还在吗?
- 网络层提供的两种服务
- JS 对象直接量方法创建对象
- 自动化爬取淘宝数据--(保存到文本中)
- WINCE6.0下载地址
- ROS2机器人操作系统简介2021英文字幕版本
- 基于Xposed框架截取安卓手机应用数据信息
- Shiro 第十七章 OAuth2集成
- 《动态规划》— 动态规划分类