概要
UnityのTextMeshProUGUIコンポーネントでTextを表示する際に、最後の文字の位置を取得したいと思ったことはありませんか?(ノベルゲームの末尾に点滅するアイコンを表示したいなど…)
今回紹介する手法を用いることで、末尾に任意のRectTransformを追従させることが出来るようになります。
※今回は 左上詰め のテキストに追従させていますが、
AnchorやPivot位置、スクリプトを調整することで任意方向に詰めたテキストにも応用できると思います。
動作環境
Unity 2021.3.6f1
TextMeshPro 3.0.6
セットアップ
Back
背景用のGameObjectです。
Imageと共に、今回作成したスクリプトをアタッチしています。
Text(TMP)
テキストを表示するGameObjectです。
RectTransformの設定は、末尾に表示する画像等を考慮して右側を少し広めに取っています。
TextMeshProUGUIは 左揃え かつ 上揃え に設定しています。
Marker
末尾に追従させるGameObjectです。
RectTransformは 左上を基準 に設定し、位置の微調整は Pivot で行います。
また、今回はアニメーションも指定しています。
惜しい実装例
よく紹介されている手法として、PreferredWidth、PreferredHeightを利用する手法があります。
[SerializeField] private TextMeshProUGUI _text;
[SerializeField] private RectTranform _marker;
private void Update(){
var x = _text.preferredWidth;
var y = _text.preferredHeight;
_marker.anchoredPosition = new Vector2(x,-y);
}
しかしこの方法では、テキストの 最大横幅 と 最大縦幅 を取得しているため、改行が入ると正しく動作しません。
(また、Wrappingの設定がONだと、自動改行時にpreferredWidthだけがドンドン大きくなるなど…)
提案する実装例
[SerializeField] private TextMeshProUGUI _text;
[SerializeField] private RectTranform _marker;
private void Update(){
var texInfo = _text.textInfo;
var x = texInfo.lineCount == 0 ? 0 : texInfo.lineInfo[texInfo.lineCount - 1].length;
var y = _text.preferredHeight;
_marker.anchoredPosition = new Vector2(x, -y);
}
TextMeshProUGUIのtextInfo.lineInfoより、各行の情報を配列で取得できます。
また、textInfo.lineCountより、現在表示中の行数を取得できます。
※Wrappingによる自動改行でも、行数は加算されます。
texInfo.lineInfo[texInfo.lineCount - 1].length より、最終行の横幅 を取得できます。
※任意行の横幅 を取得可能なため、Anchor位置やPivot、スクリプトを修正することで、
任意方向に詰めたテキストに対応できると思います。
//提案した実装
var x = texInfo.lineCount == 0 ? 0 : texInfo.lineInfo[texInfo.lineCount - 1].length;
//間違った実装
var x = texInfo.lineCount == 0 ? 0 : texInfo.lineInfo[^1].length;
「わざわざlineCountを用いなくても、lineInfo配列の最後のデータを取得すればいいのでは?」
と思う方もいるかもしれませんが、lineInfo配列はキャッシュされている情報です。
配列の要素数は現在の表示行数とは不一致で、消えてしまった以前の内容が残り続けます。
必ずlineCountを使用して下さい。
まとめ
TextMeshProUGUIのTextの最後の位置を取得する方法についてご紹介しました。
是非、ご自身の制作活動に活用してみてください。



