Vue2+JS实现扫雷小游戏

目录
  • 实现步骤
    • 1、场景布局实现
    • 2、初始化事件
    • 3、游戏动作(action)
    • 游戏收尾
  • 总结

实现步骤

1、场景布局实现

布局就是经典的方格布局,对于场景的美观度可以自行找几个配色网站作为参考。

出现问题: 先初始化一个二维数组对应方块坐标,然后依次渲染 or 直接通过预期的行、列数渲染空白方块

区别: 直接初始化二维数组,可以对坐标进行一些属性操作,例如标记、是否为地雷等等,之后操作的时候会方便很多,缺点在初始化的时候需要进行大量的计算工作(因为在点开一个安全坐标时需要显示周围的地雷个数,还要考虑边缘情况),而渲染空白方块就可以在点击坐标的时候再去做计算,并且在点击的时候只需要计算该方块的属性。

这里我选择了渲染空白方块的形式。

代码实现

使用了 element-ui组件

template

<div class="layout">
  <div class="row" v-for="row in layoutConfig.row" :key="row">
    <div
      class="cell"
      :style="{ width:  edgeLength, height: edgeLength }"
      v-for="col in layoutConfig.cell"
      :key="col">
      <div
        class="block"
        @click="open(row, col, $event)"
        @contextmenu.prevent="sign(row, col, $event)"
      >
        // 这里的逻辑现在可以暂时不用管,只需要先做好布局
        <template v-if="areaSign[`${row}-${col}`] === 'fail'">
          <img src="../../assets/svg/fail.svg" alt="">
        </template>
        <template v-else-if="areaSign[`${row}-${col}`] === 'tag'">
          <img src="../../assets/svg/Flag.svg" alt="">
        </template>
        <template v-else-if="areaSign[`${row}-${col}`] === 'normal'">
        </template>
        <template v-else>
          {{areaSign[`${row}-${col}`]}}
        </template>
      </div>
    </div>
  </div>
</div>

style:

<style scoped lang="less">
.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;
        }
      }
    }
  }
}
</style>

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: Object  key: 坐标('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 = false
   this.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 = true
  this.areaSign = {}
  this.mineList = []
  this.resetOpenedClass()
  // 初始化游戏
  this.initMineListRange()
},
// 将class = "opened" 的元素改回 "block" 状态
resetOpenedClass () {
  document.querySelectorAll('.opened').forEach(node => {
    node.className = 'block'
  })
}

总结

扫雷的实现并不复杂,首先需要对扫雷这个游戏的机制有思路,并且可以将一些逻辑捋清楚就可以了,实现的时候再将一些边缘状态考虑一下。可以更多关注一下对于代码的封装,对于代码的提炼很重要,这样在之后继续开发或者需要修改的时候很容易上手。

以上就是Vue2+JS实现扫雷小游戏的详细内容,更多关于Vue扫雷游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vue实现五子棋小游戏

    本文实例为大家分享了Vue实现五子棋小游戏的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html> <head>     <meta charset="utf-8">     <title>五子棋</title>     <script src="./configJS/vue.js"></script>     <script src=&q

  • VUE+Canvas实现财神爷接元宝小游戏

    之前的canvas小游戏系列欢迎大家戳: <VUE实现一个Flappy Bird~~~> <猜单词游戏> <VUE+Canvas 实现桌面弹球消砖块小游戏> <VUE+Canvas实现雷霆战机打字类小游戏> 如标题,这个游戏大家也玩过,随处可见,左右方向键控制财神移动,接住从天而降的金元宝等,时间一到,则游戏结束.先来看一下效果: 相比于之前的雷霆战机要打出四处飞的子弹,这次元素的运动轨迹就很单一了,垂直方向的珠宝和水平移动的财神爷,类似于之前的代码,这里就

  • 基于Vue uniapp实现贪吃蛇游戏

    目录 游戏演示 代码结构 渲染蛇身 控制蛇的方向 游戏演示 代码结构 详细代码结构如果需要请到github查看 <template> <view ref="body" class="content"> <view>蛇蛇目前:{{snakes.length}}米长</view> <view class="game-field"> <!-- 地面板块 --> <view c

  • vue实现打地鼠小游戏

    本文实例为大家分享了vue实现打地鼠小游戏的具体代码,供大家参考,具体内容如下 效果图如下: 代码如下: <template> <div class="game"> <h2>打地鼠游戏</h2> <div class="wraper"> <div class="item" v-for="n in TOTAL" :key="n"> <

  • vue+canvas实现拼图小游戏

    利用 vue+canvas 实现拼图小游戏,供大家参考,具体内容如下 思路步骤 一个拼图拼盘和一个原图参照 对原图的切割以及随机排序 通过W/A/D/S或上下左右进行移动 难度的自主选择 对拼图是否完成的判定 JS实现部分 数据分析 row:拼图的总行数:column:拼图的总列数. (用来设置拼图难度,也是每个拼图块宽高的设置规则) pic[{x,y,row,column,index}]:小拼图的集合,其内元素为小拼图的数据结构. (x.y:拼图块在canvas的绘制规则,初始化后不会进行改变

  • 阿望教你用vue写扫雷小游戏

    前言 话说阿望还在大学时,某一天寝室突然停网了,于是和室友两人不约而同地打开了扫雷,比相同难度下谁更快找出全部的雷,玩得不亦乐乎,就这样,扫雷伴我们度过了断网的一周,是整整一周啊,不用上课的那种,可想而知我们是有多无聊了. 这两天临近过年了,该放假的已经放假了,不该放假的已经请假了,公交不打挤了,地铁口不堵了,公司也去了大半部分的人了,就留阿望这种不得不留下来值班的人守着空荡荡的办公室了,于是,多年前那种无所事事的断网心态再次袭来,于是,想玩扫雷的心再次蹦跶出来,于是,点开了电脑的附件,于是,发

  • 基于Vue3制作简单的消消乐游戏

    目录 游戏介绍 核心思路 核心代码 html js 游戏开始/循环 删除 下落 添加 生成矩阵/数据 点击 换位置 游戏介绍 先看一下 好吧,我知道界面有点丑 →_→ 核心思路 游戏步骤主要就是:消除.下落.补充.移动,采用三种状态来区分需要删除的(remove).新添加的(add).和正常的方块(normal) 主要就是生成小方块列表后,马上保存每一个方块上下左右方块的信息 然后判断每一个方块和上下或和左右类型相同即为需要消除,并把该方块状态改为 remove 然后通过定位改变 top 来控制

  • Vue2+JS实现扫雷小游戏

    目录 实现步骤 1.场景布局实现 2.初始化事件 3.游戏动作(action) 游戏收尾 总结 实现步骤 1.场景布局实现 布局就是经典的方格布局,对于场景的美观度可以自行找几个配色网站作为参考. 出现问题: 先初始化一个二维数组对应方块坐标,然后依次渲染 or 直接通过预期的行.列数渲染空白方块 区别: 直接初始化二维数组,可以对坐标进行一些属性操作,例如标记.是否为地雷等等,之后操作的时候会方便很多,缺点在初始化的时候需要进行大量的计算工作(因为在点开一个安全坐标时需要显示周围的地雷个数,还

  • 分享自己用JS做的扫雷小游戏

    引用了jQuery,节省了很多鼠标点击上的判断.界面显然都是照搬Windows的扫雷啦,详细的内容注释里都有,我就不啰嗦啦~ 先上截图~ 引用了jQuery,节省了很多鼠标点击上的判断 界面显然都是照搬Windows的扫雷啦 详细的内容注释里都有,我就不啰嗦啦~ JS部分 var mineArray, //地雷数组 lastNum, //剩余雷数 countNum, //未被揭开的方块数 inGame = 0, //游戏状态,0为结束,1为进行中,2为初始化完毕但未开始 startTime; /

  • js+canvas实现简单扫雷小游戏

    扫雷小游戏作为windows自带的一个小游戏,受到很多人的喜爱,今天我们就来尝试使用h5的canvas结合js来实现这个小游戏. 要写游戏,首先要明确游戏的规则,扫雷游戏是一个用鼠标操作的游戏,通过点击方块,根据方块的数字推算雷的位置,标记出所有的雷,打开所有的方块,即游戏成功,若点错雷的位置或标记雷错误,则游戏失败. 具体的游戏操作如下 1.可以通过鼠标左键打开隐藏的方块,打开后若不是雷,则会向四个方向扩展 2.可以通过鼠标右键点击未打开的方块来标记雷,第二次点击取消标记 3.可以通过鼠标右键

  • jQuery实现扫雷小游戏

    本文实例为大家分享了jQuery实现扫雷小游戏的具体代码,供大家参考,具体内容如下 扫雷小游戏实现思路: 设计为9*9简单面板,每次随机生成10颗雷,然后计算每颗雷周围八个位置上每个位置应该标记的数字(该数字表示此位置周围八个位置上存在雷的数量),基本原理大致如此.交互问题以简单的方式实现即可. <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ut

  • JavaScript实现扫雷小游戏

    本文实例为大家分享了JavaScript实现扫雷小游戏的具体代码,供大家参考,具体内容如下 先说大体思路,下面放代码 思路: 1产生指定数量的地雷2计算方块周围的地雷3点击地雷结束4点击地雷周边显示地雷个数5点击空白块,消除所有相连的空白块6游戏主体已经完成了.剩下就是完善一些小细节,例如胜利判断 ,失败露出苦瓜脸 ,难度切换,新游戏按钮 等等… 首先是html+css的代码 <!DOCTYPE html> <html> <head>   <meta charse

  • js仿3366小游戏选字游戏

    本文实例为大家分享了js仿3366小游戏中"你是色盲吗"游戏,大家先来挑战一下 游戏目标: 按画面中出现的文字的颜色来选择颜色,千万不要被颜色的困局打扰,眼睛一定要放亮哦,游戏开始时会有10分,每答对一题得一分,总共有10分,时间用完游戏会结束. 操作说明: 鼠标点击选择颜色 1.效果图: 原图: 模仿: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8">

  • Android 实现扫雷小游戏实例代码

    Android 实现扫雷小游戏实例 最近学习Android 应用编程,抽空做个小应用,大家熟悉的扫雷应用,练手用, 以下是实现代码: MainActivity 类 public class MainActivity extends Activity implements OnClickListener, OnLongClickListener { // 最外层布局 LinearLayout textviews; LinearLayout buttons; int[][] map = new in

  • HTML+JavaScript实现扫雷小游戏

    本文实例为大家分享了JavaScript实现扫雷小游戏的具体代码,供大家参考,具体内容如下 工具:Sublime Text / Dreamweaver /Hbuilder <!doctype html> <html> <head> <meta charset="utf-8"> <title>SaoLei</title> <style type="text/css"> table {

  • C语言实现简单扫雷小游戏

    本文实例为大家分享了C语言实现扫雷小游戏的具体代码,供大家参考,具体内容如下 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <windows.h> #include <time.h> /* 用 C 语言写一个简单的扫雷游戏 */ // 1.写一个游戏菜单 Menu() // 2.开始游戏 // 1.初始化二维数组 Init_Interface() // 2.打印游戏界面 Print_Interfa

随机推荐