Dartでplay_phaserを使ってゲームプログラミング

JavaScript向けの最近盛り上がってきている[Phaser](http://phaser.io/)というゲームフレームワークがありますが、これのDartへのPortとして、play_phaserというのがあります

[play_phaser 0.11.1 | Pub Package Manager](https://pub.dartlang.org/packages/play_phaser)

まだ作られ始めてから間もないので、バグがあったり、まだPortが完全ではない部分もあったりするようですが、とりあえず動かせます。ので、始め方を。

## pubspec.yaml

まずは、pubspec.yamlから。

```yaml:pubspec.yaml
name: play_phaser_sample
dependencies:
  browser: any
  play_phaser: 0.11.1
```

現時点での最新バージョンが`0.11.1`なので、そのように指定しておきます。常に最新にしておく場合は`any`とします。

pubspec.yamlを書いたら、`pub get`して、依存ライブラリをダウンロードさせておきます。

```bash
pub get
```

## index.html

HTMLを用意しておきます。

```html:index.html
<!DOCTYPE>
<html>
<head>
  <meta charset="UTF-8">
  <title>play_phaser Sample</title>
</head>
<body>
  <div id="play_phaser_sample"></div>
  <script type="application/dart" src="play_phaser_sample.dart"></script>
  <script src="packages/browser/dart.js"></script>
</body>
</html>
```

`<div id="play_phaser_sample"></div>`の中に、play_phaserの`<canvas>`を追加する想定で作成しました。この`<div>`の用意は必須ではありません。

## Dartプログラム

次に、Dartのプログラムを書きます。

```dart:web/play_phaser_sample.dart
library play_phaser_sample;

import 'package:play_phaser/phaser.dart';

main() {
  Game game = new Game(640, 480, AUTO, 'play_phaser_sample');
}
```

`library play_phaser_sample;`の指定は必須ではありません。

`Game`クラスのインスタンスを作成することが、第一歩になります。

`Game`クラスのコンストラクタの引数の宣言は以下のようになっています。

```dart
Game([num width = 800, num height = 600, int renderer = AUTO, String parent = '', State state, this.transparent, this.antialias, this.physicsConfig]) {
```

`width`、`height`には`<canvas>`のサイズを指定。

`renderer`には、以下のレンダラーの種類を指定。

```dart
const int AUTO = 0;
const int CANVAS = 1;
const int WEBGL = 2;
const int HEADLESS = 3;
```

`AUTO`は「WebGLが使えるならWebGLを、使えないならCanvasRenderingContext2Dを使う」で、`CANVAS`、`WEBGL`なら、それぞれCanvasRenderingContext2D、WebGLを直接指定、`HEADLESS`は`<canvas>`の生成をしない、です。たぶん、おそらく。

`parent`には、`<canvas>`を追加させたいDOM要素のIDを指定します。指定なし、もしくは空文字を指定した場合は、`<body>`にそのまま追加されます。

これら以外のパラメータについては、ここでは特に詳しく説明しません。

とにかくこれだけで、初期化処理の作成は完了です。

## JavaScriptへのビルド

ビルドしてみます。

```bash
pub build
```

`pub build`したら、buildディレクトリにビルド結果が出力されます。

```bash
% tree
.
├── build
│   └── web
│       ├── index.html
│       ├── packages
│       │   ├── browser
│       │   │   ├── dart.js
│       │   │   └── interop.js
│       │   └── play_pixi
│       │       └── extras
│       │           └── spine_license
│       ├── play_phaser_sample.dart.js
│       └── play_phaser_sample.dart.precompiled.js
├── pubspec.lock
├── pubspec.yaml
└── web
    ├── index.html
    └── play_phaser_sample.dart
```

## 実行

ビルドされたindex.htmlをChromeなどで開いてみます。

![play_phaser_sample01.png](https://qiita-image-store.s3.amazonaws.com/0/636/12989541-036e-d7c0-1613-6016201b6e74.png)

とりあえず真っ黒なCanvasが生成されています。

`pub serve`することで、ローカルでWebサーバーが立てられ、HTMLファイルやDartのプログラムの更新が自動で反映されるようになります。

```bash
$ pub serve
Loading source assets...
Serving play_phaser_sample web on http://localhost:8080
Build completed successfully
```

Webブラウザから localhost:8080 にアクセスすることで、実行を試すことができます。

## Stateを作成

Phaserは、`State`クラスが動作の基準となります。`State`はMVCで言うControllerの役割を果たします。

`State`を定義するには、`State`クラスを継承したクラスを実装します。

クラスごとにファイルを分けてプログラムを書くのが行儀がいいですが、今回はサンプルということで、1つのファイルにまとめて書きます。

```dart:play_phaser_sample.dart
...
main () {
  ...
}
...
class SampleState extends State {

  preload() {
    print('SampleState.preload');
  }

  create() {
    print('SampleState.create');
  }

  update() {
  }

}
...
```

各メソッドは、任意でオーバーライドします。

`State`を作成したら、`Game`クラスのコンストラクタの`state`パラメータに、作成した`State`クラスのインスタンスを渡します。

```dart:play_phaser_sample.dart
...
main () {
  Game game = new Game(640, 480, AUTO, 'play_phaser_sample', new SampleState());
}
...
```

ここで`State`のインスタンスを渡さない場合でも、あとで`State`を開始させることもできます。

```dart
...
Game game = new Game(640, 480, AUTO, '');
...
game.state.add('sample', new SampleState());
game.state.start('sample');
```

## Spriteを使って画像を表示

せっかくなので~~俺は赤の扉を~~、Spriteを使って画像を表示してみます。

まずは画像を用意します。

- web/assets/shida.jpg

![sample.jpg](https://qiita-image-store.s3.amazonaws.com/0/636/72a2f366-2d6c-6eda-9708-8d10cb97bb37.jpeg)

SampleStateの中に処理を書いていきます。

```dart:play_phaser_sample.dart
class SampleState extends State {

  Sprite _shida;

  preload() {
    game.load.image('shida', 'assets/shida.jpg');
  }

  create() {
    _shida = game.add.sprite(game.world.centerX, game.world.centerY, 'shida');
    _shida.anchor.set(0.5);
  }

  update() {
    _shida.angle += 1;
  }

}
```

シダ画像がくるくる回転します。

![play_phaser_sample02.png](https://qiita-image-store.s3.amazonaws.com/0/636/0083ce1f-5e59-d9a2-9258-10aef559c5a3.png)

以上です。