该组件中只有一个方法:选择难度之后,跳转到游戏主界面上去,因为项目没有用路由,直接使用组件间的切换,所以,这个方法只负责告诉父组件,我已经选择好难度了,可以开始游戏了
// 选择难度 handleChoseLevel(level) { this.$emit("chose-level", level); }
代码如下:
界面长这样,当然,你要觉得难看自己换个样式也行
游戏界面
画格盘
通过游戏难度选择来决定游戏格盘的大小,组件间已通过App将游戏难度传至界面组件中,我们用props把数据接收到,消化成自己的数据,画格盘需要的数据有:横排格子数,纵排格子数
画格子:我们将格子的索引暴露出来,后续可以帮助我们试错。整个格局有两种方式来表示格盘,坐标式和索引式,比如横9纵9的格子,[0, 0]代表第1个格子,[2, 3]代表第三行第四列也就是第20个格子。此次使用索引式来标志格盘
<div v-for="col in cols" :key="Math.random() + col"> <span v-for="row in rows" :key="Math.random() + row"> <span></span> </span> </div>
随机生成地雷
首先data中添加一个minePosition属性,用来记录雷点位置
随机生成地雷比较简单,主要注意,生成的地雷点数在格盘个数范围内,那么就可以写出随机生成的地雷了。界面组件已收集到横排格子数、纵排格子数、雷数,那么就能得到格子总数,假设横9纵9,10个雷,那么就是生成10个81以内的随机数(如果索引从0开始,即80以内)。
// 随机获取雷点位置 getMinePosition() { // 定义一个数组装不重复的格点 let mineArr = []; // 循环雷数生成不重复的雷点 for (let n = 0; n < this.gameInfo[2]; n++) { const random = Math.floor(Math.random() * this.latticeNum); if (mineArr.indexOf(random) === -1) { mineArr.push(random); } else { n--; } } this.minePosition = mineArr; },
把地雷位置暴露出来
格子周围的雷数
确认了雷点位置,接下来要做的就是确认每一个非雷点位置周围的雷的数量,我们用对象来描述一个格子,这个对象主要包含以下几个属性
// 格子属性 lattice: [{ index: 0, // 格子索引 mineNum: 0, // 周围雷数 isMine: false, // 是否是雷 isOpen: false, // 是否已经被点开 isMark: false, // 是否被标记 }],
这里我们主要用到index, isMine, mineNum属性,这一步,主要是计算每个格子元素的mineNum值,依赖于以下两个方法,个人觉得扫雷游戏最难理解的,最难捋清的逻辑,其中一个就是获取非雷点位置周围8个位置索引的方法getLatticeIndex(另一个是点击空白格扩散)
// 获取格子周围的雷数, getMineNumAroundLattice(lattice, index) { // 先获取格子周围的有效索引 const latticeIndexArr = this.getLatticeIndex(index); // 循环索引,索引值在雷点数组中的,即为雷,当前格子的雷点数加1 latticeIndexArr.forEach(i => { if (this.minePosition.indexOf(i) > -1) { lattice.mineNum ++; } }); }, // 获取格子周围的有效索引 getLatticeIndex(index) { // 存索引值的变量 let latticeIndexArr = []; // 当前格子位于第几行 const latticeRow = Math.ceil(index / this.rows); // 当前格子位于第几列(求余为0说明是最右边一列) const latticeCol = Math.ceil(index % this.rows) || this.rows; // 第一行没有上一行,不需要计算减1的行值,最后一行没有下一行,不需要计算加1的行值 for (let i = (latticeRow === 1 ? 0 : -1); i < (latticeRow === this.cols ? 1 : 2); i++) { // 第一列没有左列,不需要计算减1的列值,最后一列没有右列,不需要计算加1的列值 for (let j = (latticeCol === 1 ? 0 : -1); j < (latticeCol === this.rows ? 1 : 2); j++) { // 索引值 = (当前行值 + (上一行【-1】/当前行【0】/下一行【+1】) - 1【1是索引从0开始,所以需要减去】) * 每行格子数 + 当前列值 + (上一列【-1】/当前列【0】/下一列【+1】) const latticeIndex = (latticeRow + i - 1) * this.rows + (latticeCol + j); latticeIndexArr.push(latticeIndex); } } return latticeIndexArr; },
有了这两个方法,咱成功地获取到了每个非雷点格子周围的雷的数量,来,展示出来,这样展示的好处是,我们一眼就可以看出算法是否正确
没问题了,来,接着往下走,格盘数据基本都设置好了,那我们接下来要做的就是,点开格子操作
点击交互