【Unity】カスタムフォントとTextでUI上にタイルマップを作る裏技

【Unity】カスタムフォントとTextでUI上にタイルマップを作る裏技

メニューバーの解説記事を書いていて、Custom Fontについて解説をしているときにひとつ面白いことを思いつきました。

それは、Custom Fontを使ってUIでタイルマップを作れること。

実用性などの難しいことは抜きにして、とにかく挑戦してみようぜ! という小ネタです。

 

環境

macOS 10.14 Mojave

Unity2018.3.14f1

Unity Hub 1.6.2

素材の準備

今回使う素材はぴぽやさんが公開されているマップチップで、フィールドマップ1です。ありがたく使わせていただきます。

 

ダウンロードしたらUnityのプロジェクトにインポートします。

マップチップがインポートされたのだポッター
マップチップがインポートされたのだポッター

 

このとき、インポート設定は[Sprite (2D and UI)]にしておきます。

フォントマテリアルの作成

続いてフォントで使うマテリアルを作成します。

[Assets] -> [Create] -> [Material]から作成し、シェーダーにUnlit/Transparentを指定します。テクスチャは表示したいものを選択。ここでは海の画像をセットしました。

マテリアルの作成
マテリアルの作成

 

Transparentを指定することで、マップチップに含まれているアルファが使えます。

こんな感じで、使うパーツごとにマテリアルを作成します。

カスタムフォントの作成

次はカスタムフォントを作成します。[Assets] -> [Create] -> [Custom Font]からファイルを作成しましょ。

カスタムフォントを作成
カスタムフォントを作成

 

カスタムフォントの設定を入れていきます。

設定がいっぱい
設定がいっぱい

 

Line Spacingはタイルマップの大きさである40を入れました。

Default Materialに先ほど作成したマテリアルを設定します。

Ascii Start Offsetは文字コードのインデックスでオフセットを使うかどうかの設定です。今回はインデックス番号0でA(10進法で65)となるようにしたいので、ここに65を入力しました。

その他4つはデフォルトのままにしてあります。詳細を知りたい場合はマニュアルをご覧あれ。

 

次に文字のマッピングをしていきます。

マッピングしていく
マッピングしていく

 

インデックスを0とし、[A]を入力した時の画像を設定します。今回設定の対象としている画像は40 * 200の縦長画像。以下のように下から設定していきます。

イメージ図
イメージ図

 

Uvでは、まずW(横幅)とH(縦の長さ)を決めています。これは絶対値で指定されるのではなく、割合となっています。今回使っているのは横幅が40、縦の長さが200の画像で、1マスは40 * 40です。

与えられた画像のうち、ここで指定している画像が占める横の割合は1なので、Wには1を入力します。

同様に、与えられた画像のうち、40 * 40の画像が占める縦の割合は0.2なので、Hには0.2を入力します。

XとYは、この分け方で画像を分割したときに、座標はどこなのかを割合で表します。Aの画像は(0, 0)、Bの画像は+Y方向に増えるので(0, 0.2)となります。左下が原点になっています。

VertはUvと違って画像1枚あたりの大きさを指定します。気をつけるべき点は、VertのHはマイナスで指定する必要があることです。紛らわしいね。

Advanceは文字と文字の水平方向の距離です。画像の大きさに合わせたいので40を指定します。

 

次に[B]を入力した時の設定を同様に入力します。

どこが変わったか分かるかな?
どこが変わったか分かるかな?

 

変えるのはIndexとUvのYですね。Vertは変えなくて大丈夫です。

マップチップが5枚なのでEまで設定しちゃいましょう。

Textコンポーネントで表示

いよいよ画面に表示します。

Textコンポーネントを持ったUIを作成し、テキストエリアにAからEまでの文字を入力します。Fontには今回作成したCustomFontを指定します。

マップの大きさはRectTransformでWidthとHeightを使って指定するといい感じです。今回はひとマス40 * 40の大きさなので40の倍数にしてあればOK。

Textコンポーネントで値を入力
Textコンポーネントで値を入力

 

Gameビューで見るとこのようになります。Textコンポーネントなのにタイルマップができた!

タイルマップが表示された
タイルマップが表示された

 

フィールドっぽくする

海のチップセットを使ってフィールドっぽくしたのがこちら。Textオブジェクトを分けることでレイヤー分けのようにできちゃいます。

海のレイヤー
海のレイヤー

 

Textコンポーネントのテキストエリアにはこのような文字列が入っています。Unityのテキストエリアでは入力が辛いのでテキストエディタ(VS Codeなど)を使って入力します。

 

海のレイヤーの上に地面レイヤーを追加。ちょっと浮き出ていた模様は川だったんですねぇ。

地面のレイヤー
地面のレイヤー

 

さらにこの上に森レイヤーを追加します。

森のレイヤー
森のレイヤー

 

せっかくなので橋も架けましょう。

橋や山のレイヤー
橋や山のレイヤー

 

お城も作っちゃいました。こうやって見るとフィールドっぽい?

城や建物のレイヤー
城や建物のレイヤー

 

Textオブジェクトだけでフィールドマップが作れちゃう時代なんですねぇ……(しみじみ)

画像の中の[F]は透過マスと対応しています。

テキストオブジェクトのレイヤー
テキストオブジェクトのレイヤー

 

メリット

やってみた結果、いくつかメリットもありました。いえ、決して無理やりひねり出した訳ではないですよ。

一度マッピングデータを作れば使いまわせる

カスタムフォントの設定で文字と画像のマッピングを行っておけば、同じサイズの画像を使う場合にフォントの設定を使いまわせます。

上で使った画像の使い回しですが、例えばこの海のマップチップ5マスでカスタムフォントを作成したとします。

同じ大きさの画像(例えば森など)を使ってマテリアルを作り、海のカスタムフォントを複製してからDefault Materialを差し替えれば、1からマッピングする必要は無くなります。

イメージ図
イメージ図

テキストでマップが保存できる

マップの情報はTextコンポーネントのテキストエリアに文字列で格納されます。

これを設定書などにコピペすれば、すぐに設定を残しておくことができます。バックアップ面でも安心。

テキストだから修正が容易であることも忘れてはいけません。一箇所修正するときにも、一文字だけ変えればいいのです。

……冷静に考えたら昔はCSVでマップデータを持ってたんだから、それと同じことしているだけかも……?

Canvasの拡張に対応している

UIでタイルマップを表示しているので、Canvasの拡張にも対応しています。

Canvas Scalerで[Scale With Screen Size]を選択しておけば、画面サイズが変わったとしても、それに合わせてマップを拡大、縮小してくれます。

Tilemapの方は2Dのゲームオブジェクトと同じ扱いなので、カメラに映る範囲が変わるんですよね。なので複数のデバイスがリリース対象になっているときにはこれも考慮に入れないといけないんです。

デメリット

列挙するにはデメリットが多すぎる気がしますが、やはりいくつか挙げておかねばなりません。

マッピングめんどくせええええええええ!

カスタムフォントを使うには、文字と画像のマッピングを行わなければなりません。

[A]は地面、[B]は木、[C]は町、[D]は……みたいな感じで設定を入れないといけないのが辛いんですよねぇ。一括でマッピングしてくれる機能があればいいんですけど、デフォルトではありません。

あとUVでXYを指定するのも地味に面倒です。マスの数によってはWHが割り切れない数になることもあるので、計算を頑張るか画像のマスの数を変更するか、などの対応が必要です。

 

あ、文字と画像のマッピングを行うEditor拡張を作れば楽かもしれません。今気づきました。

Unityのテキストエリアでは編集しにくい

マップを作成する上で、エディタが使いづらいというのは致命的。

Unityのテキストエリアは等幅ではなくプロポーショナル。つまり文字の幅が一定ではないので、今の行に何マス書いたか判別しにくいんです。

これは外部のテキストエディタを使えば解決できるんですけど、画面をいったりきたりするのは結構作業効率に影響が出ます。

透過マスを作る必要がある

作っている途中で気づいたのですが、ひとつのテクスチャ内に1マスは透過マスを作る必要があります。

というのも、複数のレイヤーを重ねて使いたいのですが、1つのカスタムフォントの中に透過マスがないと、下のレイヤーの画像の上に描画しちゃうんです。1カスタムフォント = 1マテリアル = 1テクスチャなので、下のレイヤーに被せたくないときには透過マスが必要です。

カスタムフォントに含まれていない文字を入力した場合にはスペースが表示されそうなものですが、その文字は無かったことにされます。これすらも画像とのマッピングが必要なんですね。

なので公開されているマップチップを使う場合は、自分で透過マスを追加しないといけない場合もあります。

Canvasの再描画が頻繁に起こる

マップとして使う場合、画面内で位置を動かす必要があるかもしれません。そうなるとCanvasの再描画が頻繁に起こります。

UnityではCanvasの要素に何かしらの変更があった場合はそのCanvasが再描画されます。これには画像の移動も含まれるんです。

対策としては、Textを使って描画したマップは別のCanvasにしておく、とかでしょうか。普段のUIでも気を付けておきたい部分です。

TileMapEditorがある

それを言っちゃあおしまいよ。

結論

TileMap Editor、使おう。

実用性が無い点に目を瞑れば、話の種にはなるかもしれません。実用化してみたい変態紳士がいたら、ぜひ挑戦してみてください。

フォント=文字みたいな固定観念がありましたが、実態は画像(あるいはベクターデータ)との関連付けがされたファイルなんですよね。今回のケースで改めて実感しました。

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!