おもちゃラボ

Unityで遊びを作ってます

uGUI Textの文字の座標を取得してインライン画像を実現する

uGUI Textの文中に画像を配置したい場合、特定の文字の座標を取得する必要があります。この記事ではuGUI Textから特定文字の座標を取得し、そこに画像を配置することでインライン画像を実現する方法を紹介します。

f:id:nn_hokuson:20211029101035p:plain:w450

uGUI Textの特定文字の座標を取得

uGUIのTextから特定文字の座標を取得するにはcachedTextGeneratorを使います。cachedTextGeneratorを使うと、それぞれの文字を囲むボックスの4頂点の座標を取得することができます。

f:id:nn_hokuson:20211029092948p:plain:w500

各文字の4頂点の座標は左上から時計回りにListに格納されています。今回は文字の中心の座標がほしいので左上の座標と右下の座標の中間値を計算します。

f:id:nn_hokuson:20211029093403p:plain:w340

それでは実際にプログラムを作ってみましょう。インライン画像を実現する流れは次のとおりです

  1. Textから特定の文字を検索する
  2. その文字の座標を計算する
  3. 計算した座標に画像を移動する

Textから特定の文字を検索する

今回は「おもちゃ・ラボ」の「・」に「♥」の画像を配置してみます。そこで文字列中から「・」を検索します。文字列から特定の文字を検索するにはIndexOfメソッドを使います。

Text message = GetComponent<Text>();
int n = message.text.IndexOf("・");

IndexOfメソッドは引数に指定した文字のインデックスを返します。C#の文法についてはコチラも合わせて参考にしてくださいね。

n番目の文字の中央座標を計算する

上で紹介したcachedTextGeneratorを使ってn番目の文字の座標を計算します。

IList<UIVertex> vertexs = message.cachedTextGenerator.verts;
float unitsPerPixel = 1 / message.pixelsPerUnit;

int idx = n * 4;
UIVertex topLeft = vertexs[idx];
UIVertex bottomRight = vertexs[idx + 2];

topLeft.position /= message.pixelsPerUnit;
bottomRight.position /= message.pixelsPerUnit;

Vector3 center = (topLeft.position + bottomRight.position) / 2f;

cachedTextGeneratoで文字の頂点配列を取得し、n番目の文字の左上座標と右下座標を取り出します。今回の場合「・」は5文字目なのでn=4となり、16番目と18番目の座標を取り出しています。

f:id:nn_hokuson:20211029100545p:plain:w500

最後に、topLeftとbottomRightの2頂点の中間値を計算することで、文字の中央の座標を取得します。
f:id:nn_hokuson:20211029100715p:plain:w250

計算した座標に画像を移動する

最後に計算したcenter座標に画像を移動します。

this.img.GetComponent<RectTransform>().anchoredPosition = center;

得られたcenter座標はanchoredPositionで計算されています。したがって、これを画像のanchoredPositionに設定しています。

まとめ

上のプログラムをまとめると次のようになります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InlineImage : MonoBehaviour
{
    [SerializeField] GameObject img;

    void Start()
    {
        Text message = GetComponent<Text>();
        int n = message.text.IndexOf("・");

        IList<UIVertex> vertexs = message.cachedTextGenerator.verts;
        float unitsPerPixel = 1 / message.pixelsPerUnit;

        int idx = n * 4;
        UIVertex topLeft = vertexs[idx];
        UIVertex bottomRight = vertexs[idx + 2];
        
        topLeft.position /= message.pixelsPerUnit;
        bottomRight.position /= message.pixelsPerUnit;

        Vector3 centerPosition = (topLeft.position + bottomRight.position) / 2f;
        this.img.GetComponent<RectTransform>().anchoredPosition = centerPosition;
    }
}

作成したInlineImageスクリプトをuGUI Textのオブジェクトにアタッチしてください。次に、インスペクタからimgに表示したい画像をドラッグ&ドロップしてください。

f:id:nn_hokuson:20211029101832p:plain

これで実行すれば、指定した文字の座標に画像が移動して、インライン画像が実現できます。

nn-hokuson.hatenablog.com