Vue2+JS实现扫雷小游戏
目录
- 实现步骤
- 1、场景布局实现
- 2、初始化事件
- 3、游戏动作(action)
- 游戏收尾
- 总结
实现步骤
1、场景布局实现
布局就是经典的方格布局,对于场景的美观度可以自行找几个配色网站作为参考。
出现问题: 先初始化一个二维数组对应方块坐标,然后依次渲染
or
直接通过预期的行、列数渲染空白方块区别: 直接初始化二维数组,可以对坐标进行一些属性操作,例如标记、是否为地雷等等,之后操作的时候会方便很多,缺点在初始化的时候需要进行大量的计算工作(因为在点开一个安全坐标时需要显示周围的地雷个数,还要考虑边缘情况),而渲染空白方块就可以在点击坐标的时候再去做计算,并且在点击的时候只需要计算该方块的属性。
这里我选择了渲染空白方块的形式。
【Vue2+JS实现扫雷小游戏】代码实现
使用了 element-ui组件
template
// 这里的逻辑现在可以暂时不用管,只需要先做好布局
文章图片
文章图片
{{areaSign[`${row}-${col}`]}}
style:
.container {display: flex; justify-content: center; align-items: center; flex-direction: column; margin-top: 100px; .typeChoose {display: flex; justify-content: center; align-items: center; width: 100%; margin-bottom: 20px; .item {margin: 0 10px; }}.layout {width: 500px; height: 500px; .row {display: flex; justify-content: center; align-items: center; .cell {border: 1px solid #735E30; caret-color: transparent; cursor: pointer; line-height: 50px; .block {height: 100%; background: #292E17; }.block:hover {background: #96875F; }.opened {height: 100%; background: #E8E0D8; }}}}}
2、初始化事件
生成地雷随机二维数组
因为布局已经通过空白方块生成了,所以我们只需要关心生成随机的地雷坐标就可以了
代码实现:
/* *type: 当前模式的地雷个数(自己定义数量) *mineList: 地雷坐标数组 *layoutConfig: { *row: 布局的行数 *col: 布局的列数 *} */// 生成随机地雷坐标数组initMineListRange () {while (this.mineList.length < this.type) {this.initMineItem()}},// 生成单个地雷坐标并且放入地雷坐标数组(mineList)中initMineItem () {const position = this.initPositionRange([1, this.layoutConfig.row], [1, this.layoutConfig.cell])if (!this.hasPositionIn(position, this.mineList)) {this.mineList.push(position)}},// 生成一个在给定范围内的随机坐标initPositionRange ([xStart, xEnd], [yStart, yEnd]) {return [this.numRange(xStart, xEnd), this.numRange(yStart, yEnd)]},// 生成一个在给定范围内的随机整数numRange (start, end) {return Math.floor((Math.random() * (end - start + 1))) + start},// 判断参数中的 position 是否已经存在与 参数中的 positionList 中hasPositionIn (position, positionList) {console.assert(position.length === 2, 'position length < 2, not a position item')return positionList.some(p => {return p[0] === position[0] && p[1] === position[1]})}
3、游戏动作(action)
指的是游戏中的一些操作以及某个操作导致的一系列变化
点击方块
分析:点击方块之后会出现三种情况
- 该方块的九宫格范围内没有地雷
- 该方块的九宫格方位内有地雷
- 踩雷了(game over)
第一种情况:(方块的九宫格范围内没有地雷)
这种情况只需要将该方块的样式改为点击过的样式即可(
class="opened"
)第二种情况:(方块的九宫格方位内有地雷)
修改样式为
opened
,并且需要计算周围的地雷数量(需要考虑边缘情况,即当前坐标是否在边缘)第三种情况:(踩雷)
修改样式为
opened
, 并且展示地雷,提示用户游戏结束代码实现
因为在点击之前该方块是空白对象,所以需要一个对象来存储该方块的属性或者状态(
areaSign
)/**areaSign: Objectkey: 坐标('1-2') value: 状态*gameProcess:当前游戏是否处于进行状态*statusEnum: 枚举 方块状态枚举值(fail,normal,tag)*/// 方块点击事件 (传入坐标以及点击事件对象) open (rowIndex, colIndex, e) {// 判断当前游戏是否 if (!this.gameProcess) {this.gameEndConfirm()return}// 判断当前坐标是否被标记,被标记则不能被点开if (this.getAreaSignValueWithPosition(rowIndex, colIndex) === statusEnum.tag) {this.confirmMessageBox('该区域已经被标记,请选择其他区域点击')return}e.target.className = 'opened'if (this.hasTouchMine([rowIndex, colIndex])) {// 踩雷this.mineTouched([rowIndex, colIndex])} else {// 第一、二种情况this.safeTouched([rowIndex, colIndex])} }, // 通过传入的坐标判断是否存在地雷坐标数组中 hasTouchMine ([xPosition, yPosition]) {return this.hasPositionIn([xPosition, yPosition], this.mineList) }, mineTouched (position) {this.setSvg(position, statusEnum.fail)// 游戏失败提示this.gameProcess = falsethis.gameEndConfirm() }, safeTouched (position) {this.setTips(position) }, // 把传入坐标通过判断是否有雷设置对应提示 setTips (position) {const total = this.positionAroundMineTotal(position)this.$set(this.areaSign, `${position[0]}-${position[1]}`, total || '') }, // 把传入坐标设置为对应状态的svg图标 setSvg (position, type) {this.$set(this.areaSign, `${position[0]}-${position[1]}`, type) }, // 传入坐标与地雷坐标数组判断是否其周围存在雷 positionAroundMineTotal (position) {const aroundPositionList = this.getAroundPosition(position[0], position[1])return aroundPositionList.filter(item => this.hasTouchMine(item)).length }, // 获取传入坐标的周围九宫格坐标 getAroundPosition (xPosition, yPosition) {const aroundPositionList = [[xPosition - 1, yPosition - 1],[xPosition - 1, yPosition],[xPosition - 1, yPosition + 1],[xPosition, yPosition - 1],[xPosition, yPosition + 1],[xPosition + 1, yPosition - 1],[xPosition + 1, yPosition],[xPosition + 1, yPosition + 1]]return aroundPositionList.filter(position => isInRange(position[0]) && isInRange(position[1]))// 判断传入数字是否在对应范围中function isInRange (num, range = [1, 10]) {return num >= range[0] && num <= range[1]} }
标记坐标
左键为点击方块,右键为标记坐标(第二次点击为取消标记),当该坐标为标记的时候,无法进行点击,并且当刚好标记的坐标数组和地雷数组一样时,则游戏结束,玩家胜利
代码实现
/**hasWin 见下文的 vue computed*/sign (rowIndex, colIndex, e) {// 判断游戏当前状态if (!this.gameProcess) {this.gameEndConfirm()return}if (this.getAreaSignValueWithPosition(rowIndex, colIndex) === undefined ||this.getAreaSignValueWithPosition(rowIndex, colIndex) === statusEnum.normal) {// 当前坐标 为被标记过或者以及被取消标记 触发:添加标记this.setSvg([rowIndex, colIndex], statusEnum.tag)} else if (this.getAreaSignValueWithPosition(rowIndex, colIndex) === statusEnum.tag) {// 当前坐标 被标记 触发:取消标记this.setSvg([rowIndex, colIndex], statusEnum.normal)}console.log(this.tagList, this.mineList)// 检测游戏是否结束this.gameInspector()},// 游戏提示gameEndConfirm () {const message = this.hasWin ? '恭喜你通关,是否继续?' : '游戏失败,是否重新开始?'this.confirmMessageBox(message, {callback: () => {this.resetGame()},cancelCallback: () => {}}, 'confirm')},// 游戏状态检测员(判断当前游戏是否结束)gameInspector () {if (this.hasWin) {this.gameEndConfirm()}},// 通过传入坐标返回对应格式的字符串(areaSign的key值)getAreaSignAttrWithPosition (xPosition, yPosition) {return `${xPosition}-${yPosition}`},// 通过传入坐标返回areaSign的value值(获取该坐标的状态)getAreaSignValueWithPosition (xPosition, yPosition) {return this.areaSign[this.getAreaSignAttrWithPosition(xPosition, yPosition)]}
// 被标记列表tagList () {return Object.keys(this.areaSign).filter(item => this.areaSign[item] === 'tag').map(attrStr => attrStr.split('-').map(str => parseInt(str)))},// 判断所有的地雷是否已经被标记hasSignAllMine () {return this.tagList.length === this.mineList.length &&this.tagList.every(tagPosition => this.hasPositionIn(tagPosition, this.mineList))},// 游戏是否胜利hasWin () {return this.hasSignAllMine}
游戏收尾
游戏失败或者胜利的时候需要重置游戏
代码实现
resetGame () {this.gameProcess = truethis.areaSign = {}this.mineList = []this.resetOpenedClass()// 初始化游戏this.initMineListRange()},// 将class = "opened" 的元素改回 "block" 状态resetOpenedClass () {document.querySelectorAll('.opened').forEach(node => {node.className = 'block'})}
总结 扫雷的实现并不复杂,首先需要对扫雷这个游戏的机制有思路,并且可以将一些逻辑捋清楚就可以了,实现的时候再将一些边缘状态考虑一下。可以更多关注一下对于代码的封装,对于代码的提炼很重要,这样在之后继续开发或者需要修改的时候很容易上手。
以上就是Vue2+JS实现扫雷小游戏的详细内容,更多关于Vue扫雷游戏的资料请关注脚本之家其它相关文章!
推荐阅读
- 基于PHP实现微博热搜实时监控平台
- c++实现md5加密的代码
- 分布式框架实现基础之IO技术 - Netty框架
- springboot|SpringBoot集成JWT实现token验证
- C语言实现简单的通讯录管理系统
- C语言实现简易通讯录实例
- C语言代码实现通讯录管理系统
- C语言实现通讯录系统程序
- 「Node学习笔记」Node.js的模块实现及编译
- 昨天面试被问到的 缓存淘汰算法FIFOLRULFU及Java实现