Phaser3でゲームを作るときに、フェードアウトとフェードインを活用してシーンを変える方法があります。しかも割と簡単。今回はその話です。
Phaser3においてシーン遷移する場合、なんの設定もしないといきなりシーンがバシッと変わってしまって、余韻もへったくれもありません。とはいえ、マスクを使ってシーンを変えるほどでもないしなーそういうのは他でやりたいなー、という場合に便利なのがフェードアウトとフェードインです。じわーっと画面がだんだん消えていって、消えきったなーと思ったら別の画面がじわーと現れる、この一連の動きを実装してみます。具体的には、遷移前のシーンをフェードアウトさせて、遷移後のシーンをフェードインさせるわけですね。
Phaser3でシーンを遷移させる場合はscene.start('nextScene')
を使うわけですが、これが実行されるとシーンが遷移します。ということは、これが実行される前にフェードアウトさせて、次のシーン側でフェードインさせるわけです。
今回はFirstScene
からSecondScene
に遷移するケースを考えてみます。
export class FirstScene extends Phaser.Scene {
constructor() {
super('firstScene');
}
create() {
const { width, height } = this.game.canvas;
this.add.text(width / 2, height / 2, 'First Scene').setOrigin(0.5);
const zone = this.add.zone(width / 2, height / 2, width, height);
zone.setInteractive({
useHandCursor: true
});
zone.on('pointerdown', () => {
zone.removeInteractive();
this.cameras.main.fadeOut(1200, 0, 0, 0);
// このシーンが完全にフェードアウトしてから次のシーンをstartする
this.cameras.main.once(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
this.scene.start('secondScene');
});
});
}
}
export class SecondScene extends Phaser.Scene {
constructor() {
super('secondScene');
}
create() {
this.cameras.main.fadeIn(1000, 0, 0, 0);
const { width, height } = this.game.canvas;
this.add.text(width / 2, height / 2, 'Second Scene').setOrigin(0.5);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
scene: [FirstScene, SecondScene]
};
new Phaser.Game(config);
シーンは前述のとおりFirstScene
とSecondScene
の2つで、これらをクラスで準備します。それぞれ、FirstScene
にはフェードアウトするコードを、SecondScene
にはフェードインするコードを実装しています。
this.cameras.main.fadeOut(1200, 0, 0, 0);
// このシーンが完全にフェードアウトしてから次のシーンをstartする
this.cameras.main.once(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
this.scene.start('secondScene');
});
上記の部分が、FirstScene
をフェードアウトさせているコードです。scene.cameras.main.fadeOut()
の第1引数にフェードアウトする時間、第2引数から第4引数まではそれぞれRGBの値をセットします。RGBの値はフェードアウトする色を指定できます。上記では真っ黒にフェードアウトしますが、「青色にフェードアウトしてほしい」という場合はfadeOut(1000, 0, 0, 255)
のように記述すればいいわけです。もちろん、100, 40, 180
のような値も設定可能なので、シーンの雰囲気によってフェードアウトする色を指定できます。
ちなみに、第5引数にはコールバック関数を指定できます。コールバック関数は、フェードアウトしている間ずっとフレームごとに呼び出されます。フェードアウトしてから呼び出されるものではないので注意。
フェードアウトし終わってから処理を行いたい場合は、scene.cameras.main.once()
の第1引数に「フェードアウトが終わったぜー」という意味のPhaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE
を渡してやります。すると、フェードアウトが完了したかどうかを勝手に判断してくれて、完了したら第2引数に指定されたコールバック関数を実行します。ここではSecondScene
に遷移しろよーと書いてあります。お察しのとおり、フェードアウトの完了以外にもイベントは存在していて、FADE_OUT_START
という「フェードアウトが始まったとき」というようにイベント開始をトリガーにできたりします。また、フェードアウト以外にもSHAKE_START
というシェイクに関するイベントも実装されています。
FADE_OUT_START
でフェードアウトの開始を検知して、BGMを変更する。FADE_OUT_COMPLETE
でフェードアウトの完了を検知して、シーンを変更する。上記のような一連の処理が、これらのイベントを組み合わせることで実装可能になるわけです。
なお、前後しますがフェードアウト処理の直前にあるzone.removeInteractive();
は、ゲームオブジェクトにsetInteractive()
で設定した「クリック可能」という状態を解除します。なんでこれが必要かというと、フェードアウトし終わる前に再度クリックされた場合、再びフェードアウト処理が実行されてしまうからです。つまりクリックを連打することで、後続処理へと遷移しなくなってしまいます。その事態を避けるため、一度クリックされたらゲームオブジェクトに対して設定されている「クリック可能」という状態を解除し、複数回クリックされないようにしてフェードアウト処理が実行されるのを1回きりに制限しています。
this.cameras.main.fadeIn(1000, 0, 0, 0);
上記の部分が、SecondScene
をフェードインさせているコードです。scene.cameras.main.fadeIn()
の引数構成はscene.cameras.main.fadeOut()
と同一です。こちらもRGBでフェードインする色を指定できるので、フェードアウトする色と同じ色を指定することでシームレスなシーン遷移が実装できます。
第5引数のコールバック関数に関しても、やはり同様です。フェードインしている間ずっとフレームごとに呼び出されます。フェードインしてから呼び出されるものではないので注意。そして、フェードインが完了したときに処理を行いたければ、FADE_IN_COMPLETE
イベントを検知すればいいわけです。こちらもやはり同様ですね。
See the Pen Change scene with fade in Phaser3 by ysko909 (@ysko909) on CodePen.
実際にCodepen上に実装してみました。クリックするとフェードアウトが発動して、フェードアウト完了時にシーンの遷移が行われます。遷移先のシーンではフェードインが発動して、遷移先のシーンがじわじわと表示される挙動を確認できると思います。
今回はPhaser3のシーン遷移について、フェードアウトとフェードインを導入して実装してみました。
フェードアウトもさることながら、フェードインに関しても「こんなに簡単に実装できるの?」というくらい全然記述してないですね。ホントにPhaser3様様です。
Phaser.Cameras.Scene2D. Camera
Phaser.Cameras.Scene2D. Events
Scene Transition with Fade Out in Phaser 3