Flutter Flameでシーン(Router World)の切り替え方法まとめ

Flutter Flame でゲーム制作をする時に役立つのが Router だ。

今回は、このRouterの処理を解説する。

FlameにおけるRouter , Worldとは何か?

他のゲームエンジン、ライブラリで言うところの以下のものになる。

  • Router → SceneManager シーンマネージャー
  • World → Scene シーン

他のゲームエンジン同様、 RouterComponentではシーン(World)をstackとして積んでいく

実際にコードを見ていく。

以下の例ではTitleSceneGameSceneを作成している。

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GameWidget(game: SampleGame());
  }
}

class SampleGame extends FlameGame {
  late final RouterComponent router;

  @override
  Future<void> onLoad() async {
    super.onLoad();

    // デフォルトでは、Vectorなどの位置関係が、中央を基準にしている。
    // 例えば、 Vector2(100, 200) と指定した時に、中央から x: 100 y 200 の位置が指定される。
    // Anchor.topLeftと指定することで、左上を基準にできる。
    camera.viewfinder.anchor = Anchor.topLeft;

    await add(
      router = RouterComponent(
        routes: {
          'title': WorldRoute(TitleScene.new),
          'game': WorldRoute(GameScene.new),
           // maintainState: デフォルトで true。 
           // true : 1ど構築したworldを維持し続ける。
           // false: worldが呼ばれるたびにworldを再構築する
          'level2': WorldRoute(MyWorld2.new, maintainState: false),
        },
        initialRoute: 'title',
      ),
    );
  }
}

そして、実際のWorldでは以下のように定義する。

class TitleScene extends World with TapCallbacks, HasGameReference<SampleGame> {

  @override
  Future<void> onLoad() async {
    super.onLoad();

    // いろいろなComponentを定義する。ここではテキストを定義しよう。
    await add(
      TextComponent(
        text: 'Title Scene',
        position: Vector2(100, 200),
        // anchor: Anchor.center,
        textRenderer: TextPaint(
          style: const TextStyle(fontSize: 32, color: Colors.white),
        ),
      ),
    );

  }

  @override
  bool onTapDown(TapDownEvent event) {
      // game sceneに遷移する。
      game.router.pushReplacementNamed('game');

      // game.router.pop();
      // game.router.pushReplacementNamed("game");

      return true;
  }
}

HasGameReferenceはFlameが用意しているMixInで、 Worldオブジェクトにgameプロパティを追加してくれる。

gameプロパティがrouterオブジェクトを持っているので、 HasGameReferenceを使うとroute処理がしやすくなる。

HasGameRefというMixInもあるが、version 1.30.1 では、deprecated(非推奨)になっている。

RouterによるWorldの遷移方法

Routerでworldを遷移するには以下の方法がある。

  • router.pushReplacementNamed('game');
  • game.router.pushReplacementNamed("game");
  • game.router.pop();

シンプルで覚えやすい。

参考文献

公式ドキュメントぐらいしかない。悲しい。