额外生命
这是 Gamedev Phaser 教程 16 个步骤中的第 13 步。在本文中,我们将实现一个生命系统,让玩家失去 3 条生命之前都能继续游戏,而不是仅失去一条生命后就结束,从而延长游戏乐趣。
新属性
在代码中现有属性的下方添加以下新属性:
class ExampleScene extends Phaser.Scene {
// ……前面的属性定义……
lives = 3;
livesText;
lifeLostText;
// ……类的其余部分……
}
它们分别存储生命数量、显示剩余生命数量的文本标签,以及玩家失去一条生命时显示在屏幕上的文本标签。
定义新的文本标签
文本的定义方式与我们在得分课程中所做的类似。在 create() 方法内现有的 scoreText 定义下方添加以下代码:
this.livesText = this.add.text(this.scale.width - 5, 5, `生命:${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,
"失去生命,点击继续",
{ font: "18px Arial", fill: "#0095dd" },
);
this.lifeLostText.setOrigin(0.5, 0.5);
this.lifeLostText.visible = false;
this.livesText 和 this.lifeLostText 对象与 this.scoreText 很相似:它们定义了屏幕上的位置、要显示的文本和字体样式。前者通过 setOrigin 将锚点设在右上边缘,以与屏幕正确对齐;后者则居中显示。
lifeLostText 只会在失去生命时显示,因此其初始可见性设为 false。
消除文本样式的重复
你可能已经注意到,scoreText、livesText 和 lifeLostText 三个文本都使用了相同的样式。若要修改字体大小或颜色,就必须在多处修改。为了便于将来维护,可以创建一个单独的变量来存储样式。我们将它命名为 textStyle,并放在文本定义之前:
const textStyle = { font: "18px Arial", fill: "#0095dd" };
现在可以在设置文本标签样式时使用这个变量。请更新代码,以变量替换多处重复的文本样式:
this.scoreText = this.add.text(5, 5, "得分:0", textStyle);
this.livesText = this.add.text(
this.scale.width - 5,
5,
`生命:${this.lives}`,
textStyle,
);
this.livesText.setOrigin(1, 0);
this.lifeLostText = this.add.text(
this.scale.width * 0.5,
this.scale.height * 0.5,
"失去生命,点击继续",
textStyle,
);
this.lifeLostText.setOrigin(0.5, 0.5);
this.lifeLostText.visible = false;
这样,只需更改一个变量中的字体设置,就会应用到所有使用它的地方。
处理生命值的代码
要在游戏中实现生命值,先修改球越过边界时的行为。不要立即重新开始游戏:
if (ballIsOutOfBounds) {
// 游戏结束逻辑
location.reload();
}
而是调用一个名为 ballLeaveScreen() 的新方法。删除上面所示的代码,替换为以下代码:
if (ballIsOutOfBounds) {
this.ballLeaveScreen();
}
我们希望每次球离开画布时都减少一条生命。在 ExampleScene 类的末尾添加 ballLeaveScreen() 方法定义:
class ExampleScene extends Phaser.Scene {
// ...
ballLeaveScreen() {
this.lives--;
if (this.lives > 0) {
this.livesText.setText(`生命:${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 {
// 游戏结束逻辑
location.reload();
}
}
}
失去一条生命时,我们不会立刻显示警告,而是先从当前生命数中减去一条,并检查它是否仍大于零。若大于零,玩家还有生命可以继续游戏:他们会看到失去生命的提示,球和板子的位置会在屏幕上重置;下一次输入(点击或触摸)后,提示会隐藏,球会再次开始移动。
当可用生命数降至零时,游戏结束,并显示游戏结束提示。
事件
你可能注意到了上方代码块中的 once 方法调用,并想知道它的作用。once() 是 Phaser 的事件监听器:它会监听指定事件的下一次发生(本例中为指针按下事件),触发后便自动移除自身。这意味着在调用 once 后,回调中的代码只会运行一次。这正符合我们的需求:玩家点击或触摸屏幕后,只需隐藏一次失去生命提示,并重新启动球的运动。
比较你的代码
以下是到目前为止应得到的实时运行效果。要查看其源代码,请点击“运行”按钮。
下一步
生命机制让游戏变得容错率更高:失去一条生命后,你仍有两条生命可以继续游戏。接下来,让我们通过添加动画和补间来丰富游戏的视觉与质感。