ビットマップフォント画像を他とまとめて１ドローコールを目指す

タイトルのような事がStarling2.0(1.xでも行けるかも）で、そこそこ簡単にできたので記事にまとめておきます。

#概要
ドローコールは少しでも減らしたいですよね。しかしビットマップフォントを入れ込むとテキストを差し込んだ位置によっては１回２回でなく怒涛のようにドローコールが増えてしまいます。(画像、テキスト、画像、テキスト。。というような順番の繰り返しなっているとそのような事がおきる。）このような時にビットマップフォントデータを他の画像とともにまとめてしまうとドローコールが１つになって非常に都合がいいです。

昔作ったアプリでは、これを真面目にヘルパークラスやらユーティリティやらを作って実装していたのですが、この間やり直してみたら簡単にできてしまったので記事にまとめておきます。

#まとめる前

![nums1.png](https://qiita-image-store.s3.amazonaws.com/0/8302/645deb15-f682-ada2-d30b-7e82a844bea9.png) 赤いの(nums1.png, nums1.fnt)と

![nums2.png](https://qiita-image-store.s3.amazonaws.com/0/8302/33f78e0e-ad45-be28-5caf-7b82da65c881.png) 緑の(nums2.png, nums2.fnt)ビットマップフォントデータを用意。
XMLデータは割愛。(適当にテキストエディタで作成)

<img width="379" alt="cap1.png" src="https://qiita-image-store.s3.amazonaws.com/0/8302/4314b879-5a40-a0ee-603e-2a8aa3ba24ce.png">
こんな単純な例でもドローコールが５回も！

```sample1.as
// AssetManagerでの読み込み部分
_assetManager = new AssetManager();
_assetManager.enqueueWithName('app:/assets/nums1.png'); //フォント１画像
_assetManager.enqueueWithName('app:/assets/nums1.fnt'); //フォント１設定
_assetManager.enqueueWithName('app:/assets/nums2.png'); //フォント２画像
_assetManager.enqueueWithName('app:/assets/nums2.fnt'); //フォント2設定
_assetManager.enqueueWithName('app:/assets/pappey.png'); //ロボ画像
```

#まとめた後

適当なテクスチャパッキングツールで(ここではTexturePacker4.1.0を利用)３枚の画像をまとめます。
そしてAssetManagerの記述を変えるだけ？です。

![atlas.png](https://qiita-image-store.s3.amazonaws.com/0/8302/144cc022-8fd6-8b0b-8c06-16dc372c7c59.png)
_画像１枚 atlas.png + 設定XML１つ atlas.xml_

```sample2.as
// AssetManagerでの読み込み部分
_assetManager.enqueueWithName('app:/assets/atlas.png'); //アトラス画像
_assetManager.enqueueWithName('app:/assets/atlas.xml'); //アトラス設定
_assetManager.enqueueWithName('app:/assets/nums1.fnt'); //フォント１設定
_assetManager.enqueueWithName('app:/assets/nums2.fnt'); //フォント2設定
```

これで、全く同じ動きをします。なぜでしょう？ それはBitmapフォントを作成するときに指定するテクスチャは1枚の画像である必要がなく、アトラスの１部分でも良いからです。AssetManagerの内部処理ではフォント設定に対応したテクスチャ名でテクスチャを取得しているだけなので、このような事ができます。もちろんAssetManagerを使わず手動でBitmapフォントを作成する場合でも同じです。
その場合はフォント画像の合成は動的に行ってもいいかもしれませんね。(コンテキストロスト時の処理が難しくなりますが。。)

#ドローコールの数が減るか

動かしてStatsの表示を確認してみましょう。。
<img width="384" alt="cap2.png" src="https://qiita-image-store.s3.amazonaws.com/0/8302/196744c9-2cf2-9d04-f95d-e5cf24b46d21.png">
ドローコールの数が減って。。ない（笑）ですね。これは、どういう事かというとテキストフィールドの内部では1ドローコールを消費する代わりに、処理をまとめて効率化するバッチ処理が行われているからです。ざっとしか確認していないので間違っているかもしれませんが、テキストが更新された場合などの処理が効率良く書かれているように見えます。ドローコールが増えてもそのほうが速いという判断がなされているのではないでしょうか。

では、テキストのドローコールを減らすことはできないのでしょうか？結論をいうと、できました！

<img width="327" alt="cap3.png" src="https://qiita-image-store.s3.amazonaws.com/0/8302/8ff81048-8037-fba7-7f2e-449c1abf77d6.png">
見事にドローコールが１です。何をしたのかというと、TextFieldクラスにはテキストを描画したSpriteを作ってくれる機能が存在するので、それを使いました。TextFiledをnewせず、以下のようにやります。

```sample3.as
//TextField.getBitmapFont('フォント名').createSprite(横幅, 縦幅, '表示文字', フォーマット [,オプション]);
var sprite:Sprite = TextField.getBitmapFont('nums1').createSprite(200, 32, '00001111', new TextFormat('nums1', 32, 0xffffff));
```
このような感じです。Spriteの中身はただのイメージがたくさん置いてあるだけなので、更新のない静的なテキストであれば、これで問題ないでしょう。更新が多いテキストの場合、頻度にもよるでしょうが、素直にTextFieldを使ったほうが速いのではないでしょうか。Scoutなどでパフォーマンスを確認してジャッジしましょう。

#さらなる考察
上記では文字ImageのつまったSpriteを生成しましたが、１文字のイメージ単体で生成したり、文字のテクスチャ自体を取り出すこともできます。

```sample4.as
var char:BitmapChar = TextField.getBitmapFont(fontName).getChar(48); // 48 = '0'を取得
var image:Image = char.createImage(); // 直接イメージを作る
var texture:Texture = char.texture; // テクスチャだけ取り出す
```
テキストのアニメーション（ Flashぽい！ ）を行う場合はこれを使うのが良いですね。また、スコアやタイム表示であれば、自分が以前に(starling1.x用ですが)作成した gotoAndPlayが使えるMovieClip( http://qiita.com/harayoki/items/2bf5e1bb8e6296a68858 )に各数字のイメージを突っ込んでおけば、mc.gotoAndFrame('1');などのように使えて便利かもしれません。一桁ごとにMovieClipを用意する感じです。ドローコール１が実現できて、スピードも落ちないはず。

#おわりに
文字１つ１つでなく、フォントとしてまとめられた画像を入れ子にしてパックするので、余白を少なくするという点では無駄がありそうですが、TexturePackerであればある程度の余白はトリムしてくれるので、まあなんとかなるかもしれません。ところで、最近のTexturePackerはアルファ付き256色パレットpng(pngquant)も書き出してくれるんですね。すばらしい。