ビットマップフォントで遊ぶ:フォントに絵文字を入れ込む


Bitmap Fontの初期化はAssetManagerに任せたままだったり、コンストラクタにXMLが必要で不便だったり、そんな理由で、プログラムで構築する事はあまりされていないかと思いますが、面倒くさいながらも自由にいじる事ができるので、いろいろおもしろい事ができます。そのあたりをいくつか紹介します。


1のフォントを王冠画像に動的に置き換えてみた例

絵文字を挿入する

ビットマップフォントの1文字はBitmaCharクラスで表されます。普通にテクスチャ(=サブテクスチャ=テクスチャアトラスの1パーツ)を指定して既存フォントに登録する事やすでにあるフォントを上書きする事が可能です。

sample.as
var char:BitmapChar = new BitmapChar(id, texture, xOffset, yOffset, xAdvance); 
someFont.addChar(id, char);

サンプルコードをみてみましょう。ここで、idは文字コード番号、xOffsetとyOffsetはテクスチャが余白をトリミングしたものである場合に指定するもの、xAdvanceは次の文字を表示する位置です。textureは普通にテクスチャです。なお、BitmapCharにはカーニングの指定もできますが、ここでは考えません。

以下は、固定幅フォントを指定する場合で、テクスチャに余白がない場合はコードがとても簡単になります。

sample.as
var char:BitmapChar = new BitmapChar(65, texture, 0, 0, 16); // "A"の文字(コード番号65)の場所に横16ドット固定幅の画像を登録
someFont.addChar(char.charID, bitmapChar);

このようにすると、記事の最初の画像のように、1文字を絵文字で後から置き換えるような事が可能です。フォント画像は単色である必要はありません。他の文字と横幅をそろえる必要もありません。縦の位置がずれてしまう場合は、yOffsetの値で調整してください。

最初から絵文字を含んだフォントを用意するのと何が違うのかというと、フォントを書き出しなおす手間がいらないという事と、配布済みフォントもカスタム化ができる、という所です。配布済みのビットマップフォントはそもそも再書き出しが難しかったりしますし。

文字化け注意

ただし、Fontに指定してあるテクスチャとBitmapCharで直接登録した文字のテクスチャが別ソース画像である場合、TextFieldでのフォント利用で文字化けしたような状態になってしまいますTextField内のバッチ処理でテクスチャソース画像が2つ以上混在している事が考慮されていないのでしょう。font.createSprite()して文字を表示する場合は文字化けしません。


これは、英字フォントに別のかなフォントテクスチャから"あ"の画像を上記の方法で移植した場合で、上がTextField表示、下がfont.createSprite表示です。

テクスチャ画像をまとめる

文字化けをcreateSpriteで回避したとしても、文字の途中でテクスチャが切り替えがあると、その度にドローコールが増えてしまいます。なので差し込む絵文字画像とフォント画像を合成してしまうと良いです。これは、フォント画像の再書き出しをするという事ではありません。文字をパック済みのフォント画像を、別のテクスチャアトラスの一部として取り込んでしまいます。詳しくは、自分の過去記事を参照してください。
ビットマップフォント画像を他とまとめて1ドローコールを目指す


このように、ドローコールの増加が防げます。

デモ

自分の作ったUtilクラスを通しているので、上記とはコードが異なりますが、実際に同じ事を行っている動作するコードが下記にあります。ご参考まで。(別投稿のデモも含みます。)
https://github.com/harayoki/-qiita1/blob/replaceBitmapCharByTexture/src/StarlingMain.as

bassui.as
var emoji:BitmapChar = // "1"の文字に[王冠画像]を上書き登録
    BitmapFontUtil.createBitmapCharByTexture(
        "1", _assetManager.getTexture("oukan"),0, 0, 16 + 2);
BitmapFontUtil.addBitmapCharToFont(eijiFont, emoji);
_doHelper.locateDobj(
    _doHelper.createSpriteText(
        "STAGE 1-A", eijiFont.name, 300, 50, 16, 0xffffff),
    50, 20);

<続くクエー