概要
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
の最後の位置を取得する方法についてご紹介しました。
是非、ご自身の制作活動に活用してみてください。