用一份 HTML 文件实现 2048 小游戏:合并算法与动画实践
<h2>一、为什么选择单文件实现</h2>
<p>前段时间需要给一个纯静态的展示站点加一个小游戏,约束很明确:不引入构建工具、不加第三方依赖、打开就能玩。2048 规则简单、交互纯粹,非常适合用来验证"单文件交付"的可行性。最终成品是一份 index.html,HTML、CSS、JavaScript 全部内联,体积不到 30KB。</p>
<h2>二、状态设计</h2>
<p>棋盘是标准的 4×4 网格。为了兼顾逻辑与渲染,我用了两层结构:一层是数值网格 grid[4][4],只存方块 id;另一层是 tiles 映射表,记录每个方块的 DOM 元素、行列坐标和数值。移动时只操作映射表,渲染层根据坐标做 CSS 位移,逻辑与视图互不干扰。</p>
<h2>三、核心算法:滑动与合并</h2>
<p>2048 的难点在合并规则:一次移动中,每个方块最多参与一次合并。我的做法是先按方向确定遍历顺序——向上下移动时按行反向遍历,向左右移动时按列反向遍历,这样保证靠边的方块先移动。对每个方块沿方向循环探测:遇到空格就继续前进,遇到相同数值且该目标本回合未被合并过,就合并并标记;否则停在原地。遍历结束后统一重绘,再随机生成一个新方块(90% 概率为 2,10% 为 4)。</p>
<p>伪代码大致是:</p>
<pre><code>for each tile in traversal_order:
find farthest empty cell or mergeable same-value cell
if moved: update grid, animate DOM position
if merged: double value, mark target merged, add score</code></pre>
<h2>四、动画与输入</h2>
<p>动画没有用 JS 逐帧计算,而是给每个方块设置绝对定位,位移交给 CSS transition(120ms ease)。新方块出现和合并用 keyframes 做一个小幅缩放,观感上会自然很多。输入层同时监听键盘(方向键与 WASD)和触摸事件:touchstart 记录起点,touchend 计算位移方向和距离,超过 24px 才触发移动,避免误触。</p>
<h2>五、踩过的坑</h2>
<p>第一个坑是合并标记。最初没有记录"本回合已合并",导致 2-2-4 的行向左滑动时出现连锁合并,一步变成 8。加上 merged 标记后行为才正确。第二个坑是重开局的资源清理:新游戏时要同时清空网格和移除所有 DOM 节点,否则旧方块会残留在界面上。第三个坑是响应式:用 CSS Grid 定义格子,再用 JS 计算每个格子的像素尺寸来定位方块,窗口缩放时要重新计算,否则会出现错位。</p>
<h2>六、小结</h2>
<p>单文件 2048 的代码量约 400 行,其中一半是样式与动画。它没有复杂框架,却把状态管理、算法、动画和输入处理串成了一个完整闭环。对于需要"打开即用"的场景,这种实现方式的维护成本远低于引入一套构建体系。代码已经开源在仓库中,欢迎交流。</p>
- 点赞
- 收藏
- 关注作者
评论(0)