构建砖块区域

这是 Gamedev Canvas 教程 的 10 个步骤中的**第 6 步**。您可以在 Gamedev-Canvas-workshop/lesson6.html 找到完成本课程后代码的样子。

修改游戏机制后,我们现在可以输掉游戏了——这很棒,因为这意味着游戏终于开始感觉更像游戏了。但是,如果你只是让球在墙壁和球拍之间弹来弹去,很快就会变得无聊。一个真正的打砖块游戏需要一些砖块来用球摧毁,这就是我们现在要创建的!

设置砖块变量

本课的总体目标是使用嵌套循环(遍历二维数组)为砖块渲染几行代码。但是首先,我们需要设置一些变量来定义有关砖块的信息,例如它们的宽度和高度、行数和列数等。在您之前在程序中声明的变量下方添加以下行到您的代码中。

js
const brickRowCount = 3;
const brickColumnCount = 5;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;

在这里,我们定义了砖块的行数和列数、它们的宽度和高度、砖块之间的填充(以便它们不会相互接触)以及顶部和左侧的偏移量(以便它们不会从画布边缘开始绘制)。

我们将把所有砖块存储在一个二维数组中。它将包含砖块列 (c),而列又将包含砖块行 (r),而行又将分别包含一个对象,其中包含在屏幕上绘制每个砖块的 xy 位置。在您的变量下方添加以下内容

js
const bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
  bricks[c] = [];
  for (let r = 0; r < brickRowCount; r++) {
    bricks[c][r] = { x: 0, y: 0 };
  }
}

上面的代码将循环遍历行和列并创建新的砖块。请注意,稍后砖块对象也将用于碰撞检测。

砖块绘制逻辑

现在让我们创建一个函数来循环遍历数组中的所有砖块并在屏幕上绘制它们。我们的代码可能如下所示

js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      bricks[c][r].x = 0;
      bricks[c][r].y = 0;
      ctx.beginPath();
      ctx.rect(0, 0, brickWidth, brickHeight);
      ctx.fillStyle = "#0095DD";
      ctx.fill();
      ctx.closePath();
    }
  }
}

同样,我们循环遍历行和列来设置每个砖块的 xy 位置,并且我们还在每次循环迭代中在画布上绘制一个砖块——大小为 brickWidth x brickHeight。问题是我们把它们都绘制在一个位置,坐标为 (0,0)。我们需要做的是包含一些计算,这些计算将计算出每次循环迭代中每个砖块的 xy 位置

js
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;

每个 brickX 位置都计算为 brickWidth + brickPadding,乘以列号 c,再加上 brickOffsetLeftbrickY 的逻辑相同,只是它使用行号 rbrickHeightbrickOffsetTop 的值。现在每个砖块都可以放置在其正确的行和列中,砖块之间有填充,并从画布左侧和顶部边缘偏移绘制。

在将 brickXbrickY 值分别作为坐标而不是每次都使用 (0,0) 后,drawBricks() 函数的最终版本将如下所示——将此添加到您的代码中,位于 drawPaddle() 函数下方

js
function drawBricks() {
  for (let c = 0; c < brickColumnCount; c++) {
    for (let r = 0; r < brickRowCount; r++) {
      const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
      const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
      bricks[c][r].x = brickX;
      bricks[c][r].y = brickY;
      ctx.beginPath();
      ctx.rect(brickX, brickY, brickWidth, brickHeight);
      ctx.fillStyle = "#0095DD";
      ctx.fill();
      ctx.closePath();
    }
  }
}

实际绘制砖块

本课中要做的最后一件事是在 draw() 函数中的某个位置添加对 drawBricks() 的调用,最好是在开头,在清除画布和绘制球之间。在 drawBall() 调用上方添加以下内容

js
drawBricks();

比较您的代码

此时,游戏又变得有趣了一些

注意:尝试更改一行或一列中的砖块数量或其位置。

后续步骤

所以现在我们有了砖块!但是球根本没有与它们交互——我们将在继续进行第七章:碰撞检测 时更改这一点。