前のページはこちら

Flameにはゲームウィジェット上に既存のウィジェットを載せる事が可能で、かつ、ゲームとの連携も出来ます。

簡単なウィジェットを載せてみる

ウィジェットの作成

簡単なStatelessWidgetでボタンを新しく作ってみます。GenerationButton.dartという名前でコードは下記となります。

import 'package:flutter/material.dart';
import 'your_game.dart';

class GenerationButton extends StatelessWidget {
  const GenerationButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {},
        child: const Text('Start'),
      ),
    );
  }
}

GameWidgetのパラメータにoverlayBuilderMapを追加

main.dartで呼んでいたGameWidgetのパラメーターにoverlayBuilderMapを追加します。「startButton」というKeyを定義し、そのkyeに対するウィジェットを登録しています。

登録時の第2引数にYourGame型のyourGameを定義しています。最後に先ほど作ったGenerationButtonを記述しています。

      body: GameWidget(
        game: yourGame,
        overlayBuilderMap: {
          'startButton': (context, YourGame yourGame) => GenerationButton(),
        },
      ),

ゲーム側で起動させる

your_game.dartでウィジェットを起動させます。onLoadだと上手く動かない時があったので、今回はonLoadが完了した後に呼ばれるonMountに記載します。overlays.addで先ほど定義したKeyを呼び出せば、ゲーム上にウィジェット(今回はスタートボタン)が出現します。

  @override
  Future<void> onMount() async {
    overlays.add('startButton');
  }

ゲームとの連携

ゲーム内の関数を実行したり、ゲーム内の値を参照したりと、ゲーム内との連携も可能です。コードを書き換えます。

your_game.dartに関数追加

your_gameに円をランダムで生成する関数を追加します。updateの方はまるっと消してしまいます。

  void makeCirecle() {
    //半径、X、Yのランダム値生成
    var randomRadius = Random().nextInt(50) as double;
    var randomX = Random().nextInt(300) as double;
    var randomY = Random().nextInt(300) as double;

    //CircleManを生成する。もうadd関数の中で生成しちゃう。
    add(CircleMan(randomRadius, Vector2(randomX, randomY)));
  }

GenerationButton.dart書き換え

GenerationButtonを下記に書き換えます。今回はStatefulWidgetです。

import 'package:flutter/material.dart';
import 'circle_man.dart';
import 'your_game.dart';

class GenerationButton extends StatefulWidget {
  const GenerationButton({Key? key, required this.yourGame}) : super(key: key);
  final YourGame yourGame;

  @override
  _GenerationButtonState createState() => _GenerationButtonState();
}

class _GenerationButtonState extends State<GenerationButton> {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('生成された円の数は' +
              widget.yourGame.children.query<CircleMan>().length.toString()),
          ElevatedButton(
            onPressed: () {
              widget.yourGame.makeCirecle();
              setState(() {});
            },
            child: const Text('Start'),
          ),
        ],
      ),
    );
  }
}

解説

  const GenerationButton({Key? key, required this.yourGame}) : super(key: key);
  final YourGame yourGame;

yourGame自体を保持します。

        children: [
          Text('生成された円の数は' +
              widget.yourGame.children.query<CircleMan>().length.toString()),
          ElevatedButton(
            onPressed: () {
              widget.yourGame.makeCirecle();
              setState(() {});
            },
            child: const Text('Start'),
          ),
        ],

テキストとボタンを出しています。

テキストの方は保持したyourGameを使って、以前使ったchildren.queryが使えます。lengthで取得したCircleManの数が取得できます。それをTextで出しています。

ボタンの方では先ほどyour_gameで定義したmakeCirecleを実行しています。

GameWidgetのパラメータも追加

GenerationButtonがyourGameを受け取るので、GameWidget側で渡す必要があります。下記のコードはGenerationButtonの引数としてyourGameを渡しています。

      body: GameWidget(
        game: yourGame,
        overlayBuilderMap: {
          'startButton': (context, YourGame yourGame) => GenerationButton(
                yourGame: yourGame,
              ),
        },
      ),

実行

Startボタンを押す度に円が出来ていきます。また、カウントも増えていくのが確認出来ます。

ウィジェットの消去

最後に、ボタンの消去をしてみます。your_game.dartのmakeCirecleを変更します。

  void makeCirecle() {
    //半径、X、Yのランダム値生成
    var randomRadius = Random().nextInt(50) as double;
    var randomX = Random().nextInt(300) as double;
    var randomY = Random().nextInt(300) as double;

    //CircleManを生成する。もうadd関数の中で生成しちゃう。
    add(CircleMan(randomRadius, Vector2(randomX, randomY)));

    if (children.query<CircleMan>().length > 50) {
      overlays.remove('startButton');
    }
  }

追加したif文は、生成されたCircleManの数が50を越えたら、overlays.removeでウィジェットを消去するという意味になります。これで実行すると、50を越えるとボタンが消えます。

次のページはこちら