按钮

这是 Gamedev Phaser 教程 的 16 个步骤中的第 15 步。与其立即开始游戏,不如通过添加一个玩家可以按下的“开始”按钮来将这个决定权交给玩家。让我们来研究一下如何实现这一点。

新属性

我们需要一个属性来存储一个布尔值,表示游戏当前是否正在进行,以及另一个属性来表示我们的按钮。在其他属性定义下方添加这些行

js
class ExampleScene extends Phaser.Scene {
  // ... previous property definitions ...
  playing = false;
  startButton;
  // ... rest of the class ...
}

加载按钮精灵图

我们可以像加载小球的摇摆动画一样加载按钮精灵图。在 preload() 方法的末尾添加以下内容

js
this.load.spritesheet("button", "img/button.png", {
  frameWidth: 120,
  frameHeight: 40,
});

单个按钮帧的宽度为 120 像素,高度为 40 像素。

您还需要 获取按钮精灵图,并将其保存在您的 /img 目录中。

将按钮添加到游戏中

通过使用 add.sprite 方法将新按钮添加到游戏中。在 create() 方法的末尾添加以下行

js
this.startButton = this.add.sprite(
  this.scale.width * 0.5,
  this.scale.height * 0.5,
  "button",
  0,
);

除了我们传递给其他 add.sprite 调用的参数(例如添加小球和挡板时)之外,这次我们还传递了帧编号,在本例中为 0。这意味着精灵图的第一帧将用于按钮的初始外观。

为了让按钮响应各种输入,例如鼠标点击,我们需要在前面的 add.sprite 调用后立即添加以下行

js
this.startButton.setInteractive();
this.startButton.on(
  "pointerover",
  () => {
    this.startButton.setFrame(1);
  },
  this,
);
this.startButton.on(
  "pointerdown",
  () => {
    this.startButton.setFrame(2);
  },
  this,
);
this.startButton.on(
  "pointerout",
  () => {
    this.startButton.setFrame(0);
  },
  this,
);
this.startButton.on(
  "pointerup",
  () => {
    this.startGame();
  },
  this,
);

首先,我们在按钮上调用 setInteractive 以使其响应指针事件。然后,我们将四个事件监听器添加到按钮中

  • pointerover — 当指针悬停在按钮上时,我们将按钮的帧更改为 1,即精灵图的第二帧。
  • pointerdown — 当按钮被按下时,我们将按钮的帧更改为 2,即精灵图的第三帧。
  • pointerout — 当指针移出按钮时,我们将按钮的帧改回 0,即精灵图的第一帧。
  • pointerup — 当按钮被释放时,我们调用 startGame 方法来开始游戏。

现在,我们需要定义上面代码中引用的 startGame() 方法

js
class ExampleScene extends Phaser.Scene {
  // ...
  startGame() {
    this.startButton.destroy();
    this.ball.body.setVelocity(150, -150);
    this.playing = true;
  }
}

当按下按钮时,我们移除按钮,设置小球的初始速度,并将 playing 属性设置为 true

最后,在本节中,回到您的 create 方法,找到 this.ball.body.setVelocity(150, -150); 行,并将其删除。您只希望在按下按钮时小球才移动,而不是之前!

游戏开始前保持挡板静止

它按预期工作,但我们仍然可以在游戏开始前移动挡板,这看起来有点奇怪。为了阻止这种情况,我们可以利用 playing 属性,使挡板仅在游戏开始后才能移动。为此,请按如下方式调整 update() 方法

js
class ExampleScene extends Phaser.Scene {
  // ...
  update() {
    // ...
    if (this.playing) {
      this.paddle.x = this.input.x || this.scale.width * 0.5;
    }
    // ...
  }
  // ...
}

这样,在所有内容加载和准备好之后,但在实际游戏开始之前,挡板是不可移动的。

Compare your code

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

后续步骤

在本系列文章中,我们做的最后一件事是通过为小球从挡板反弹的方式添加一些 随机化 来使游戏玩法更加有趣。