动画
在 Phaser 中,可以从外部加载精灵表,并依次显示其中的帧来制作动画。例如,我们会让球在碰到物体时摆动。
首先,获取精灵表,并将其保存到你的 /img 目录中。
接下来,在 preload() 方法的末尾添加以下代码来加载精灵表:
this.load.spritesheet("wobble", "img/wobble.png", {
frameWidth: 20,
frameHeight: 20,
});
我们加载的不再是球的单张图片,而是包含多张图片的精灵表。依次显示其中的图片,就能形成动画效果。spritesheet() 方法的额外参数指定了精灵表中每一帧的宽度和高度,让程序知道如何将图片切分为单独的帧。
加载动画
接下来,进入 create() 方法,找到加载和配置球精灵的代码块,在其下方添加 anims.create() 调用,如下所示:
this.ball = this.add.sprite(
this.scale.width * 0.5,
this.scale.height - 25,
"ball",
);
// ...
this.ball.anims.create({
key: "wobble",
frameRate: 24,
frames: this.anims.generateFrameNumbers("wobble", {
frames: [0, 1, 0, 2, 0, 1, 0, 2, 0],
}),
});
要为对象添加动画,我们使用 anims.create() 方法,传入包含以下属性的对象:
key:为动画选定的名称。frameRate:以每秒帧数(fps)表示的帧速率。这里的动画以 24 fps 播放,共有 9 帧,因此每秒会播放略少于三遍。frames:定义动画播放时帧的显示顺序的数组。再看看wobble.png,你会发现它包含三帧。Phaser 会提取这些帧,并将它们的引用存储在数组的第 0、1 和 2 个位置。上面的数组表示依次显示第 0 帧、第 1 帧,再显示第 0 帧,依此类推。
当球击中球板时播放动画
在处理球与球板碰撞的 physics.collide() 调用中(即 update() 方法内的第一行,见下方),我们可以像处理 hitBrick() 方法那样,增加一个参数,指定每次碰撞时执行的函数。如下所示,更新 update() 方法中的第一行:
class ExampleScene extends Phaser.Scene {
// ...
update() {
this.physics.collide(this.ball, this.paddle, (ball, paddle) =>
this.hitPaddle(ball, paddle),
);
this.physics.collide(this.ball, this.bricks, (ball, brick) =>
this.hitBrick(ball, brick),
);
this.paddle.x = this.input.x || this.scale.width * 0.5;
// ...
}
// ...
}
然后创建接收 ball 和 paddle 参数的 hitPaddle() 方法,在调用时播放摆动动画。将以下方法添加到 hitBrick() 方法的上方:
class ExampleScene extends Phaser.Scene {
// ...
hitPaddle(ball, paddle) {
this.ball.anims.play("wobble");
}
// ...
}
每当球击中球板时,动画就会播放。如果你觉得这样能让游戏看起来更好,也可以在 hitBrick() 方法中调用 anims.play()。
补间
动画会依次播放精灵表中的图像,而补间则会平滑地改变游戏世界中对象的属性,例如宽度或不透明度。
让我们添加一个补间,使砖块在被球击中后平滑消失。在 hitBrick() 方法中找到 brick.destroy();,并将其替换为以下代码:
const destroyTween = this.tweens.add({
targets: brick,
ease: "Linear",
repeat: 0,
duration: 200,
props: {
scaleX: 0,
scaleY: 0,
},
onComplete() {
brick.destroy();
},
});
destroyTween.play();
我们来看看这段代码的作用:
- 定义补间时,需要指定目标对象的哪些属性要发生变化。这里我们希望砖块被球击中后不立即消失,而是将宽度和高度逐渐缩小到零。为此,我们调用
tweens.add(),将brick指定为targets,并在props对象中指定要改变的scaleX和scaleY属性。 - 还可以设置
ease来指定缓动函数(这里是Linear),用repeat指定补间的重复次数(0表示不重复),并用duration指定补间完成所需的时间,单位为毫秒。 - 可选的
onComplete事件处理器定义了补间结束时执行的函数。 - 最后,调用
play()方法立即启动补间。
比较你的代码
以下是到目前为止应得到的实时运行效果。要查看其源代码,请点击“运行”按钮。
下一步
动画和补间让游戏画面更生动,但我们还可以继续完善游戏。在下一节中,我们将学习如何处理按钮输入。