phina.jsのShapeを複数まとめて画像として使う

# はじめに

この記事では、phina.jsのv0.2を使用しています。
https://cdn.rawgit.com/phi-jp/phina.js/v0.2.0/build/phina.js

この記事の続編です
[phina.jsのShapeを画像として使う](http://qiita.com/simiraaaa/items/ba1f1648a6d0451b5abc)

あと、Shapeじゃなくても、画面に描画されているもの全てを画像にする事ができます。

# 普通のやり方

サンプル
http://runstant.com/simiraaaa/projects/shapeToImageRenderer
クリックすると、imgタグで追加されたり、Spriteで画面に追加されたりします。
流れだけ説明すると。

- Canvasのラッパーオブジェクトを作成
- `CanvasRenderer`のレンダリング対象に設定
- Sceneに追加するのと同じように、`DisplayElement`を`layer`として生成
- そこに描画したいShapeを追加していく
- 前回記事と同様にShapeは自分で`render()`を実行する
- `CanvasRenderer`で`layer`を`renderObject`する

```js

// 画像用にあたらしいCanvasを作る
var canvas = phina.graphics.Canvas();
canvas.setSize(640, 960);

// CanvasRenderer を生成する
var renderer = CanvasRenderer(canvas);

// 何もないオブジェクトを生成
var layer = DisplayElement();

// 星を100個ランダムに layerに追加
(100).times(function(i){
  var star = StarShape({
    // 色をカラフルに
    fill: 'hsla(' + (i * 3.6) + ', 80%, 60%,  1)',
    x: Math.randint(0, canvas.width),
    y: Math.randint(0, canvas.height),
  }).addChildTo(layer);
  
  // 星自体の描画
  star.render(star.canvas);
});

// layerの中身を canvasに描画
renderer.renderObject(layer);


```

これでレンダリングが終わったので、画像として取得します。

最初に生成したCanvasラッパーオブジェクトの`domElement`プロパティが実際の`Canvas`です。
`canvas.domElement`

あとはサンプルのように好きなようにいじってください。

`Sprite`として扱うときは、生成したCanvasラッパーオブジェクトをそのまま渡してインスタンス化すれば良いです。
`Sprite(canvas)`

# ちょっと楽なやり方

サンプル
http://runstant.com/simiraaaa/projects/shapeToImageDisplayScene

流れ

- DisplaySceneオブジェクトを`scene`として生成
- さっきの　`layer`にShapeを追加していく感覚で好きなように追加していく
- Shape自体のレンダリングも忘れずにやる
- scene._render()を実行する

```js

// 画像用にあたらしいDisplaySceneを作る
var scene = DisplayScene({
  width: 640,
  height: 960,
  backgroundColor: 'rgba(0, 0, 64, 0.2)',
});

// 星を100個ランダムに scene に追加
(100).times(function(i){
  var star = StarShape({
    // 色をカラフルに
    fill: 'hsla(' + (i * 3.6) + ', 80%, 60%,  1)',
    x: Math.randint(0, scene.width),
    y: Math.randint(0, scene.height),
  }).addChildTo(scene);
  
  // 星自体の描画
  star.render(star.canvas);
});

// sceneの内容を描画
scene._render();

```

これで、描画できました。
CanvasRendererを使う方法との違いは、自分でCanvasとCanvasRendererオブジェクトを生成しなくて良くなる点ですね。あとDisplayElementを`layer`として用意する必要もないですし、いつも`MainScene`の`init`で書いてるコードの感覚でやったあとに、自分で`scene._render()`を呼ぶだけです。

最初のコードと同様にCanvasラッパーオブジェクトを取得する場合は`scene.canvas`
Canvas自体を取得するには`scene.canvas.domElement`でできます。

なぜ、CanvasRendererとCanvasラッパーオブジェクトの生成を省略できたのかというと、`DisplayScene`がシーンの内容を描画するために、`init`内で生成しているからです。
最初から準備してくれているので、あとはそこに追加して、描画メソッドを呼ぶだけできるということです。


# CanvasApp を使う方法

サンプル
http://runstant.com/simiraaaa/projects/shapeToImageCanvasApp

流れ

- CanvasAppのインスタンスを生成(append:false)
- `scene`の取得(`app.currentScene`)
- Shapeを生成して、`scene`に追加(Shapeを自分で描画する必要はない)
- `app._update()`で追加したShapeの事前描画を一気に実行する
- `app._draw()`で`scene`の内容を描画する

```js

// 画像用にあたらしいCanvasAppを作る
var app = CanvasApp({
  width: 640,
  height: 960,
  // app の場合は backgroundColorを設定してもsceneのcanvasに直接反映されない
  //backgroundColor: 'rgba(0, 0, 64, 0.2)',
  // append を false にしないと bodyに自動的にcanvasが追加されてしまう!
  append: false,
});

// app のシーンを取得
var scene = app.currentScene;
scene.backgroundColor = 'rgba(0, 0, 64, 0.2)';

// 星を100個ランダムに scene に追加
(100).times(function(i){
  var star = StarShape({
    // 色をカラフルに
    fill: 'hsla(' + (i * 3.6) + ', 80%, 60%,  1)',
    x: Math.randint(0, scene.width),
    y: Math.randint(0, scene.height),
  }).addChildTo(scene);
  
  // 星自体の描画しなくても良い(あとでアップデートする)
  // star.render(star.canvas);
});

// app更新
app._update();
// appの中身描画
app._draw();

```

このあとは、`DisplayScene`のやり方と同じです。
`DisplayScene`でやる方法の違いは、Shapeを自分で描画しなくても良くなったことですね。
これは、`CanvasApp`が`Updater`という、phina.jsの更新用オブジェクトで、更新してくれるからです。(`_update()`)

ここまで、来ると逆に複雑なので、一番わかり易いのは`DisplayScene`でのやり方だと思います。

# おわりに
個人的には、DisplayScene辺りから画像化するのが、楽な印象です。
CanvasAppを使う場合は、よっぽど複雑な状態のSceneの内容を描画する場合などでしょうか。
まあ、あんまりここまで、まとめて画像化するのはやりませんけどねｗ
質問、要望等は遠慮なくどうぞ