额外生命

这是 Gamedev Phaser 教程 的 16 个步骤中的第 13 步。在本文中,我们将实现一个生命系统,这样玩家就可以一直玩下去,直到失去三条生命,而不仅仅是一条,这使得游戏更有趣、更持久。

新属性

在您的代码中,在现有属性下方添加以下新属性

js
class ExampleScene extends Phaser.Scene {
  // ... previous property definitions ...
  lives = 3;
  livesText;
  lifeLostText;
  // ... rest of the class ...
}

这些属性将分别存储生命的 数量、显示剩余生命数量的文本标签,以及当玩家失去一条生命时屏幕上显示的文本标签。

定义新的文本标签

定义文本看起来和我们在 分数 课程中学到的很相似。在 create() 方法中,在现有的 scoreText 定义下方添加以下几行

js
this.livesText = this.add.text(
  this.scale.width - 5,
  5,
  `Lives: ${this.lives}`,
  { font: "18px Arial", fill: "#0095dd" },
);
this.livesText.setOrigin(1, 0);
this.lifeLostText = this.add.text(
  this.scale.width * 0.5,
  this.scale.height * 0.5,
  "Life lost, click to continue",
  { font: "18px Arial", fill: "#0095dd" },
);
this.lifeLostText.setOrigin(0.5, 0.5);
this.lifeLostText.visible = false;

this.livesTextthis.lifeLostText 对象看起来与 this.scoreText 非常相似——它们定义了屏幕上的位置、要显示的实际文本以及字体样式。前者在其右上角锚定以正确对齐屏幕,后者居中,都使用了 setOrigin

lifeLostText 只会在失去生命时显示,因此其可见性最初设置为 false

让我们的文本样式 DRY

您可能已经注意到,我们对所有三个文本:scoreTextlivesTextlifeLostText 使用了相同的样式。如果我们想更改字体大小或颜色,将不得不在多个地方进行更改。为了将来更易于维护,我们可以创建一个单独的变量来保存我们的样式,我们称之为 textStyle,并将其放在文本定义之前

js
const textStyle = { font: "18px Arial", fill: "#0095dd" };

现在我们可以在设置文本标签样式时使用此变量——更新您的代码,将多个文本样式实例替换为该变量

js
this.scoreText = this.add.text(5, 5, "Points: 0", textStyle);

this.livesText = this.add.text(
  this.scale.width - 5,
  5,
  `Lives: ${this.lives}`,
  textStyle,
);
this.livesText.setOrigin(1, 0);
this.lifeLostText = this.add.text(
  this.scale.width * 0.5,
  this.scale.height * 0.5,
  "Life lost, click to continue",
  textStyle,
);
this.lifeLostText.setOrigin(0.5, 0.5);
this.lifeLostText.visible = false;

这样,在一个变量中更改字体将把更改应用于所有使用它的地方。

生命处理代码

为了在我们的游戏中实现生命系统,让我们先改变当球超出边界时的行为。而不是立即重新开始

js
if (ballIsOutOfBounds) {
  // Game over logic
  location.reload();
}

我们将调用一个名为 ballLeaveScreen() 的新方法;删除之前的行(如上所示),并用以下行替换

js
if (ballIsOutOfBounds) {
  this.ballLeaveScreen();
}

我们希望每次球离开画布时都减少生命数量。将 ballLeaveScreen() 方法定义添加到 ExampleScene 类的末尾

js
class ExampleScene extends Phaser.Scene {
  // ...
  ballLeaveScreen() {
    this.lives--;
    if (this.lives > 0) {
      this.livesText.setText(`Lives: ${this.lives}`);
      this.lifeLostText.visible = true;
      this.ball.body.reset(this.scale.width * 0.5, this.scale.height - 25);
      this.input.once(
        "pointerdown",
        () => {
          this.lifeLostText.visible = false;
          this.ball.body.setVelocity(150, -150);
        },
        this,
      );
    } else {
      // Game over logic
      location.reload();
    }
  }
}

而不是在失去生命时立即弹出提示,我们首先从当前数量中减去一条生命,并检查它是否为非零值。如果是,则玩家仍有一些生命,并且可以继续玩——他们将看到生命丢失消息,球和挡板的位置将在屏幕上重置,在下一个输入(单击或触摸)时,消息将隐藏,球将再次开始移动。

当可用生命数量达到零时,游戏结束,将显示游戏结束提示消息。

事件

您可能已经注意到上述代码块中的 once 方法调用,并想知道它是什么。once() 方法是一个 Phaser 事件侦听器,它侦听指定事件(在本例中为 pointer down 事件)的下一次发生,然后在触发后自行移除。这意味着回调中的代码在调用 once 后只会运行一次,这正是我们想要的——我们只想在玩家单击或触摸屏幕后隐藏生命丢失消息并重新开始球的移动。

Compare your code

这是您到目前为止应该看到的效果,实时运行。要查看其源代码,请单击“播放”按钮。

后续步骤

生命系统让游戏更加宽容——如果您失去一条生命,您还有两条生命可以继续玩。现在,让我们通过添加 动画和缓动效果 来扩展游戏的外观和感觉。