LoginSignup
33
26

More than 5 years have passed since last update.

[Unity] UI.Text (uGUI) で縦書き(のようなもの)を作る

Last updated at Posted at 2016-10-30

前置き

  • ゆるっと対応する
  • ほんとにゆるやかに対応する (念押し)
  • 小説等の対応を行う為のガチなアプローチはここでは行わない

image

縦書き対応で満たされて欲しい案件

  • (1) レイアウト
    • (1-1) テキストボックス入力時に縦に文が伸びる
    • (1-2) 改行語、既存の文の左に文が追加出来る
  • (2) 文字

フォントの縦書き設定

Unity (UI.Text) と縦書き設定

  • Unity (UI.Textコンポーネント) では現在 (5.4.1f) 時点でフォントの縦書き設定は読み込めない

対応

RectTransformを回転させる

rotate_text.gif

  • 文字を入力した際に縦に文章が伸びる用にRectTransformのZを90°回転させる
  • これによりレイアウトの条件を満たす

テキストの頂点を90°回転させる

image

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

public class RotateText : UIBehaviour, IMeshModifier
{
    public new void OnValidate()
    {
        base.OnValidate();

        var graphics = base.GetComponent<Graphic>();
        if (graphics != null)
        {
            graphics.SetVerticesDirty();
        }
    }

    public void ModifyMesh (Mesh mesh) {}
    public void ModifyMesh (VertexHelper verts)
    {
        if (!this.IsActive())
        {
            return;
        }

        List<UIVertex> vertexList = new List<UIVertex>();
        verts.GetUIVertexStream(vertexList);

        ModifyVertices(vertexList);

        verts.Clear();
        verts.AddUIVertexTriangleStream(vertexList);
    }

    void ModifyVertices(List<UIVertex> vertexList)
    {
        // memo: 1テキスト6頂点
        for (int i = 0, vertexListCount = vertexList.Count; i < vertexListCount; i += 6)
        {
            var center = Vector2.Lerp(vertexList[i].position, vertexList[i + 3].position, 0.5f);
            for (int r = 0; r < 6; r++)
            {
                var element = vertexList[i + r];
                var pos = element.position - (Vector3)center;
                var newPos = new Vector2(
                    pos.x * Mathf.Cos(90 * Mathf.Deg2Rad) - pos.y * Mathf.Sin(90 * Mathf.Deg2Rad),
                    pos.x * Mathf.Sin(90 * Mathf.Deg2Rad) + pos.y * Mathf.Cos(90 * Mathf.Deg2Rad)
                );

                element.position = (Vector3)(newPos + center);
                vertexList[i + r] = element;
            }
        }
    }
}

一部文字は回転させない

image

  • 上記のままだと一部文字 (e.g: ー ) が正常に見えない
  • 一部の文字に対して、回転を施さないような処理を加える
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using System.Linq;

[RequireComponent(typeof(Text))]
public class RotateText : UIBehaviour, IMeshModifier
{
    private Text textComponent;
    private char[] characters;

    // 回転させない文字群
    // XXX 別の設定ファイルなりcsvにまとめて最初に読み込んでしまうのが良さそう
    public List<char> nonrotatableCharacters;

    public new void OnValidate()
    {
        base.OnValidate();
        textComponent = this.GetComponent<Text>();

        var graphics = base.GetComponent<Graphic>();
        if (graphics != null)
        {
            graphics.SetVerticesDirty();
        }
    }

    public void ModifyMesh (Mesh mesh) {}
    public void ModifyMesh (VertexHelper verts)
    {
        if (!this.IsActive())
        {
            return;
        }

        List<UIVertex> vertexList = new List<UIVertex>();
        verts.GetUIVertexStream(vertexList);

        ModifyVertices(vertexList);

        verts.Clear();
        verts.AddUIVertexTriangleStream(vertexList);
    }

    void ModifyVertices(List<UIVertex> vertexList)
    {
        characters = textComponent.text.ToCharArray();
        if (characters.Length == 0)
        {
            return;
        }

        for (int i = 0, vertexListCount = vertexList.Count; i < vertexListCount; i += 6)
        {
            int index = i / 6;
            if (IsNonrotatableCharactor(characters[index]))
            {
                continue;
            }

            var center = Vector2.Lerp(vertexList[i].position, vertexList[i + 3].position, 0.5f);
            for (int r = 0; r < 6; r++)
            {
                var element = vertexList[i + r];
                var pos = element.position - (Vector3)center;
                var newPos = new Vector2(
                    pos.x * Mathf.Cos(90 * Mathf.Deg2Rad) - pos.y * Mathf.Sin(90 * Mathf.Deg2Rad),
                    pos.x * Mathf.Sin(90 * Mathf.Deg2Rad) + pos.y * Mathf.Cos(90 * Mathf.Deg2Rad)
                );

                element.position = (Vector3)(newPos + center);
                vertexList[i + r] = element;
            }
        }
    }

    bool IsNonrotatableCharactor(char character)
    {
        return nonrotatableCharacters.Any(x => x == character);
    }
}

TODO 一部文字位置の調整

image

  • 上記のコードのままだと「。」「っ」等の文字の位置が適切でない
  • 字を半文字分横にズラす対応を入れると良さそう
    • 良き時に追記する(遠い目)

TODO その他頂点が増える場合の対応

  • 上記コードのままだと、UIComponentのShadowやOutline等、頂点の数が追加される場合に正常に動かないので注意
    • 具体的には vertexList.Count (頂点数) が文字列数*6より多くなってしまうため

パフォーマンス対策

最後に

  • 諸々細かい調整入れるの大変なのでUnity側で縦書き対応していただきたいところ....!!

ユニティちゃんライセンス

この作品はユニティちゃんライセンス条項の元に提供されています

33
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
26