Flutterの2DゲームエンジンFlameはドット絵ゲーム作成におすすめ👾

本記事は[Flutter #2 Advent Calendar 2020の5日目](https://qiita.com/advent-calendar/2020/flutter-2)の記事です:santa:

# はじめに
2020年はゲームギアミクロ、ミニテトリス、ゲーム&ウォッチなど携帯ゲームがいっぱい発売されました！

<img width=480 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/2ad48fb0-9b4f-c9ef-9136-a2e18c5938d5.jpeg" />

というわけでゲームギアミクロと同じくらいのサイズのAndroidスマホ、Jelly Pro向けにゲーム&ウォッチ風アプリを作ってみました。(上の大きく見えるのはPixel4です)

<img width=480 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/96000ca1-a28b-d5cb-6c9f-eb2ed5c94b8c.jpeg" />

前々から調査していたのですが、12/1〜12/3にドット絵を書いて、12/4の仕事終わりからコードを書いて12/5にできたサンプルコードが以下になります。

ソースコード: https://github.com/keidroid/flame_santa/

衝突判定やスコアなどのゲーム要素は作っていないのですが、プレゼントが上から落ちてきて、左右キーでサンタが動かせるようになっています。

<img width=480 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/62fefef6-541a-5792-aa92-ec2ed0663ed6.gif" />

今回FlameというFlutterの2Dゲームエンジンで作ったのですが、Flameの良いところをサンプルアプリのコードの解説しつつ紹介していきます。
ちなみに、Flameは2020年12月5日現在、安定版が0.82.0なのですが11月から1.0.0-rc1がリリースされています。もうすぐ1.0.0の正式版がリリースされるとのことです:tada:

https://flame-engine.org/
https://github.com/flame-engine/flame

# Flameの良いところ
## セットアップがかんたん

パッケージ化されているのでpubspecに1行追加し、 `flutter pub get`するのみです。

```pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flame: ^1.0.0-rc2 //この行をたす
```

https://pub.dev/packages/flame/install

## ゲームのための初期設定がかんたん

Flameの初期設定は以下のように行います。
基本的にはFlame.initを呼び出すだけでFlame.utilに集約されています。
Flame.util.setLandscapeを呼び出すと右向き・左向きの横画面に両対応します。

```main.dart
void main() async {
  await Flame.init(
      fullScreen: true, orientation: DeviceOrientation.landscapeRight);

  await Flame.util.setLandscape();
  await Flame.util.initialDimensions();
  : 
```

## Widgetを使うことでドット絵向けのゲーム画面が作りやすい

今回サンプルアプリの画面のドット絵部分は64x64となっています。
スマホ向けゲームでは異なる解像度や画面サイズに対応しないといけないのがつらいですが、Flameではゲーム画面をWidgetとして扱うことで対応できます。
FlutterのSizedBox Widgetを使えば、画面解像度(今回は64x64)を保ったまま画面いっぱいに引き伸ばすことが可能です。
これによってドットがボケることもありません。

```.dart
   SizedBox(width: 64, height: 64, child: game.widget)))),
```

Unityのような3D系のゲームエンジンだと、初期設定で拡大するとぼやけた2D画像になるものが多いため、ドット絵のゲームにおすすめです。

## 操作系UIをゲーム画面外に配置できる

ゲーム画面内のタッチイベントでも操作可能ですが、今回はゲーム画面外の画面端にButtonを配置しました。
FlameではGameをWidgetとして扱えるので他Widgetとの連携を簡単に行うことができます。ゲーム自体はドット絵にして、ボタンをリアルにすることなども可能です。

今回のサンプルアプリではGame WidgetとButton Widgetを均等配置することで、サイズが違う端末でも親指で操作できるようになっています。

Pixel4 と Jelly Pro のキャプチャ比較: ボタン位置(灰色)が調整されている
<img width=250 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/9c5b3ed3-f3e4-1b9a-4840-5cfc82906aa7.png" /> <img width=200 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19692/80d9b1f8-f65b-a0a4-9556-5aa648c0ba83.png" />

## 画像の回転・反転がかんたん
FlutterのみでImageクラスを扱おうとすると、[行列計算を使用しないと回転・反転ができなかった](https://qiita.com/keidroid/items/ac213910980bc125995a)のですがFlameではComponentクラスでラップされており、回転・反転操作がしやすくなっています。

https://flame-engine.org/docs/components.md

```.dart
    import 'package:flame/components/component.dart';

    Sprite sprite = Sprite('player.png');

    final size = Vector2.all(128.0);
    var player = SpriteComponent.fromSprite(size, sprite);

    // screen coordinates
    player.position = ...
    player.angle = 30; // 回転はangle指定
    player.renderFlipX = true; // 反転はflipで指定
    player.render(canvas);
```
## 表示形式のサポート
2Dゲームには必須のSpriteSheet形式はもちろん、Flutterで使用できるSVGやRive(元Flare)もGame Widget内に組み込むことができます(未検証)
他にもParticles、Tilemap、Parallaxなど2Dゲームに必要そうな機能が一通りあります。
https://flame-engine.org/docs/components.md

## Flutter Webで動作する
Flutter本体の動作が危ういですがFlame自体は動作しました！
以下ページのFirebase Hostingで公開します。

https://flame-santa.web.app/

Flutterのビルド後にCSSを追記しました。
CSS側でレンダリングを `pixelated` 指定すればドット絵がボケずに拡大します。

```css

body {
  image-rendering: pixelated;
}
```

## 2D物理演算がバンドルされている
少し前までBox2Dをサポートしていたのですが、1.0.0-rc2現在は派生のForge2dをサポートしています。通常のBox2Dと同じ用に扱うことができます。

Forge2d
https://github.com/flame-engine/flame_forge2d
Box2D
https://pub.dev/packages/flame_box2d

## 派生の2D RPGゲームエンジンがある
FlutterとFlameを使用して、Bonfireという2DのRPGエンジンを作られている方がいます。
https://github.com/RafaelBarbosatec/bonfire

# Flutter+Flameを使ってみて気になったところ

- 非力な端末だとFlutterのGestureDetectorでイベントが抜けることがあった
- fpsを落とす機能が見当たらない. (ドット絵ゲームはカクカクにしたい)
- ~~Kotlinで書きたい~~

# まとめ
ドット絵のゲームやミニゲームを作成する方にはFlameとてもおすすめです。
今までFlameの0.x.x系を使用していたのですが、1.0.0ではFlutterのデフォルトの機能をより生かして独自クラスを減らした構成になっているように感じました。


以下はFlutterでゲーム制作を模索する過去ログです。Flameを使用することでFlutterでのゲーム作成のしきいが一気に下がったように思います。

第1弾: Flutterを半日くらいやって良さげだと思ったこと
https://qiita.com/keidroid/items/dd3230dba329eb9f82c5
第2弾: Flutterで作ったミニゲームをFlutter for Webに移植した
https://qiita.com/keidroid/items/84691d1c891061298144
第3弾: Flutterの低レイヤー周り - Flutterでゲーム制作はできそうか調査してみた
https://qiita.com/keidroid/items/ac213910980bc125995a