热门标签 | 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百多行,设计思路也比较简单。对于在开发中的收获,或许就是当你玩着自己开发的游戏时,作为程序员的快乐。

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


推荐阅读
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 出库管理 | 零件设计中的状态模式学习心得与应用分析
    出库管理 | 零件设计中的状态模式学习心得与应用分析 ... [详细]
  • 在Java基础中,私有静态内部类是一种常见的设计模式,主要用于防止外部类的直接调用或实例化。这种内部类仅服务于其所属的外部类,确保了代码的封装性和安全性。通过分析JDK源码,我们可以发现许多常用类中都包含了私有静态内部类,这些内部类虽然功能强大,但其复杂性往往让人感到困惑。本文将深入探讨私有静态内部类的作用、实现方式及其在实际开发中的应用,帮助读者更好地理解和使用这一重要的编程技巧。 ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 分享一款基于Java开发的经典贪吃蛇游戏实现
    本文介绍了一款使用Java语言开发的经典贪吃蛇游戏的实现。游戏主要由两个核心类组成:`GameFrame` 和 `GamePanel`。`GameFrame` 类负责设置游戏窗口的标题、关闭按钮以及是否允许调整窗口大小,并初始化数据模型以支持绘制操作。`GamePanel` 类则负责管理游戏中的蛇和苹果的逻辑与渲染,确保游戏的流畅运行和良好的用户体验。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 检查在所有可能的“?”替换中,给定的二进制字符串中是否出现子字符串“10”带 1 或 0 ... [详细]
  • 在 Java 中,`join()` 方法用于使当前线程暂停,直到指定的线程执行完毕后再继续执行。此外,`join(long millis)` 方法允许当前线程在指定的毫秒数后继续执行。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
  • 《我的世界》Java版种子合集:探索多样世界生成
    本文介绍了《我的世界》Java版中用于生成多样化游戏世界的种子代码。这些种子是由一个或多个字符(包括正整数和负整数)组成的值,能够为玩家带来截然不同的地形和环境体验。通过使用不同的种子,玩家可以探索各种独特的地貌、生物群系和结构,从而丰富游戏的乐趣和挑战性。 ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
  • Codeforces 605C:Freelancer's Dreams —— 凸包算法解析与题解分析 ... [详细]
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社区 版权所有