专栏首页知晓程序开发 | 「小游戏」开发难?不妨先从 2048 入手试试看

开发 | 「小游戏」开发难?不妨先从 2048 入手试试看

作者:windlany

最近流行微信「跳一跳」小游戏,我也心血来潮写了一个微信小程序版 2048,本篇文章主要分享实现 2048 的算法以及注意的点,一起来学习吧!

算法

  • 生成 4*4 棋盘视图
  • 随机生成 2 或 4 填充两个单元格
  • 记录用户 touch 时的起始位置和结束位置,以此判断滑动方向
  • 根据滑动方向移动单元格,并进行相同值合并
  • 用户一次滑动完成后重复执行步骤 2
  • 判断游戏是否结束,并根据游戏结果产生不同提示

难点

  • 确定滑动方向
  • 用户滑动时,相同格子合并,并移到滑动方向一侧

视图实现

1. 用 WXML + WXSS 生成棋盘视图

2. 用 wx:for 将数据渲染到每个单元格

逻辑实现

1. 页面加载完毕随机用数字 2 或 4 填充两个单元格

2. 判断用户滑动方向

  • 使用 touchStart 事件函数获取起始位置 touchStartX、touchStartY
  • 使用 touchMove 事件函数获取终点位置 touchEndX、touchEndY
var disX = this.touchStartX - this.touchEndX;
var absdisX = Math.abs(disX);
var disY = this.touchStartY - this.touchEndY;
var absdisY = Math.abs(disY);  

// 确定移动方向
// 0:上, 1:右, 2:下, 3:左
var direction = absdisX > absdisY ? (disX < 0 ? 1 : 3) : (disY < 0 ? 2 : 0);

3. 根据滑动方向(假设向右滑动)移动表格以及相同项合并

将 2048 的棋盘生成 4*4 的二维数组 list,为空的空格用 0 表示

var grid = [
    [2, 2, 0, 0],
    [0, 0, 0, 0],
    [0, 8, 4, 0],
    [0, 0, 0, 0]
];

根据滑动方向生成 4*4 二维数组

var list = [
    [0, 0, 2, 2], // 注意是0022不是2200,因为像右滑动所以从右边push入数组
    [0, 0, 0, 0],
    [0, 4, 8, 0],
    [0, 0, 0, 0]
]

相应代码(代码中 this.board.grid 为上面的初始 grid):

formList(dir) {  // 根据滑动方向生成list的四个数组
  var list = [[], [], [], []];
  for (var i = 0; i < this.size; i++)
    for (var j = 0; j < this.size; j++) {
      switch (dir) {
        case 0:
          list[i].push(this.board.grid[j][i]);
          break;
        case 1:
          list[i].push(this.board.grid[i][this.size - 1 - j]);
          break;
        case 2:
          list[i].push(this.board.grid[this.size - 1 - j][i]);
          break;
        case 3:
          list[i].push(this.board.grid[i][j]);
          break;
      }
    }
  return list;
}

将 list 的每一个小数组中的数字提到前面,0 放到末尾

list2 = [
    [2, 2, 0, 0],
    [0, 0, 0, 0],
    [4, 8, 0, 0],
    [0, 0, 0, 0]
];

相应代码:

changeItem(item) {  // 将 [0, 2, 0, 2] 改为 [2, 2, 0, 0]
    var cnt = 0;
    for(var i = 0; i < item.length; i++)
      if(item[i] != 0)
        item[cnt++] = item[i];
    for(var j = cnt; j < item.length; j++) 
      item[j] = 0;
    return item;
  }

将相同值的单元格加起来,并将后面的一个单元格值变为 0

list2 = [
    [4, 0, 0, 0],
    [0, 0, 0, 0],
    [4, 8, 0, 0],
    [0, 0, 0, 0]
];

相应代码:

combine(list) { // 滑动时相同的合并
  for (var i = 0; i < list.length; i++)  // 数字靠边
    list[i] = this.changeItem(list[i]);

  for (var i = 0; i < this.size; i++) {
    for (var j = 1; j < this.size; j++) {
      if (list[i][j - 1] == list[i][j] && list[i][j] != "") {
        list[i][j - 1] += list[i][j];
        list[i][j] = "";
      }
    }
  }
  for (var i = 0; i < list.length; i++)  // 再次数字靠边
    list[i] = this.changeItem(list[i]);
  return list;
}

将 list2 回退为 list 并渲染数据到棋盘视图

list = [
    [0, 0, 0, 4],
    [0, 0, 0, 0],
    [0, 0, 8, 4],
    [0, 0, 0, 0]
];

相应代码:

move(dir) {
  // 0:上, 1:右, 2:下, 3:左
  var curList = this.formList(dir);
  var list = this.combine(curList);
  var result = [[], [], [], []];

  for (var i = 0; i < this.size; i++)
    for (var j = 0; j < this.size; j++) {
      switch (dir) {
        case 0:
          result[i][j] = list[j][i];
          break;
        case 1:
          result[i][j] = list[i][this.size - 1 - j];
          break;
        case 2:
          result[i][j] = list[j][this.size - 1 - i];
          break;
        case 3:
          result[i][j] = list[i][j];
          break;
      }
    }
  this.board.grid = result;
  this.setDataRandom();

  return result;
}

4. 重复步骤 1

5. 判断游戏是否结束

判断标准:4*4 单元格填满且任意一个单元格上下左右没有相同值的单元格

isOver() {  // 游戏是否结束,结束条件:可用格子为空且所有格子上下左右值不等
  this.board.__proto__ = this.bproto;
  if (!this.board.cellEmpty()) {
    return false;
  } else {
    for (var i = 0; i < this.size; i++) // 左右不等
      for (var j = 1; j < this.size; j++) {
        if (this.board.grid[i][j] == this.board.grid[i][j - 1])
          return false;
      }
    for (var j = 0; j < this.size; j++)  // 上下不等
      for (var i = 1; i < this.size; i++) {
        if (this.board.grid[i][j] == this.board.grid[i - 1][j])
          return false;
      }
  }
  return true;
}

6. 根据游戏结果给出相应提示

原文地址: https://juejin.im/post/5a6690dd518825732c53ace5

本文分享自微信公众号 - 知晓程序(zxcx0101),作者:让你更知微信的

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-01-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 24 小时开发微信小程序,重庆人是这样玩的 | 未来小程序

    知晓君
  • 开发 | 傻瓜式操作带你初始化「跳一跳」游戏场景

    在上一篇教程里,知晓程序为大家详细讲解了如何创建小游戏「跳一跳」的游戏场景。通过介绍,大家一定对于小游戏的开发有了更进一步的认识。

    知晓君
  • 开发 | 想让小程序变得更漂亮?一招教你使用图标字体

    图标字体,相信大家都不陌生。包括 font-awesome,iconic 等等,都是很不错的图标字体服务。

    知晓君
  • 面向对象+模块化设计绘制canvas星空动画

    require.js的相关内容已在我的博文 《requireJs的使用,以canvas绘制星空为例》中描述, 可查看:https://cloud.tencent...

    lonelydawn
  • 学习笔记-小甲鱼Python3学习第十九

    局部变量(Local Variable):在整个py文件中声明,全局范围内都可以调用

    py3study
  • JavaScript OOP(一)之构造函数与new命令

     面向对象编程:Object Oriented Programming,简称OOP。 典型的oop语言,如hava、c++,存在着类的概念,类就是对象的模板 (...

    用户1149564
  • 【Golang语言社区--H5编程】smoke.js

    大家好,我是社区主编彬哥,今天给大家带来的H5游戏编程中,烟雾特效的js库; 源码如下 var smokemachine = function (c...

    李海彬
  • 由javascript中"匿名函数调用写法"引出的一些东东

    匿名函数自动调用的三种写法如下: var f1 = function(){alert("f1");}(); (function(){alert("f2");...

    菩提树下的杨过
  • 深入理解JavaScript系列(37):设计模式之享元模式

    享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。

    用户4962466
  • Vue+Element前端导入导出Excel(实践)

    arr就是我们要的结果,是一个数组。每一个值是个对象,包含了code type两个属性。

    coder_koala

扫码关注云+社区

领取腾讯云代金券