Logo
Section 1 / 3

四格骨牌与方块绘制

在本节课中,你将了解如何使用类来表示俄罗斯方块的方块,并学习如何将它们绘制在画布上。

导入

四格骨牌与方块绘制

在本节课中,你将了解如何使用类来表示俄罗斯方块的方块,并学习如何将它们绘制在画布上。

俄罗斯方块中的一个方块是由四个方块组成的一个整体形状,通常称为四格骨牌(tetromino),共有七种不同的形状和颜色。这些形状的名称 I、J、L、O、S、T 和 Z 与其外形相似。

七种俄罗斯方块形状
七种俄罗斯方块形状

四格骨牌矩阵表示

我们将 J 型四格骨牌表示为一个矩阵,其中数字 2 表示有颜色的方块单元格。为了便于旋转,我们在矩阵中添加一行零:

1[2, 0, 0], 2[2, 2, 2], 3[0, 0, 0];

四格骨牌在生成时是横向放置的,其中 J、L 和 T 型是以平边朝前的方式生成的。

由于我们频繁使用四格骨牌,可以将其封装成一个名为 Piece 的类。

Piece 类

Piece 类需要知道它在游戏板上的 位置、颜色 和 形状。为了能够将自己绘制到画布上,该类还需要持有对 canvas 上下文 的引用。

最初,我们可以直接在 Piece 类的构造函数中硬编码这些值:

1class Piece { 2 constructor(ctx) { 3 this.ctx = ctx; 4 5 this.color = 'blue'; 6 this.shape = [ 7 [2, 0, 0], 8 [2, 2, 2], 9 [0, 0, 0] 10 ]; 11 12 // 初始位置 13 this.x = 3; 14 this.y = 0; 15 } 16}

绘制四格骨牌

要将四格骨牌绘制到游戏板上,我们需要遍历其形状中的每个单元格。如果某个单元格的值大于零,则将其涂色:

1 X → 2Y [2, 0, 0] 3↓ [2, 2, 2] 4 [0, 0, 0]

因此,我们可以根据坐标 [x, y] 进行着色,例如:

1[0, 0] 2[0, 1], [1, 1], [2, 1]

但我们也需要记录当前四格骨牌在游戏板上的实际位置。这正是通过 piece 的坐标来实现的。

[this.x, this.y] 表示形状左上角的位置:

1 X → 2Y [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 3↓ [0, 0, 0, [2, 0, 0], 0, 0, 0, 0] 4 [0, 0, 0, [2, 2, 2], 0, 0, 0, 0] 5 [0, 0, 0, [0, 0, 0], 0, 0, 0, 0] 6 7// this.x = 3, this.y = 1

因此,[this.x + x, this.y + y] 就是该方块在游戏板上的实际位置。这正是我们用来确定哪些位置应被涂成蓝色的方法:

1[3, 1] 2[3, 2], [4, 2], [5, 2]

现在我们已经理清了逻辑思路,代码实现就变得简单了:

1class Piece { 2 draw() { 3 this.ctx.fillStyle = this.color; 4 this.shape.forEach((row, y) => { 5 row.forEach((value, x) => { 6 if (value > 0) { 7 this.ctx.fillRect(this.x + x, this.y + y, 1, 1); 8 } 9 }); 10 }); 11 } 12}

初始化

在初始化游戏板时,我们创建一个四格骨牌并显示在画布上。为了使其可见,我们调用 Piece 类的 draw 方法:

1class Board { 2 constructor(ctx) { 3 this.ctx = ctx; 4 this.grid = this.getEmptyBoard(); 5 this.piece = new Piece(ctx); 6 } 7}

我们需要使用 clearRect() 清除画布上旧的绘制内容。利用 canvas 的宽度和高度,可以在每次绘制之间清理画布。

这里我们可以使用 对象解构 来让代码更简洁:

1function draw() { 2 const { width, height } = ctx.canvas; 3 ctx.clearRect(0, 0, width, height); 4 5 board.piece.draw(); 6}

尝试运行代码,按下播放按钮后,你会看到蓝色的四格骨牌出现在屏幕上。

初识俄罗斯方块

键盘交互与方块移动