【Unity】TextMeshProで「数字」をテキストで表現する時にGC Allocを発生させない2つの方法
今回はTextMeshProを使用する際に、UIに文章を表示する際のGCを抑えるアプローチについてです。
数字を表示する際にGCが発生するのを回避したい
「数字をUIに表示する」アプローチはよくある動作です。例えばスコアであったり、ダメージであったり、HPであったり、残金であったり。
一時は文字に頼らないUI表現が流行しましたが、現状は多くのケースで数値が採用されています。
この数字を表示するアプローチ、場合によってはGCが発生します。正確には数字をStringに変換(int.ToString()
)のタイミングでGCが発生します。これを回避するための色々なアプローチはあるのですが、TextMeshProを使用するとかなり簡単に回避出来たので、それを紹介します。
SetCharArray(...)を使用する
ある意味、昔ながらのアプローチに近いのがTextMeshProUGUI.SetCharArray(...)
を使用するアプローチです。
SetCharArray(...)
は、stringではなくchar [ ](キャラクターの配列)やint [ ](文字コードの配列)を使用して文字を表現するAPIです。例えば下のような動作になります。
// 例1、結果:TEST1 int[] characters1 = new int[]{84, 69, 83, 84, 49}; label.SetCharArray(characters1, 0, characters1.Length); // 例2、結果:Test2 char[] characters2 = new char[]{'T', 'E', 'S', 'T', '2'}; label.SetCharArray(characters2, 0, characters2.Length);
後の話は簡単で、SetCharArray(...)
の引数となるintやcharの配列の中身を数字と書き換えてやれば、int.ToString()
を使用せずとも数値を表現出来るという寸法です。
なおSetCharArray(int[], start, length)
のAPIが要求するintの配列の中身はUnicodeです。これは普通にUnicode表を見れば乗っていますが、同様にTextMeshProのFontAsset>CharacterTable
からも確認出来ます。表示は16進数ですが、要求する数字は10進数なので、そこは注意が必要ですが…
ヒント:Unicodeの0~9は、数字の48~57が該当します。なので、(数字+48)で数値を表現出来ます。
SetText(...)を使用する
もう一つのアプローチが、SetText(...)
を使用するアプローチです。こちらはString.Format(...)
のような使い勝手で使用できるので、SetCharArray(...)
と比較して圧倒的に楽に使用できます。
例えば数値を表示したい場合、下のようなコードで表示します。
// 例3 int value = 12345; label.SetText("value : {0}", value);
なお、コチラの場合は小数点やマイナスの表現のために一工夫する必要もありません。
// 例4 float value = -123.41234f; label.SetText("value : {0:2}", value); // 小数点2桁まで表示
エディターではGCが発生する点に注意
この機能で少し厄介なのは、エディター上で動作させている場合と、実際にビルドした場合で動作が異なるという点です。具体的には、エディターで動作させるとGCが発生します。
追ってみた所、どうもSetCharArray(int[], int, int)
でint[](Unicode)を使用している場合、エディターのTextMeshProのInputBoxに文字を表示するため、IntToString
が呼ばれるみたいです。また他のケースでも何処かでGCが発生しています。
SetCharArray(...)のサンプル
数字を文字コードの配列に直す場合、桁数固定の0埋めなら下のような感じです。
一方、0埋めでない時の動作はこんな感じです。桁数を求めてintを埋めてる感じです。
charを使用する場合は、こんな感じで使えます。結果は0埋めと同じ動作です。
SetText(...)のサンプル
#感想
派手に装飾した数字を出す時でも、色々と考えなくて良いのは楽で良いです。
関連
charを使用した場合
マイナスに対応したchar[]ベースのアプローチ