Flutter flame のサンプルコードを紐解く

# サンプルコードの動かし方
以下をクローンします。他のサンプルもありますが、以下のコードが最もシンプル？だと思われます。

https://github.com/flame-engine/flame/tree/main/packages/flame/example

# サンプルコードの動き
* 起動すると、黒い画面に四角がくるくる回っている
* 四角をクリックすると、四角が消える
* 四角以外の場所をクリックすると、くるくる回る四角が増える

# ソースコードの中身
## main 関数
* `main`関数内では、いつもの`MaterialApp`ではなく`GameWidget`が呼ばれています。  
* `GameWidget`には引数として`MyGame`（後述）クラスが渡されています。

```dart:main.dart
void main() {
  runApp(
    GameWidget(
      game: MyGame(),
    ),
  );
}
```

### わかったこと

* ゲームを開始するときは`GameWidget`を使う。

### 疑問
* 最初は`MaterialApp`でスタートし、例えばボタンをクリックしたら`GameWidget`を呼ぶとかもできるのか？
* 画面の大きさはどのように指定するか？

## MyGame クラス

* `MyGame` クラスは `FlameGame` を継承して作られています。
* また、`MyGame` クラスは `HasTappableComponents` を mixin して作られています。
* `onLoad`をオーバーライドして、ゲーム開始時に四角（`Square`クラス）が1つある状態にしています。
* `onTapDown`をオーバーライドして、タップダウンイベントがあったときに四角を追加する処理を実行しています。

```dart:main.dart
/// This example simply adds a rotating white square on the screen.
/// If you press on a square, it will be removed.
/// If you press anywhere else, another square will be added.
class MyGame extends FlameGame with HasTappableComponents {
  @override
  Future<void> onLoad() async {
    add(Square(size / 2));
  }

  @override
  void onTapDown(TapDownEvent event) {
    super.onTapDown(event);
    if (!event.handled) {
      final touchPoint = event.canvasPosition;
      add(Square(touchPoint));
    }
  }
}
```

### わかったこと
* 必要なジェスチャー（`HasTappableComponents`）は mixin で指定する。
* `onLoad`でゲーム開始時に実行したい処理を実行できる。
* mixin したジェスチャーに応じてイベント処理を定義できる。
* `event.canvasPosition`でクリック（タップ）した場所を取得している。

### 疑問
* 他にはどのようなジェスチャーが対応している？
* `event.handled`とは？

## Square クラス
* `RectangleComponent`を継承して作られている。
* `TapCallbacks`を mixin して作られている。
* `RectangleComponent`は`position`、`size`、`anchor`が指定できる。
* 定期的に実行される`update`関数でくるくるさせている。
* `RectangleComponent`は`angle`フィールドを持っていて、それを更新すると角度が変わる。
* `onLoad`で`Square`が生成された際に真ん中の赤い四角と角にある青い四角を追加している。
* `onTapDown`で自身を消したあとに、`event.handled`を`true`にセットしている。

```dart:main.dart
class Square extends RectangleComponent with TapCallbacks {
  static const speed = 3;
  static const squareSize = 128.0;
  static const indicatorSize = 6.0;

  static Paint red = BasicPalette.red.paint();
  static Paint blue = BasicPalette.blue.paint();

  Square(Vector2 position)
      : super(
          position: position,
          size: Vector2.all(squareSize),
          anchor: Anchor.center,
        );

  @override
  void update(double dt) {
    super.update(dt);
    angle += speed * dt;
    angle %= 2 * math.pi;
  }

  @override
  Future<void> onLoad() async {
    super.onLoad();
    add(
      RectangleComponent(
        size: Vector2.all(indicatorSize),
        paint: blue,
      ),
    );
    add(
      RectangleComponent(
        position: size / 2,
        size: Vector2.all(indicatorSize),
        anchor: Anchor.center,
        paint: red,
      ),
    );
  }

  @override
  void onTapDown(TapDownEvent event) {
    removeFromParent();
    event.handled = true;
  }
}
```

### わかったこと
* `GameWiget`->`FlameGame`->`XXXComponent` という関係性で構成されている。
* `update`でコンポーネントごとに定期的に実行したい処理を書ける。
* `Square`以外の場所がタップされた場合は、`MyGame`の`onTapDown`のみが実行される。
* `Square`がタップされた場合は、`Square`の`onTapDown`が実行されたあと、`MyGame`の`onTapDown`が実行される。
    * このとき`event.handled`が`true`にセットされているため、`MyGame`の`onTapDown`での`Square`追加処理がスキップされている。

### 疑問
* 他のはどのようなコンポーネント、ジェスチャーがあるか？