Phaser3 シーン管理

phaser

Phaser3 シーン管理

前回の記事
https://mijinc0.github.io/blog/post/20200820_phaser3_about/

Phaser3のシーン管理について。
※ typesriptで書くことを前提にしています

基本

Phaserのシーンを扱う時、チュートリアルに従って書くとSceneを継承したクラスを自分で用意することになると思う。

Sceneクラスにはinit,preload,create,updateを用意し、シーンが開始して終了するまで、それぞれのフェーズで必要な処理をそこに書いていく。

上記は公式のチュートリアルでも説明されていたはずなので上記で簡単におさらい。

preloadpreload中にLoaderPluginを使ったアセットのロード処理が全て完了したら、次のcreateが呼び出されるようになっている。また、シーンに描写したいスプライトなどを配置する処理を書くのは主にcreateになるが、preload中にオブジェクトを配置しても描写はされる。これは、簡単なローディングシーンを実装するときに使える。

シーンの開始について

SceneManageradd関数によって追加されたシーンを開始する方法はいくつかある。

SceneManagerGameクラス内でthis.sceneをするとアクセス出来、ScenePluginSceneクラス内で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関数は指定されたシーンの状態によって挙動を変える。

全く動いていないシーンに対しては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の開始まとめ

使い分けとしては以下のようにまとめる。

  1. Gameクラス内において、シーンを開始するだけであればstartを使う
  2. Gameクラス内において、シーンの状態によって新規開始、再開、などを分けたければrunを使う
  3. Sceneクラス内において、現在のシーンを停止して新しいシーンを新規開始したければstartを使う
  4. Sceneクラス内において、現在のシーンをそのままに新しいシーンをその状態によって新規開始、再開、などを分けて開始したければrunを使う
  5. 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