Unityの代表的なUIであるTextMeshPro(UGUI)、日本人であれば縦書きしたいシチュエーションがあると思います。ここではTextMeshProUGUIを縦書きにしてみたいと思います。サンプルではUGUIのみ対応しますが、普通のTextMeshProも同じコンポーネントで対応出来ます。
目次
縦書きするだけ
まずは縦書きにしたいだけの人向け。スクリプト持っていって、TextMeshPro(UGUI)のコンポーネントがあるインスペクターに貼り付けると縦書きになります。
出来上がり
TMPと同じインスペクターにコンポーネントを貼り付けると、ゲーム実行時に縦書きに変化します。基準になる部分は一文字目を基準に縦書きに変化します。
スクリプト
こちらのスクリプトはかなり限定的な機能しかありません。
- 毎フレーム更新
- 最初の一文字が大きさの基準
- 1行のみ
using UnityEngine;
using TMPro;
public class TMPTate : MonoBehaviour
{
private TMP_Text textMeshPro;
private void Awake()
{
textMeshPro = gameObject.GetComponent<TMP_Text>();
}
private void Update()
{
textMeshPro.ForceMeshUpdate();
var textInfo = textMeshPro.textInfo;
if (textInfo.characterCount == 0)
{
return;
}
Vector3[] firstDestVertices = textInfo.meshInfo[0].vertices;
float startX = firstDestVertices[0].x;
Vector3 startCenter = (firstDestVertices[0] + firstDestVertices[2]) / 2;
float characterHeight = firstDestVertices[1].y - firstDestVertices[0].y;
for (int index = 0; index < textInfo.characterCount; index++)
{
var charaInfo = textInfo.characterInfo[index];
if (!charaInfo.isVisible)
{
continue;
}
int materialIndex = charaInfo.materialReferenceIndex;
int vertexIndex = charaInfo.vertexIndex;
Vector3[] destVertices = textInfo.meshInfo[materialIndex].vertices;
Vector3 charaCenter = (destVertices[vertexIndex + 0] + destVertices[vertexIndex + 2]) / 2;
float offsetX = charaCenter.x - startCenter.x;
float offsetY = (characterHeight * index);
Vector3 offset = new Vector3(-offsetX, -offsetY, 0);
destVertices[vertexIndex + 0] += offset;
destVertices[vertexIndex + 1] += offset;
destVertices[vertexIndex + 2] += offset;
destVertices[vertexIndex + 3] += offset;
}
for (int i = 0; i < textInfo.meshInfo.Length; i++)
{
textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
textMeshPro.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
}
}
}
TextMeshProの表示を操作する
とりあえずやり方を伝授したあとに、そもそもどういう事やっているのか興味がある方はここも目を通していってください。
表示する1文字ずつループする
TextMeshPro(UGUI)では、textInfoというプロパティのなかに様々な情報が入っています。ここで利用する主な情報としては以下
- 表示されている文字数:characterCount
- 1文字ごとのメッシュの頂点:meshInfo[].vertices
一文字ずつは4つの頂点からなるメッシュで表示されています。この頂点座標を変化させることで縦書きにしています。
頂点情報の順番
一文字に対して4つの頂点座標を持っていますが、これらは必ず規則正しい順序で入っています。どの番号がどの頂点なのかを利用して中心点を出したり、オフセットする方向を決めたりしています。
- 左下が0番
- 時計回り
これらの頂点操作中はよくマジックナンバー的に0とか2とかが入りますが、左下だと0、右上だと2のように扱います。
表示に反映させるまでの流れ
基本的にやってることは頂点を操作して反映する!これだけ!!
- TextMeshPro(UGUI)をリフレッシュ
- ForceMeshUpdateメソッドで、いつもどおりの頂点情報に戻す
- textInfo.meshInfo[].verticesの頂点座標を変更
- 文字数でループ
- 文字に対してメッシュ情報が存在するのでそのパラメータを取得
- 一文字ごとに4つの頂点があるので、それらを操作する
- TextMeshPro(UGUI)に反映させる
- 更新した頂点座標を反映させる
- UpdateGeometryを使って各メッシュごとに反映させる
スライム
縦書きにしたい場合は、2文字目以降の座標をスライドさせる形ですね
コメント