热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微信小程序实现经典window扫雷游戏

这篇文章主要为大家详细介绍了微信小程序实现经典window扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

打开手机游戏列表发现了一款经典的扫雷游戏,在玩的过程中发现游戏逻辑应该不难,想着是不是能自己写写这个游戏,后来用了1天实现了整体游戏开发,于是有了这篇文章来总结整体的游戏开发思路。

一、扫雷游戏规则是什么?

1、游戏为在10*10或其它排序组合网格中找雷
2、网格中隐藏着一定数量的雷,点击到雷即为输
3、点击无雷的网格会显示其临近8个方向上的总雷数,若为0则临近8个方向上的网格也会自动显示雷数,以此类推,直到出现不为0的网格
4、长按网格可以标记网格为雷
5、找出所有的雷即为胜利

二、开发前准备

1.创建小程序项目

使用微信开发者工具创建一个小程序项目。推荐使用官方推荐模板(此游戏项目使用js来实现)

2.开始开发

2.1.实现网格地图

页面初始数据:

groundSize: [16, 16], // 地图大小
minePosition: [], // 保存雷的位置
secondInterval: 0, // 时间定时器
data: {
  second: 0, // 游戏时间
  mineCount: 24, // 雷总数
  markMineCount: 0, // 已标记雷数
  renderGridList: [], // 网格列表
},

此地图为16*16的地图,行列大小根据 groundSize 来,后续可以设置不同的地图大小。

地图wxml代码(具体样式自行规划):


  
     
       
       
       
       
       
       {{col.mineNum}}
     
   

renderGridList 渲染列表结构(二维数组):

[
  [
    {
      isMine: false, // 是否为雷
      mineTag: false, // 手动添加是否是雷的标识
      isBoom: false, // 是否点击到了雷
      mineNum: 0, // 周围雷数
      showNum: false, // 是否显示雷数
      value: 0, // 等同于id
      position: [0, 0], // 标志在第几行第几列
    },
    ...
  ],
  ...
]

初始化网格方法:

initGrid() {
  const gridList = [];
   // 当前遍历gridList到第几个元素
   let currentNum = 0;
   // 当前遍历minePosition到第几个元素
   let currentMineIndex = 0;
   for (let i = 0; i 

2.2.生成雷

generateMine() {
   this.minePosition = [];
   // 已设置的雷总数
   let hadSetCount = 0;
   // 随机最大值根据网格大小来
   const groundCount = this.groundSize[0] * this.groundSize[1];
   if (this.data.mineCount >= groundCount) {
      return;
    }
    while (hadSetCount  (a > b ? 1 : -1));
  }

根据页面初始数据中的 mineCount 来指定生成的雷数,通过随机值函数来生产随机的雷的 value 值,每生成一个先判断值是否在 minePosition 数组存在,不存在就push到 minePosition 数组中去。最终结果如下:在 initGrid 方法中会根据 minePosition 对应的值和网格的value值作比较,相等即为雷。

minePosition (24) [10, 17, 25, 28, 34, 35, 48, 73, 106, 132, 152, 187, 196, 197, 199, 203, 210, 217, 220, 226, 234, 238, 240, 245]

2.3.生成雷数

generateMineNum(gridList) {
 gridList.forEach(row => {
    row.forEach(col => {
      // 是雷则跳过
      if (col.isMine) {
        return;
      }
      col.mineNum = this.checkMine(gridList, col.position);
    });
  });
  return gridList;
},
checkMine(gridList, position) {
  const [i, j] = position;
  let mineNum = 0;
  // 判断8个方位是否有雷
  // 上 [i - 1][j]
  if (gridList[i - 1] && gridList[i - 1][j].isMine) {
    mineNum += 1;
  }
  // 右上 [i - 1][j + 1]
  if (gridList[i - 1] && gridList[i - 1][j + 1] && gridList[i - 1][j + 1].isMine) {
    mineNum += 1;
  }
  // 右 [i][j + 1]
  if (gridList[i][j + 1] && gridList[i][j + 1].isMine) {
    mineNum += 1;
  }
  // 右下 [i + 1][j + 1]
  if (gridList[i + 1] && gridList[i + 1][j + 1] && gridList[i + 1][j + 1].isMine) {
    mineNum += 1;
  }
  // 下 [i + 1][j]
  if (gridList[i + 1] && gridList[i + 1][j].isMine) {
    mineNum += 1;
  }
  // 左下 [i + 1][j - 1]
  if (gridList[i + 1] && gridList[i + 1][j - 1] && gridList[i + 1][j - 1].isMine) {
    mineNum += 1;
  }
  // 左 [i][j - 1]
  if (gridList[i][j - 1] && gridList[i][j - 1].isMine) {
    mineNum += 1;
  }
  // 左上 [i - 1][j - 1]
  if (gridList[i - 1] && gridList[i - 1][j - 1] && gridList[i - 1][j - 1].isMine) {
    mineNum += 1;
  }
  return mineNum;
}

判断8个方向上是否有雷时我们需要注意那些在边角的网格,这些网格方向少于8个,所以我们在做判断是需先判断其方向上是否有网格才行。

2.4.长按添加雷的标识

setMineTag(e) {
  const {
    currentTarget: {
      dataset: { value },
    },
  } = e;
  const renderGridList = this.data.renderGridList;
  let markMineCount = 0;
  for (const row of renderGridList) {
    for (const col of row) {
      if (col.value === value) {
        col.mineTag = !col.mineTag;
      }
      if (col.mineTag) {
        markMineCount += 1;
      }
    }
  }
  this.setData({
    renderGridList,
    markMineCount,
  });
},

我们在网格上设置 data-value ,这样长按事件就能获取对应的 value 值,通过遍历比较找到对应的网格并对网格的 mineTag 属性取反来达到长按标记或取消的功能,同时 mineTag 为真时需记录下标记数量。

2.5.点击网格事件

clearBox(e) {
  const {
    currentTarget: {
      dataset: { value },
    },
  } = e;
  let renderGridList = this.data.renderGridList;
  out: for (const row of renderGridList) {
    for (const col of row) {
      if (col.value === value) {
        // 判断是否是雷,为雷则输
        col.isBoom = col.isMine;
        if (col.isBoom) {
          wx.showToast({
            icon: 'error',
            title: '踩到雷了',
          });
          break out;
        }
        renderGridList = this.loopClearBox(renderGridList, col);
        break out;
      }
    }
  }
  this.setData({
    renderGridList,
  });
},
loopClearBox(gridList, col) {
  if (col.isMine || col.showNum) {
    return gridList;
  }
  col.showNum = true;
  if (col.mineNum) {
    return gridList;
  }
  // 判断相邻的4个方位是否为空并递归遍历
  const [i, j] = col.position;
  if (gridList[i - 1]) {
      // 上
    col = gridList[i - 1][j];
    if (col) {
      if (!col.mineNum) {
        gridList = this.loopClearBox(gridList, col);
      } else {
        col.showNum = !col.isMine;
      }
    }
  }
  if (gridList[i + 1]) {
      // 下
    col = gridList[i + 1][j];
    if (col) {
      if (!col.mineNum) {
        gridList = this.loopClearBox(gridList, col);
      } else {
        col.showNum = !col.isMine;
      }
    }
  }
  // 左
  col = gridList[i][j - 1];
  if (col) {
    if (!col.mineNum) {
      gridList = this.loopClearBox(gridList, col);
    } else {
      col.showNum = !col.isMine;
    }
  }
  // 右
  col = gridList[i][j + 1];
  if (col) {
    if (!col.mineNum) {
      gridList = this.loopClearBox(gridList, col);
    } else {
      col.showNum = !col.isMine;
    }
  }
  return gridList;
}

loopClearBox 是递归遍历方法,当点击的网格的周围雷数为空时我们需要递归其上下左右方向的网格。效果如图所示:

递归只有遇到有雷数的网格才会停下。

2.6.输赢判断

checkWin() {
  // 当标记数小于总雷数时才判断输赢
  if (this.data.mineCount >= this.data.markMineCount) {
    // 遍历网格判断标记的雷是否正确
    for (let row in this.data.renderGridList) {
      for (let col of row) {
        if (col.isMine !== col.mineTag) {
          return false;
        }
      }
    }
    return true;
  }
  return false;
}

输赢判断是在点击网格事件中执行的,当返回值为true时即为通关。

总结

以上就是整个游戏开发的整体思路讲解,代码量不多,总体js代码只有2百多行,设计思路也比较简单。对于在开发中的收获,或许就是当你玩着自己开发的游戏时,作为程序员的快乐。

希望这篇文章对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文主要介绍关于微信小程序,小程序,今日头条,新闻,前端的知识点,对【仿今日头条实时新闻微信小程序项目源码】和【自己怎么弄微信小程序】有兴趣的朋友可以看下由【叶绿体不忘呼吸】投稿的技术文章,希望该技术 ... [详细]
  • 微信小程序地图实现展示线路的方法
    这篇文章将为大家详细讲解有关微信小程序地图实现展示线路的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • 本文介绍了腾讯最近开源的BERT推理模型TurboTransformers,该模型在推理速度上比PyTorch快1~4倍。TurboTransformers采用了分层设计的思想,通过简化问题和加速开发,实现了快速推理能力。同时,文章还探讨了PyTorch在中间层延迟和深度神经网络中存在的问题,并提出了合并计算的解决方案。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
  • 花瓣|目标值_Compose 动画边学边做夏日彩虹
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Compose动画边学边做-夏日彩虹相关的知识,希望对你有一定的参考价值。引言Comp ... [详细]
  • 校园表白墙微信小程序,校园小情书、告白墙、论坛,大学表白墙搭建教程
    小程序的名字必须和你微信注册的名称一模一样在后台注册好小程序。mp.wx-union.cn后台域名https。mp.wx-union.cn ... [详细]
  • 百度地图   绘制东莞东城地图示例
    先上图:index.html ... [详细]
  • 微信小程序中如何实现轮播图
    这篇文章主要介绍了微信小程序中如何实现轮播图,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带 ... [详细]
  • 微信小程序实现星级评分与展示
    这篇文章主要为大家详细介绍了微信小程序实现星级评分与展示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的 ... [详细]
  • 微信小程序学习笔记-3-问题
    一些在开发微信小程序中常见的问题页面渲染  微信小程序中规定所有页面上渲染出来的数据,包括文字和图片皆包含在在每个页面文件夹中的js文件中的page这个内置函数的参数data中, ... [详细]
  • 微信小程序下拉触发onPullDownRefresh函数调用,但是问题在这里面的实现并没有生效。原因:微信小程序默认不支持下拉也就是说想要支持下拉刷新的功能,还必须得要在app.jso ... [详细]
author-avatar
王晓宁smile
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有