Phaser3 シーン管理
Posted
Phaser3 シーン管理
前回の記事
https://mijinc0.github.io/blog/post/20200820_phaser3_about/
Phaser3のシーン管理について。
※ typesriptで書くことを前提にしています
基本
Phaserのシーンを扱う時、チュートリアルに従って書くとScene
を継承したクラスを自分で用意することになると思う。
Scene
クラスにはinit
,preload
,create
,update
を用意し、シーンが開始して終了するまで、それぞれのフェーズで必要な処理をそこに書いていく。
init
: 主にpreload前にやっておきたい初期化処理を書くpreload
: 主にアセット(スプライトや音楽など)を読込む処理を書くcreate
: シーンにタイルマップやスプライトを配置する処理を書く(シーンを作るメインはここ)update
: 1フレーム毎に実行される処理を書く
上記は公式のチュートリアルでも説明されていたはずなので上記で簡単におさらい。
preload
はpreload
中にLoaderPlugin
を使ったアセットのロード処理が全て完了したら、次のcreate
が呼び出されるようになっている。また、シーンに描写したいスプライトなどを配置する処理を書くのは主にcreate
になるが、preload
中にオブジェクトを配置しても描写はされる。これは、簡単なローディングシーンを実装するときに使える。
シーンの開始について
SceneManager
のadd
関数によって追加されたシーンを開始する方法はいくつかある。
SceneManager
のstart
関数SceneManager
のrun
関数ScenePlugin
のstart
関数ScenePlugin
のrun
関数ScenePlugin
のlaunch
関数- (
ScenePlugin
のrestart
関数)
SceneManager
はGame
クラス内でthis.scene
をするとアクセス出来、ScenePlugin
はScene
クラス内でthis.scene
をするとアクセス出来る。似たような操作感で似たような関数を使うことになる部分が"ややこしい"ポイント。
import * as Phaser from 'phaser';
export class CustomGame extends Phaser.Game {
constructor() {
const config: Phaser.Types.Core.GameConfig = {
// 色々書く
};
super(config);
// SceneManager
this.scene;
}
}
import * as Phaser from 'phaser';
export class CustomScene extends Phaser.Scene {
init(data: any): void {
// ScenePlugin
this.scene;
}
}
それぞれ簡単に見ていく。
SceneManager.start
これがSceneManagerでシーンを開始する時の基礎的な関数。
SceneManager.run
run関数は指定されたシーンの状態によって挙動を変える。
- pause状態 : resume関数を呼ぶ
- sleep状態 : wake関数を呼ぶ
- 完全な停止状態 : start関数を呼ぶ
全く動いていないシーンに対してはrun
でもstart
でも、結局のとろこrun
関数内でstart
を呼ぶので同じことをしている。
ScenePlugin.start
現在のシーン (ScenePluginはSceneクラス内でscene
プロパティにアクセスすることを思い出して欲しい) を停止して、新たに指定したシーンを開始する。
ScenePlugin.run
SceneManagerのrunを呼ぶのと同じ。
ScenePlugin.launch
SceneManagerのstartを呼ぶのと同じ。だが、ScenePlugin.start
が現在のシーンを停止して、新しいシーンをstartさせるのに対し、こちらは新たしいシーンをstartさせるだけであることに注目してほしい。
関数の説明に “Launch the given Scene and run it in parallel with this one.” とあるのはそのため。
Sceneの開始まとめ
使い分けとしては以下のようにまとめる。
- Gameクラス内において、シーンを開始するだけであれば
start
を使う - Gameクラス内において、シーンの状態によって新規開始、再開、などを分けたければ
run
を使う - Sceneクラス内において、現在のシーンを停止して新しいシーンを新規開始したければ
start
を使う - Sceneクラス内において、現在のシーンをそのままに新しいシーンをその状態によって新規開始、再開、などを分けて開始したければ
run
を使う - Sceneクラス内において、現在のシーンをそのままに新規開始したければ
launch
を使う
マルチシーン
Phaser3では並行して複数のシーンを動かすことが出来る。
“並行して” とあるが、非同期で動いているわけではない。一つのフレーム(一回のupdateループ)内で複数のシーンが同時にupdateされるという意味である。動かす順番は、SceneManager.add
によって追加した順に動く。(後から変えることも出来る)
この順番は大事で、SceneManager.add
で追加された順に描写される、つまり、後から追加されたシーンの描写は重なった時に手前に描写されるということを意味する。
例えば、画面を真っ暗にした状態でメッセージだけ表示したいときのことを考えてみる。勿論一つのシーン内でdepth(z-index)
を調整してメッセージのみを表示することは可能だ。だが、とても面倒くさいと思わないか。また、雨のエフェクトを画面に追加するときのことを考えてほしい。
雨のエフェクトはほしいが、メッセージが見づらくなるのは嫌だとなると、一つのシーンでそれを調整するのは面倒ではないか。
これらを解決する方法として、複数のシーンを立てておいてメッセージなどのUIは手前のシーンに描写、キャラクターなどが存在するシーンと分けるという手段がある。これなら、それらをdepth
の調整をせずに達成することが出来る。メッセージボックス等のUIを必ず手前のシーンに描写すると決めてしまえば、ゲーム本体のシーンがフェードアウトして真っ暗になってもメッセージボックスは表示できるし、雨のエフェクトがかかっていてもメッセージボックスには影響を与えない。
参考
https://github.com/photonstorm/phaser/blob/v3.22.0/src/scene/SceneManager.js
https://github.com/photonstorm/phaser/blob/v3.22.0/src/scene/ScenePlugin.js
https://photonstorm.github.io/phaser3-docs/Phaser.Scenes.SceneManager.html
https://photonstorm.github.io/phaser3-docs/Phaser.Scenes.ScenePlugin.html