Posted at
phina.jsDay 20

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

More than 1 year has passed since last update.


はじめに

この記事では、phina.jsのv0.2を使用しています。

https://cdn.rawgit.com/phi-jp/phina.js/v0.2.0/build/phina.js

この記事の続編です

phina.jsのShapeを画像として使う

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


普通のやり方

サンプル

http://runstant.com/simiraaaa/projects/shapeToImageRenderer

クリックすると、imgタグで追加されたり、Spriteで画面に追加されたりします。

流れだけ説明すると。


  • Canvasのラッパーオブジェクトを作成


  • CanvasRendererのレンダリング対象に設定

  • Sceneに追加するのと同じように、DisplayElementlayerとして生成

  • そこに描画したいShapeを追加していく

  • 前回記事と同様にShapeは自分でrender()を実行する


  • CanvasRendererlayerrenderObjectする


// 画像用にあたらしい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()を実行する


// 画像用にあたらしい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として用意する必要もないですし、いつもMainSceneinitで書いてるコードの感覚でやったあとに、自分で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の内容を描画する


// 画像用にあたらしい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を自分で描画しなくても良くなったことですね。

これは、CanvasAppUpdaterという、phina.jsの更新用オブジェクトで、更新してくれるからです。(_update())

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


おわりに

個人的には、DisplayScene辺りから画像化するのが、楽な印象です。

CanvasAppを使う場合は、よっぽど複雑な状態のSceneの内容を描画する場合などでしょうか。

まあ、あんまりここまで、まとめて画像化するのはやりませんけどねw

質問、要望等は遠慮なくどうぞ