玩家挡板和控制
这是 Gamedev Phaser 教程 的 第 7 步(共 16 步)。我们已经让球移动并从墙壁反弹,但很快就会变得无聊——没有互动性!我们需要一种引入游戏玩法的方式,因此在本篇文章中,我们将创建一个挡板来移动并击球。
渲染挡板
从框架的角度来看,挡板与球非常相似——我们需要添加一个属性来表示它,加载相关的图像资源,然后进行魔法操作。
加载挡板
首先,在 ball 属性之后,添加我们将在游戏中使用的 paddle 属性。
class ExampleScene extends Phaser.Scene {
ball;
paddle;
// ...
}
然后,在 preload 方法中,通过添加以下新的 load.image() 调用来加载 paddle 图像。
class ExampleScene extends Phaser.Scene {
// ...
preload() {
this.load.image("ball", "img/ball.png");
this.load.image("paddle", "img/paddle.png");
}
// ...
}
以免我们忘记,此时,您应该获取 挡板图形 并将其保存在您的 /img 文件夹中。
使用物理引擎渲染挡板
接下来,我们将通过在 create() 方法中添加以下 add.sprite() 调用来初始化我们的挡板——将其添加到最底部。
this.paddle = this.add.sprite(
this.scale.width * 0.5,
this.scale.height - 5,
"paddle",
);
我们可以使用 scale.width 和 scale.height 值将挡板定位在我们想要的位置:this.scale.width * 0.5 将位于屏幕的中间。在我们的例子中,世界与画布相同,但对于其他类型的游戏,如横卷轴游戏,世界会更大,您可以对其进行调整以创建有趣的效果。
您会注意到,如果此时重新加载 index.html,挡板当前位于屏幕的最底部,对于挡板来说太低了。为什么?因为计算位置的起点是从对象的中心开始的。我们可以更改这一点,将原点设置在挡板宽度中间和高度底部,这样更容易将其定位在屏幕底部边缘。在上一行新增代码的下方添加以下一行。
this.paddle.setOrigin(0.5, 1);
挡板现在已定位在我们想要的位置。现在,为了使其与球碰撞,我们必须为挡板启用物理引擎。继续在 create() 方法的末尾添加以下新行。
this.physics.add.existing(this.paddle);
现在魔法可以开始发生了——框架可以负责在每一帧检查碰撞检测。要在挡板和球之间启用碰撞检测,请按所示方式将 collide() 方法添加到 update() 方法中。
class ExampleScene extends Phaser.Scene {
// ...
update() {
this.physics.collide(this.ball, this.paddle);
}
}
第一个参数是我们感兴趣的对象之一——球,第二个是另一个对象,挡板。这有效,但并不完全如我们所料——当球撞击挡板时,挡板会从屏幕上掉下来!我们只希望球从挡板上反弹,而挡板保持在原地。我们可以将挡板的 body 设置为不可移动,这样当球撞击它时它就不会移动。为此,请在 create() 方法的末尾添加以下行。
this.paddle.body.setImmovable(true);
第二个您会注意到的问题是,球撞击挡板后,它开始水平移动而不是反射回来。要解决此问题,我们还需要在球本身上设置反弹因子(我们已经通过 setCollideWorldBounds() 为墙壁碰撞做了这一点)。将以下行添加到 create() 方法中,紧跟在 ball.body.setCollideWorldBounds(true, 1, 1) 行之后(我们希望将所有球的配置保留在一起)。
this.ball.body.setBounce(1);
现在它按预期工作。
控制挡板
下一个问题是我们无法移动挡板。要解决此问题,我们可以使用系统的默认输入(取决于平台,鼠标或触摸)并将挡板位置设置为 input 位置所在的位置。按所示方式将以下新行添加到 update() 方法中。
this.paddle.x = this.input.x;
现在,在每一帧中,挡板的 x 位置都会相应地调整为输入的 x 位置。但是,当我们开始游戏时,挡板的位置不在中间。这是因为输入位置尚未定义。要解决此问题,我们可以将默认位置(如果尚未定义输入位置)设置为屏幕的中间。将上一行更新为以下内容。
this.paddle.x = this.input.x || this.scale.width * 0.5;
如果您还没有这样做,请重新加载您的 index.html 并尝试一下!
定位球
我们已经使挡板按预期工作,现在让我们将其定位在球上。这与定位挡板非常相似——我们需要将其水平放置在屏幕中间,垂直放置在底部,并与底部保持一点偏移。为了将其精确地放置在我们想要的位置,我们将原点设置为球的精确中心。找到现有的 this.ball = this.add.sprite(...) 行,并将其替换为以下几行。
this.ball = this.add.sprite(
this.scale.width * 0.5,
this.scale.height - 25,
"ball",
);
速度几乎保持不变——我们只是将第二个参数的值从 150 更改为 -150,因此球将向上移动而不是向下移动开始游戏。找到现有的 this.ball.body.setVelocity() 行并将其更新为以下内容。
this.ball.body.setVelocity(150, -150);
现在球将从挡板的中间开始。
Compare your code
这是您到目前为止应该看到的效果,实时运行。要查看其源代码,请单击“播放”按钮。
后续步骤
我们可以移动挡板并让球从挡板上反弹,但如果球仍然从屏幕底部边缘反弹,那有什么意义呢?让我们引入失败的可能性——也称为 游戏结束 逻辑。