phina.jsでゲームを開発するためのボイラープレートを作った

## 概要
phina.jsはJavaScriptで作られたゲームライブラリです。
他のゲームライブラリよりも、**簡単**かつ**国産**ということで初心者に親しみやすいことが特徴です。

先日、知り合いから`phina.js`のことを聞いたので調べたところ、ゲームを作る欲が満ち満ちてきました。

> 簡単なら試しにゲーム作ってみるか

と意気揚々に

```
$ npm init
$ npm install phina.js
```

と打ったら・・・`phina.js`のバージョンが低い。
npmには最新は上がっていない模様。yarnも試しましたが変わりありませんでした。

ついでにフォルダ構成やアーキテクチャも調べてみたんですが、あまり出てこず・・・。

じゃあ自分でまず環境を作るか！とボイラープレートを作ったという次第です。

## クイックスタート

https://github.com/tosaka07/phina-boilerplate

ここからcloneするなり、ZIPでダウンロードするなりお好きにどうぞ！

```bash
$ git clone git@github.com:tosaka07/phina-boilerplate.git
```

取ってきたら、ルートディレクトリに移動しましょう。

### 開発する

```bash
$ npm install
$ npm run dev
```

HTTPサーバーが立ちます。[http://localhost:4444](http://localhost:4444)にアクセスしてみてください。

**Hello phina.js!**と表示されていたら成功です。

### リリースする

```bash
$ npm install
$ npm run build
```

bundleフォルダにjsが生成されていたら成功です。

## 構成

```
dist/
  └ index.html
src/
  └ js/
.gitignore
fuse.js
package.json
package-lock.json
```

初期はこのような状態です。実際に開発する際には、src/js/Sceneの方にフォルダを分けて開発する感じですかね。

## phina.js

どうやって最新のphina.jsを取って来るべきか。考えた結果、[phina.jsのリポジトリ](https://github.com/phi-jp/phina.js)から直接取ってくることにしました。masterブランチだと古いままなため、developブランチから取ってきます。~~地味に危ない~~

`npm install`するときにブランチから取ってきますので、あんまり意識する必要ないかも。

### ファイルを分けたい

何かコンポーネントを作ったら、`index.js`に読み込みましょう。

`import コンポーネント名 from "パス";`と読み込み、`コンポーネント名()`とメソッドを呼ぶ感じにしたら動きます。

以下の部分はmainSceneとsampleShapeを別ファイルに分けたときのサンプルです。

```index.js
import * as phina from "phina.js";
import mainScene from "./Scene/main";
import sample from "./Shape/sample";

phina.globalize();

mainScene();
sample();

phina.main(function() {
  var app = GameApp({
    startLabel: 'main'
  });
  app.run();
});
```

```main.js
import * as phina from "phina.js";

export default function() {
  phina.define('MainScene', {
    superClass: 'DisplayScene',
    init: function() {
      this.superInit();
      var label = Label('Hello, phina.js!').addChildTo(this)
        .setPosition(this.gridX.center(), this.gridY.center());
    }
  });
}
```

## モジュールバンドラ

phina.jsの作品のコードみたらほとんどモジュール化されていない。元々そういう設計であれば仕方がないのですが、できれば分けたいということでバンドラを用意しています。

Webpack・Rollup・browserifyと沢山ありますが、今回は`Fusebox`を採用しました。理由は、**新しくて早いから**です。~~今思えば他のほうが良かったかも~~

Fuseboxの説明は[こちら](https://qiita.com/suttang/items/a3420a34b82e9a5a4389)から。

```fuse.js
const {FuseBox, Sparky, UglifyESPlugin} = require('fuse-box');

let fuse;
let isProduction = false;

const outputName = 'bundle';
const start = `> index.js`;
const homeDir = 'src/js';
const outputDir = 'dist/';
const output = `${outputDir}js/$name.js`;


// Production判定用
Sparky.task('set-production', () => {
  isProduction = true;
});

// 基本
Sparky.task('config', () => {
  fuse = FuseBox.init({
    homeDir: homeDir,
    output: output,
    sourceMaps: !isProduction,
    cache: !isProduction,
    plugins: isProduction
    ? [ UglifyESPlugin() ]
    : []
  });
  app = fuse.bundle(outputName).instructions(start);
});

// Develop用
Sparky.task('default', ['config'], () => {
  fuse.dev({
    port: 4444,
    root: outputDir,  // ルートディレクトリを指定。
    httpServer: true  // http サーバ機能を有効化するかどうかを指定。デフォルトは true
  });

  app.watch();
  return fuse.run();
});

// Production用
Sparky.task('prod', ['set-production', 'config'], () => {
  return fuse.run();
});
```

ポートはデフォルトで4444になっています。被っていたり他のポートにしたい場合、`port: 4444`のところを変更してみてください。

## まとめ

実運用に耐えるかはもうちょっと開発を進めなければわかりません。  
なにか修正してほしいところがあればコメントでも良いですし、githubのプルリク、issueを作っていただければ反応します。