一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

HTML怎么做2048游戏_html 2048数字游戏制作教程【含示例】

时间:2026-07-18 18:17:49 编辑:袖梨 来源:一聚教程网

初始化4×4空棋盘需用Array(4).fill().map(() => Array(4).fill(0))避免引用共享;addNumber()先收集空位再随机填充2(90%)或4(10%);合并逻辑按方向遍历并去重补零;游戏结束需同时满足全非零且横纵均无相邻相等。

直接用 div + grid + 原生 JS 就能跑通核心逻辑,不用框架、不依赖 Canvas,4x4 合并判断写对了,游戏就活了。

怎么初始化一个空的 4x4 游戏板?

别用 Array(4).fill(Array(4).fill(0)) —— 这会创建 4 个指向同一数组的引用,改一行全变。必须用 map 每次新建:

const board = Array(4).fill().map(() => Array(4).fill(0));

初始化后立刻调用两次 addNumber(),确保开局有两个数字(2 占 90%,4 占 10%):

  • addNumber() 要先遍历找所有 board[i][j] === 0 的坐标,存进 emptyCells 数组
  • 再用 Math.floor(Math.random() * emptyCells.length) 取随机索引,避免空数组时崩溃
  • 生成值用 Math.random() ,别硬写死 <code>2

方向移动时为什么合并总漏掉或重复?

关键在遍历顺序和“合并标记”:比如 moveLeft() 必须按行遍历,每行内从左到右扫描,但合并只允许每个格子最多参与一次(即合并后该位置不能再被后续格子合并)。

立即学习“前端免费学习笔记(深入)”;

典型错误写法是两层 for 循环里直接 board[i][j] += board[i][j+1],没考虑“已合并格子是否还能动”。正确做法是:

  • 为每行建一个临时数组 row = board[i].filter(n => n !== 0)
  • 再单趟遍历 rowif (row[j] === row[j+1]) { row[j] *= 2; row.splice(j+1, 1); }
  • 补零至长度 4,再写回 board[i]

上下方向同理,只是把“行”换成“列”,遍历维度要转过来。

怎么判断游戏真正结束了?

不能只看有没有空格——满格时还可能有相邻相等数字可合并。必须同时检查两个条件:

  • 所有格子非零:board.flat().every(n => n !== 0)
  • 横向无相邻相等:!board.some(row => row.some((n, j) => j
  • 纵向无相邻相等:!board[0].some((_, j) => board.some((row, i) => i

三个条件全满足才触发 gameOver。漏掉任一,就会出现“明明还能合并却提示 Game Over”的 bug。

键盘事件监听容易卡死或重复触发?

keydown 事件默认会连续触发(长按方向键),导致一次按键执行多次移动。必须加防抖:

  • 用一个布尔变量 isMoving 标记当前是否正在处理移动
  • handleKeyPress 开头加 if (isMoving) return;
  • 进入 move() 后立刻设 isMoving = true,渲染完、新方块加完再设 isMoving = false

否则玩家猛按左键,可能一次滑动就把整行全吸到左边,中间根本没机会合并。

最易被忽略的是:每次移动后,必须严格区分“是否真发生了位置变化或合并”,只有 hasMoved === true 才调用 addNumber()。否则空按方向键也会塞新数字,棋盘很快爆满。

热门栏目