Tetris in JS
引言
在这个项目里,我们会实现一个俄罗斯方块小游戏。
一般情况下,这样的游戏应该使用 canvas,或者更先进的 JavaScript 游戏引擎,如 Egret 和 cocos2d-js。
在这个项目中,为了让玩家学员,掌握熟练使用最最基础的 HTML, JavaScript 和 CSS,我们会让大家直接操作 DOM 来实现游戏。虽然很老土,但是还记得小时候火遍大江南北的 QQ 空间游戏么(还是说两三年已经一代沟了...)?那上面的游戏,实现方式是直接操作 DOM 的游戏比例是最高的。
顺带说一下,我们的团队里有使用 Canvas 的大神,大家感兴趣的话我们可以把他拉来~
代码结构
请先下载初始代码。
将压缩包解压,你会得到以下三个文件:
- tetris-in-js.html
- tetris-in-js.css
- tetris-in-js.js
我们游戏的画面和控制按钮定义在 .html 文件中,画面和控制按钮的样式定义在 .css 文件中,游戏的逻辑定义在 .js 文件中。
HTML 文件
HTML 文件定义了我们的游戏框和按钮,并且将 JS 文件中的函数绑定到对应的地方(如按钮)。
CSS 文件
CSS 文件定义了我们在 HTML 文件中绘制的游戏框的样子。本项目提供的 CSS 文件定义了按钮和游戏框的长相。
JS 文件
JS 文件是所有逻辑和运算发生的地方,它控制着游戏的开始、结束,方块的移动和消除等等。
需要做什么?
本项目提供的这份不完全的俄罗斯方块代码,包含了一些需要填补的代码框架。其中标注 YOUR CODE STARTS 和 YOUR CODE ENDS 中间的部分,是需要完善的部分。
在现实的开发场景中,合作几乎是不可避免。经常性地,你的合作者也会像这样给你一份代码框架,需要你去填补其中的逻辑。这可能也是成长最快的方法(不过,若是遇到不写注释或是思路清奇的工友,那当我没说)。
在这个项目中,我们需要做的,是实现以下游戏逻辑:
- 游戏开始 (Game Start)
- 方块自动下落
- 控制方块移动 (左、右) 和加速下落 (down)
- 方块坠底 (drop)
- 当一行被填满时消去
- 当方块在上方超出屏幕时游戏结束。
在完成了这些逻辑之后,大家可以尝试修改这个游戏的外观,或是增加新的逻辑。
关于外观,大家根据自己的审美,怎么漂亮怎么来。
同样,关于逻辑,怎么好玩儿怎么来。下面给大家举几个例子:
- 显示当前得分
- 调整游戏难度
- 闯关机制
- 新的方块
- 可以穿过方块,一直落到最底下的补缝小方块
- 落到底时可以消去一圈方块的炸弹方块
- 所有方块都能落到最下面,无需保持原来形状的雨滴方块
定义
在书写程序之前,我们要先搞清楚定义和用语,这样沟通成本会比较低,写起来也方便。
Piece 和 Block
程序中的 piece 指的是一种方块,而 block 指的是一个小单元。
在基础版本中,一个 piece 由四个 block 通过一定排列而成。
比如,一个长条的 piece 由四个 block 水平(或垂直)首尾相接而成。
DOM
一个 HTML 页面是由一堆节点(叫做 DOM,全称是 Document Object Model,或 文档对象模型)组成的,好比你的餐桌、餐桌上的盘子以及盘子里的水果拼盘(橙子、番茄和西瓜),每一个都可以被当作一个节点。当你把餐桌向北移动一米,它上面的所有东西都会向北移动一米,而相对位置不变;当你移动盘子,盘子里的水果品盘的形状不会被破坏,餐桌也不会移动,但水果的位置确实都改变了。在这里,餐桌是盘子的 母节点,盘子的 子节点 是盘子里的所有水果。类比到俄罗斯方块里,一个 piece 就是四个 block 的母节点,它们的位置是相对 piece 的位置确定的(就好比水果的位置是相对盘子确定的,而不是桌子)。这一点非常重要。
DOM 的属性
每个 DOM 都有一大堆的属性。假设对一个名字为 block 的 DOM 变量,以下是设置的示例:
block.className = 'myblock'; // 相当于给它打上了一个叫作 myblock 的标签。在 CSS 文件中,我们会声明,所有带 myblock 标签的 DOM 都会被染成某种颜色。
block.style.width = '10px'; // block 的宽度为 10 像素
block.style.height = '15px'; // block 的高度
block.style.top = '20px'; // block 的顶上要空出 20 像素的空间(相当把 block 从原来的位置往下移动 20 像素)
block.style.left = '20px'; // block 的左边要空出 20 像素的空间(相当把 block 从原来的位置往右移动 20 像素)
各种方块
基础版本的俄罗斯方块有七种不同的 piece:
请看图片。

从左到右,第一行的名字分别是:
- bar
- sevenShapeReversed
- sevenShape
- square
第二行的名字分别是:
- zShape
- hump
- zShapeReversed
occupationMatrix
这是一个二维数组,每个元素都是要么是 null(没有被 block 占据的时候),要么是一个 DOM 元素(被 block 占据的时候)。occupationMatrix[0] 对应的是画面的最上面那一行,occupationMatrix[0][0] 对应的是画面最上面一行的最左边那一个格子。occupationMatrix[19][9]就是画面的最右下角那一格。所以,往下和往右是加,往上和往左是减。
关键的像素大小
我们的游戏画面宽度是 200 像素,高度是 400 像素。我们定义了一个 block 是长宽都为 20 像素的方块。在设置的时候,需要把这个设置好。
指引
我们强烈建议学生自己通读代码和文档后,直接开始编写程序。
但如果觉得需要一些引导,可以按照以下流程来进行:
定义方块
在第一个 YOUR CODE HERE 的地方,仿照已经给的例子,完成全部七种 piece 的定义。
推荐拿纸和比稍微计算一下哦。
完成后,点击不停点击开始游戏按钮,应该可以看到所有不同方块随机生成。
生成方块
- 通读并理解
generatePiece,setPosition和getPiece函数。
方块的移动
- 完成
fall,moveLeft和moveRight函数。 - 如果实现正确,你就可以通过控制面板控制方块了。
- 在
play中找到setInterval这个函数,改变后面1000的值,可以调节下落速度。
方块的旋转
- 完成
rotate函数。要注意的是,在角落里旋转的时候,处理是有一点点复杂的。 - 如果实现正确,你就可以通过控制面板旋转方块了。
- 可能会有一点难度,请务必多寻求帮助!
方块的消除、游戏结束以及其它
补充剩余的逻辑,完善你的俄罗斯方块!
部署
完成你的俄罗斯方块之后,我们会教你怎样把它放到你的个人网站上,开放给大家玩。
所以,你可以试着多加一些功能,并且把它做得好看一点,也许大家会对你做的东西爱不释手!