うにty生活

UnityChanを生活させたい

【Unity】textInfoの内容が取得できない時の対処法

今回はTextMeshProやTextMeshProUGUIで扱えるプロパティ、textInfoを使っていて困ったことと対処方法を書いていきます。

※TextMeshPro自体の使い方や説明は省きます。

 

 

環境

Windows 11

Unity 2021.3.16f1

URP 12.1.8

 

TMP_TextInfoとは

TMP_TextInfoとは、TextMeshProやTextMeshProGUIが継承しているTMP_Textクラスに存在するクラスの一つです。

このTextInfoクラスには文字数だったり、テキストメッシュの座標情報が格納されていて結構使い勝手が良いです。

 

ここからは使っていて困ったことと解決策を書いていきます。

 

ちなみにTextMeshのメッシュが板ポリだったってことに気が付くのは結構最近のお話笑

 

characterInfoやmeshInfoの中身が上手く取得できない

困ったことの1つ目です。Debug.LogでcharacterInfoを出力してみても文字が入ってなかったりクラス自体がNullだったりします。

 

準備としてTextMeshProUGUIを用意しました。

TextMeshProUGUIを用意したScene画像

 

NGコード×

public class TextInfoBlog : MonoBehaviour
{
    public TextMeshProUGUI uiText;// TextMeshをアタッチ済み
    
    // Start is called before the first frame update
    void Start()
    {
        TMP_TextInfo textInfo = uiText.textInfo;
        Debug.Log(textInfo.characterInfo[0].character); //出力:空
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

原因は呼び出しタイミングが早すぎることです。

 

対処法

AwakeやStartからの呼び出しで使わないこと

 

OKコード〇

public class TextInfoBlog : MonoBehaviour
{
    public TextMeshProUGUI uiText;// TextMeshをアタッチ済み
    
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyUp(KeyCode.G))
        {
            TMP_TextInfo textInfo = uiText.textInfo;
            Debug.Log(textInfo.characterInfo[0].character); //出力:N
        }   
    }
}

 

AwakeとStartから呼び出すとInspectorで文字が入っていたとしてもcharacterInfoやmeshInfoが正しく呼ばれることはありません。

必ず、Startよりあとのタイミングで呼び出すようにしましょう

 

新しく設定したtextのtextInfoが取得できない

2つ目の困ったことは新しくtextを設定したとき、最新のtextInfoを取得してこないという問題があります。

 

NGコード×

※他は同じなのでUpdateのみ記述

void Update()
{
    if (Input.GetKeyUp(KeyCode.G))
    {
        uiText.text = "Textinfo test";
        TMP_TextInfo textInfo = uiText.textInfo;
        Debug.Log(textInfo.characterInfo[0].character); //出力:N
    }   
}

「T」という文字が取得したいのにデフォルトの「New Text」の「N」が出力されます。

 

対処法

GetTextInfo(newText)関数を使う

 

OKコード〇

void Update()
{
    if (Input.GetKeyUp(KeyCode.G))
    {
        TMP_TextInfo textInfo = uiText.GetTextInfo("Textinfo test");
        Debug.Log(textInfo.characterInfo[0].character);
    }   
}

TMP_TextInfo textInfo = uiText.GetTextInfo(newText)とやると内部的にtextも「newText」にセットできるし、「newText」のtextInfoも取得できる。(Get関数なのに内部でtextをSetしているのは少しわかりにくいですが関数の中身を見たら気が付けます...)

 

他にも見つけた便利なプロパティ

1文字の中央座標を取得する

よく紹介されている手法として、textInfo.meshInfoから全てのvertex(頂点)情報を取得後4を掛けてn文字の中央座標を求めることができます。

以下のコードでは「New Text」の3文字目、「w」の中心座標を求めて上からspriteをかぶせています

 

コード

public class TextInfoBlog : MonoBehaviour
{
    public TextMeshProUGUI uiText;// TextMeshをアタッチ済み
    public Image imagePrefab;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyUp(KeyCode.G))
        {
            TMP_TextInfo textInfo = uiText.textInfo;
//※ここで取得した座標はuiTextのローカル座標なので注意            
var mesh = textInfo.meshInfo[0]; var vertices = mesh.vertices; //3文字目のメッシュを取得 var charMechStart = 2 * 4; var topleft = vertices[charMechStart]; var bottomRight = vertices[charMechStart + 2]; var center = (topleft + bottomRight) / 2; var image = Instantiate(imagePrefab, uiText.transform, false); image.transform.localPosition = center; } } }

参考:uGUI Textの文字の座標を取得してインライン画像を実現する - おもちゃラボ

 

上記コードはNGというわけではありませんがもっと簡単な方法があったので紹介します。

 

characterInfoのtopleftやbottomrightといった座標プロパティが存在するのでそこから計算すればok。

 

改善コード(Updateだけ)

やってることは同じです。

void Update()
    {
        if (Input.GetKeyUp(KeyCode.G))
        {
            TMP_TextInfo textInfo = uiText.textInfo;
            var topleft = textInfo.characterInfo[2].topLeft;
            var bottomRight = textInfo.characterInfo[2].bottomRight;
            var center = (topleft + bottomRight) / 2;
            var image = Instantiate(imagePrefab, uiText.transform, false);
            image.transform.localPosition = center;
        }   
    }

 

正しい文字数を表示する

textInfo.characterCountのカウントは残念ながら思った通りには返ってきません。

例えばhoge hoge¥nfuga fugaというtextが存在すると、このテキストの正確な文字数は16文字です。空白も改行も数えてしまいます。

TMP_TextInfo textInfo = uiText.GetTextInfo("hoge hoge\nfuga fuga");
Debug.Log(textInfo.characterCount); //19

 

なのでこういう時はスペース数を取得して引いたものが正しい文字数です。

TMP_TextInfo textInfo = uiText.GetTextInfo("hoge hoge\nfuga fuga");
Debug.Log(textInfo.characterCount - textInfo.spaceCount); //16

なぜ改行もスペースとして数えられるのかはわかりませんがこれで正しい文字数は出せました。これをループに使えば各文字に何らかの処理を行えます!

 

いかがだったでしょうか、textInfo便利なのでぜひ使ってみてください。