构建砖块区域

这是 游戏开发 Phaser 教程 的 16 个步骤中的第 **9 步**。您可以在 Gamedev-Phaser-Content-Kit/demos/lesson09.html 中找到完成本课后代码应有的样子。

构建砖块区域比在屏幕上添加单个对象稍微复杂一些,尽管在 Phaser 中比在纯 JavaScript 中更容易。让我们探讨如何使用循环创建一个砖块组并将它们打印到屏幕上。

定义新变量

首先,让我们定义所需的变量 - 在您之前的变量定义下方添加以下内容

js
let bricks;
let newBrick;
let brickInfo;

bricks 变量将用于创建一个组,newBrick 将是循环每次迭代时添加到组中的一个新对象,而 brickInfo 将存储我们所需的所有数据。

渲染砖块图像

接下来,让我们加载砖块的图像 - 在其他 load.image() 调用下方添加以下内容

js
function preload() {
  // …
  game.load.image("brick", "img/brick.png");
}

您还需要从 GitHub 获取砖块图像 并将其保存到您的 /img 目录中。

绘制砖块

我们将把所有用于绘制砖块的代码放在 initBricks 函数中,以将其与其他代码分离。在 create() 函数的末尾添加对 initBricks 的调用

js
function create() {
  // …
  initBricks();
}

现在进入函数本身。将 initBricks() 函数添加到我们游戏代码的末尾,就在结束标签 </script> 之前,如下所示。首先,我们包含了 brickInfo 对象,因为它很快就会派上用场

js
function initBricks() {
  brickInfo = {
    width: 50,
    height: 20,
    count: {
      row: 3,
      col: 7,
    },
    offset: {
      top: 50,
      left: 60,
    },
    padding: 10,
  };
}

这个 brickInfo 对象将保存我们所需的所有信息:单个砖块的宽度和高度,我们将在屏幕上看到的砖块行数和列数,顶部和左偏移量(我们在画布上开始绘制砖块的位置)以及每个砖块行和列之间的填充。

现在,让我们开始创建砖块本身 - 首先添加一个空组来容纳砖块,在 initBricks() 函数的底部添加以下行

js
bricks = game.add.group();

我们可以遍历行和列来创建每次迭代的新砖块 - 在之前代码行的下方添加以下嵌套循环

js
for (let c = 0; c < brickInfo.count.col; c++) {
  for (let r = 0; r < brickInfo.count.row; r++) {
    // create new brick and add it to the group
  }
}

这样,我们将创建所需数量的砖块,并将它们全部包含在一个组中。现在,我们需要在嵌套循环结构中添加一些代码来绘制每个砖块。按照以下内容填写内容

js
for (let c = 0; c < brickInfo.count.col; c++) {
  for (let r = 0; r < brickInfo.count.row; r++) {
    let brickX = 0;
    let brickY = 0;
    newBrick = game.add.sprite(brickX, brickY, "brick");
    game.physics.enable(newBrick, Phaser.Physics.ARCADE);
    newBrick.body.immovable = true;
    newBrick.anchor.set(0.5);
    bricks.add(newBrick);
  }
}

在这里,我们遍历行和列以创建新的砖块并将它们放置在屏幕上。新创建的砖块被启用用于 Arcade 物理引擎,其主体被设置为不可移动(因此它在被球击中时不会移动),我们还将锚点设置为居中,并将砖块添加到组中。

目前的问题是,我们把所有的砖块都画在一个地方,坐标为 (0,0)。我们需要做的是在每个砖块的 x 和 y 位置绘制每个砖块。将 brickXbrickY 行更新如下

js
const brickX =
  c * (brickInfo.width + brickInfo.padding) + brickInfo.offset.left;
const brickY =
  r * (brickInfo.height + brickInfo.padding) + brickInfo.offset.top;

每个 brickX 位置都被计算为 brickInfo.width 加上 brickInfo.padding,乘以列号 c,再加上 brickInfo.offset.leftbrickY 的逻辑相同,只是它使用行号 rbrickInfo.heightbrickInfo.offset.top 的值。现在,每个砖块都可以放置在正确的位置,每个砖块之间都有填充,并在距画布左边缘和顶边缘的偏移量处绘制。

检查 initBricks() 代码

以下是 initBricks() 函数的完整代码

js
function initBricks() {
  brickInfo = {
    width: 50,
    height: 20,
    count: {
      row: 3,
      col: 7,
    },
    offset: {
      top: 50,
      left: 60,
    },
    padding: 10,
  };
  bricks = game.add.group();
  for (let c = 0; c < brickInfo.count.col; c++) {
    for (let r = 0; r < brickInfo.count.row; r++) {
      const brickX =
        c * (brickInfo.width + brickInfo.padding) + brickInfo.offset.left;
      const brickY =
        r * (brickInfo.height + brickInfo.padding) + brickInfo.offset.top;
      newBrick = game.add.sprite(brickX, brickY, "brick");
      game.physics.enable(newBrick, Phaser.Physics.ARCADE);
      newBrick.body.immovable = true;
      newBrick.anchor.set(0.5);
      bricks.add(newBrick);
    }
  }
}

如果您此时重新加载 index.html,您应该会在屏幕上看到绘制的砖块,它们彼此之间相隔均匀。

比较您的代码

您可以在下面的实时演示中查看本课的完成代码,并尝试使用它,以更好地理解它的工作原理

后续步骤

不过,还缺少了一些东西。球穿过砖块而没有停止 - 我们需要适当的 碰撞检测