额外生命

这是 Gamedev Phaser 教程 的 16 步中的第 13 步。你可以在 Gamedev-Phaser-Content-Kit/demos/lesson13.html 中找到完成本课后代码应有的样子。

我们可以通过添加生命来使游戏更持久。在本文中,我们将实现一个生命系统,这样玩家就可以继续玩,直到他们损失了三条生命,而不仅仅是一条。

新变量

将以下新变量添加到代码中现有变量下方

js
let lives = 3;
let livesText;
let lifeLostText;

它们分别用于存储生命数量、显示剩余生命数量的文本标签以及玩家损失生命时显示在屏幕上的文本标签。

定义新文本标签

定义文本类似于我们在 分数 课中所做的事情。将以下代码行添加到 create() 函数中现有 scoreText 定义下方

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

livesTextlifeLostText 对象与 scoreText 对象非常相似——它们定义了屏幕上的位置、要显示的实际文本以及字体样式。前者锚定在它的右上角,以与屏幕正确对齐,后者居中,两者都使用 anchor.set()

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

使我们的文本样式 DRY

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

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

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

js
scoreText = game.add.text(5, 5, "Points: 0", textStyle);
livesText = game.add.text(
  game.world.width - 5,
  5,
  `Lives: ${lives}`,
  textStyle,
);
livesText.anchor.set(1, 0);
lifeLostText = game.add.text(
  game.world.width * 0.5,
  game.world.height * 0.5,
  "Life lost, click to continue",
  textStyle,
);
lifeLostText.anchor.set(0.5);
lifeLostText.visible = false;

这样,在一个变量中更改字体将把更改应用到所有使用它的位置。

生命处理代码

为了在游戏中实现生命,让我们首先更改球绑定到 onOutOfBounds 事件的函数。与其立即执行一个匿名函数并显示警报,

js
ball.events.onOutOfBounds.add(() => {
  alert("Game over!");
  location.reload();
}, this);

我们将分配一个名为 ballLeaveScreen 的新函数;删除之前的事件处理程序(如上所示)并用以下代码行替换它

js
ball.events.onOutOfBounds.add(ballLeaveScreen, this);

我们希望每次球离开画布时都减少生命数量。在代码的末尾添加 ballLeaveScreen() 函数定义

js
function ballLeaveScreen() {
  lives--;
  if (lives) {
    livesText.setText(`Lives: ${lives}`);
    lifeLostText.visible = true;
    ball.reset(game.world.width * 0.5, game.world.height - 25);
    paddle.reset(game.world.width * 0.5, game.world.height - 5);
    game.input.onDown.addOnce(() => {
      lifeLostText.visible = false;
      ball.body.velocity.set(150, -150);
    }, this);
  } else {
    alert("You lost, game over!");
    location.reload();
  }
}

与其在失去生命时立即打印警报,我们首先从当前数量中减去一条生命,并检查它是否是非零值。如果是,则玩家仍然有一些生命可以继续玩——他们会看到生命损失的消息,球和球拍位置将在屏幕上重置,并且在下一个输入(点击或触摸)时,消息将被隐藏,球将再次开始移动。

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

事件

你可能已经注意到上述两个代码块中的 add()addOnce() 方法调用,并想知道它们有什么区别。不同之处在于 add() 方法绑定给定的函数,并导致每次事件发生时都执行该函数,而 addOnce() 在你希望绑定函数只执行一次,然后取消绑定以便不再执行时很有用。在我们的例子中,对于每个 outOfBounds 事件,都会执行 ballLeaveScreen,但当球离开屏幕时,我们只想删除屏幕上的消息一次。

比较你的代码

你可以在下面的实时演示中查看本课的完整代码,并与它互动以更好地了解它的工作原理

后续步骤

生命使游戏更宽容——如果你损失了一条生命,你仍然有两条生命可以继续玩。现在,让我们通过添加 动画和补间动画 来扩展游戏的视觉效果和感觉。