びぼうろくってみんなやってる

みんなやってるからぼくもやる

uGUITextとTMProを一括で扱いたい人

やりたいこと

  • uGUITextとTextMeshProを一括で扱いたい
    • TextComponentとして一つにまとめる

なにができるの

  • uGUITextとTextMeshProをUnityEditor上で好きなときに切り替えられる。

動機

  • エンジニアはスクリプト側でuGUIかTMProか気にしたくない。
  • デザイナーはエディタ側を弄ってもスクリプトに触りたくはないと思ってると思ってると思う。
  • 互いが想定するコンポーネントを一つにしたい。

欲しい機能

  • UnityEditor上でuGUIとTMProを選択できる。
  • ScriptableObjectでフォントの設定を保持できる。
  • Script上ではuGUITextと同じ扱いができる。

必要なもの

  • TextComponent
    • 本体。
  • TextComponentEditor
    • エディタ拡張。
  • TextConfig
    • フォント設定のScriptableObject。

書くこと

  • TextComponent
    • [SerializeField] TextType textType
      • enumで外から選びたい。
    • [SerializeField] TextConfig TextConfig
      • フォント設定をD&Dで入れたい。
      • もちろんスクリプト側でも触れると良い。
    • string text
      • 本文
      • 混乱の元なのでEditor側には出さない

つかいかた

TextComponent

  • 新しくTextComponentをつける場合
    • オブジェクトのInspectorでAddComponentを押してTextComponentを選択。
    • TextComponentのTextTypeプルダウンでUGUIかTextMeshProを選択。
  • 既にuGUITextまたはTMProがオブジェクトにアタッチされている場合。
    • オブジェクトのInspectorでAddComponentを押してTextComponentを選択。
    • TextComponent上で右クリックして、GetValueを選択。
      • スクリプト上でTextComponent側からTextをいじれるようになる。
      • このタイミングでTextComponentのメンバ変数textに本文が入る。
    • UGUIのTextをTMProにしたい場合はTextComponentのTextTypeプルダウンで選択。
      • uGUITextが消えてTMProがアタッチされる。
    • 文章が消えるので、TextComponent上で右クリックしてSetTextを選択する。
      • 元の文章が反映される。

TextConfig

  • TextConfigを作る。
    • projectの、TextConfigを置きたい場所で右クリック-> Create -> UI -> TextConfigを選択。
      • 生成されたTextConfigを選択し、名前をつける。
      • Inspectorで値を設定する。
  • 作ったTextConfigを使いたい。
    • TextComponentのTextConfigの枠に使いたいTextConfigをD&D。
      • ドロップした時点で反映される。
    • あとはuGUIかTMProのText設定を行う。

スクリプト側での使い方。

  • [SerializeField] TextComponent textComponent; とかで宣言して、
    • textComponent.Text = "例文"; とかでstringを投げ込む。

ソースコード

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class TextComponent : MonoBehaviour
{
    public enum TextType
    {
        None = 0,
        UGUI,
        TextMeshPro
    }

    public TextConfig textConfig;

    public TextType textType;
    TextType preTextType;

    RectTransform rectTransform;
    Text uGUIText;
    TextMeshProUGUI textMeshPro;

    string text;

    public string Text
    {
        set
        {
            text = value;
            switch(textType)
            {
                case TextType.None:
                    break;
                case TextType.UGUI:
                    if(uGUIText == null) { uGUIText = GetComponent<Text>(); }
                    uGUIText.text = value;
                    break;
                case TextType.TextMeshPro:
                    if(textMeshPro == null) { textMeshPro = GetComponent<TextMeshProUGUI>(); }
                    textMeshPro.text = value;
                    break;
            }
        }
    }


    [ContextMenu("GetValue")]
    void GetValue()
    {
        if(uGUIText != null || textMeshPro != null) { Debug.Log("Already have TextComponent"); return; }

        uGUIText = GetComponent<Text>();
        textMeshPro = GetComponent<TextMeshProUGUI>();

        if(uGUIText != null)
        {
            text = uGUIText.text;
            textType = TextType.UGUI;
            preTextType = textType;
        }

        if(textMeshPro != null)
        {
            text = textMeshPro.text;
            textType = TextType.TextMeshPro;
            preTextType = textType;
        }
    }

    [ContextMenu("SetText")]
    void SetText()
    {
        switch(textType)
        {
            case TextType.None:
                Debug.LogWarning("先にGetValueしてください");
                break;
            case TextType.UGUI:
                if(uGUIText == null) { Debug.LogWarning("先にGetValueしてください"); return; }
                uGUIText.text = text;
                break;
            case TextType.TextMeshPro:
                if(textMeshPro == null) { Debug.LogWarning("先にGetValueしてください"); return; }
                textMeshPro.text = text;
                break;
        }
    }


    void SetValue()
    {
        if(textType == TextType.None) { return; }
        if(textConfig == null) { return; }

        if(textConfig.IsSetAnchor)
        {
            if(rectTransform == null) { rectTransform = GetComponent<RectTransform>(); }
            rectTransform.anchorMin = new Vector2(textConfig.MinX, textConfig.MinY);
            rectTransform.anchorMax = new Vector2(textConfig.MaxX, textConfig.MaxY);
        }

        switch(textType)
        {
            case TextType.UGUI:

                if(textConfig.IsSetFont) { uGUIText.font = textConfig.UGUIFont; }
                if(textConfig.IsSetSize) { uGUIText.fontSize = textConfig.FontSize; }
                if(textConfig.IsSetColor) { uGUIText.color = textConfig.FontColor; }
                if(textConfig.IsSetAutoSize)
                {
                    uGUIText.resizeTextForBestFit = textConfig.BestFit;
                    uGUIText.resizeTextMinSize = textConfig.UGUIMinSize;
                    uGUIText.resizeTextMaxSize = textConfig.UGUIMaxSize;
                }
                if(textConfig.IsSetAlignment) { uGUIText.alignment = textConfig.UGUIAlignment; }
                break;
            case TextType.TextMeshPro:
                if(textConfig.IsSetFont) { textMeshPro.font = textConfig.TMPFont; }
                if(textConfig.IsSetSize) { textMeshPro.fontSize = textConfig.FontSize; }
                if(textConfig.IsSetColor) { textMeshPro.color = textConfig.FontColor; }
                if(textConfig.IsSetAutoSize)
                {
                    textMeshPro.enableAutoSizing = textConfig.AutoSize;
                    textMeshPro.fontSizeMin = textConfig.TMPMinSize;
                    textMeshPro.fontSizeMax = textConfig.TMPMaxSize;
                }
                if(textConfig.IsSetAlignment) { textMeshPro.alignment = textConfig.TMPAlignment; }
                if(textConfig.IsSetMaterial) { textMeshPro.material = textConfig.TMPMaterial; }
                break;
        }
    }

    public void SetTextType()
    {
        if(textType == preTextType) { SetValue(); return; }

        switch(textType)
        {
            case TextType.None:
                None();
                preTextType = textType;
                break;
            case TextType.UGUI:
                UGUI();
                break;
            case TextType.TextMeshPro:
                TextMeshPro();
                break;
        }
        SetValue();
        preTextType = textType;
    }

    void None()
    {
        if(uGUIText != null)
        {
            text = uGUIText.text;
            DestroyImmediate(uGUIText);
        }

        if(textMeshPro != null)
        {
            text = textMeshPro.text;
            DestroyImmediate(textMeshPro);
        }
    }
    void UGUI()
    {
        None();
        uGUIText = gameObject.AddComponent<Text>();
    }
    void TextMeshPro()
    {
        None();
        textMeshPro = gameObject.AddComponent<TextMeshProUGUI>();
    }
}
  • EditorScript
using UnityEditor;

[CustomEditor(typeof(TextComponent), true)]
public class TextComponentEditor : Editor
{
    TextComponent text;

    TextConfig config;
    TextComponent.TextType type;

    void OnEnable()
    {
        text = target as TextComponent;
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        text.textConfig = EditorGUILayout.ObjectField("TextConfig", text.textConfig, typeof(TextConfig), true) as TextConfig;
        text.textType = (TextComponent.TextType)EditorGUILayout.EnumPopup("TextType", text.textType);

        serializedObject.ApplyModifiedProperties();

        if(text.textConfig != config || text.textType != type)
        {
            config = text.textConfig;
            type = text.textType;
            text.SetTextType();
        }
    }
}
  • ScriptableObject
using UnityEngine;
using TMPro;

public interface ITextConfig
{
    Font UGUIFont { get; }
    TMP_FontAsset TMPFont { get; }
    int FontSize { get; }
    Color FontColor { get; }
}

[CreateAssetMenu(fileName = "TextConfig", menuName = "UI/Text Config")]
public class TextConfig : ScriptableObject, ITextConfig
{
    public enum VerticalAnchor
    {
        Top = -1,
        Middle = 0,
        Bottom,
        Stretch
    }

    public enum HorizontalAnchor
    {
        Left = -1,
        Center = 0,
        Right,
        Stretch,
    }


    [Header("・共通")]
    [SerializeField] VerticalAnchor verticalAnchor;
    [SerializeField] HorizontalAnchor horizontalAnchor;
    [SerializeField] int fontSize;
    [SerializeField] Color fontColor = Color.white;

    [Header("・uGUI")]
    [SerializeField] Font uguiFont;
    [SerializeField] bool uguiBestFit;
    [SerializeField] int uguiMinSize;
    [SerializeField] int uguiMaxSize;
    [SerializeField] TextAnchor uguiAlignment;

    [Header("・TMPro")]
    [SerializeField] TMP_FontAsset tmpFont;
    [SerializeField] Material tmpMaterial;
    [SerializeField] bool tmpAutoSize;
    [SerializeField] int tmpMinSize;
    [SerializeField] int tmpMaxSize;
    [SerializeField] TextAlignmentOptions tmpAlignment;

    [Header("・適用フラグ")]
    [SerializeField] bool setAnchor;
    [SerializeField] bool setFont;
    [SerializeField] bool setSize;
    [SerializeField] bool setColor;
    [SerializeField] bool setAutoSize;
    [SerializeField] bool setAlignment;
    [SerializeField] bool setMaterial;

    public Font UGUIFont { get { return uguiFont; } }
    public TMP_FontAsset TMPFont { get { return tmpFont; } }
    public int FontSize { get { return fontSize; } }
    public Color FontColor { get { return fontColor; } }
    public bool BestFit { get { return uguiBestFit; } }
    public int UGUIMinSize { get { return uguiMinSize; } }
    public int UGUIMaxSize { get { return uguiMaxSize; } }
    public TextAnchor UGUIAlignment { get { return uguiAlignment; } }

    public bool AutoSize { get { return tmpAutoSize; } }
    public int TMPMinSize { get { return tmpMinSize; } }
    public int TMPMaxSize { get { return tmpMaxSize; } }
    public TextAlignmentOptions TMPAlignment { get { return tmpAlignment; } }
    public Material TMPMaterial { get { return tmpMaterial; } }

    public bool IsSetAnchor { get { return setAnchor; } }
    public bool IsSetFont { get { return setFont; } }
    public bool IsSetSize { get { return setSize; } }
    public bool IsSetColor { get { return setColor; } }
    public bool IsSetAutoSize { get { return setAutoSize; } }
    public bool IsSetAlignment { get { return setAlignment; } }
    public bool IsSetMaterial { get { return setMaterial; } }

    public float MinX
    {
        get
        {
            switch(horizontalAnchor)
            {
                case HorizontalAnchor.Left:
                    return 0f;
                case HorizontalAnchor.Center:
                    return 0.5f;
                case HorizontalAnchor.Right:
                    return 1.0f;
                case HorizontalAnchor.Stretch:
                    return 0f;
                default:
                    return 0.5f;
            }
        }
    }
    public float MaxX
    {
        get
        {
            switch(horizontalAnchor)
            {
                case HorizontalAnchor.Left:
                    return 0f;
                case HorizontalAnchor.Center:
                    return 0.5f;
                case HorizontalAnchor.Right:
                    return 1.0f;
                case HorizontalAnchor.Stretch:
                    return 1.0f;
                default:
                    return 0.5f;
            }
        }
    }
    public float MinY
    {
        get
        {
            switch(verticalAnchor)
            {
                case VerticalAnchor.Top:
                    return 1.0f;
                case VerticalAnchor.Middle:
                    return 0.5f;
                case VerticalAnchor.Bottom:
                    return 0f;
                case VerticalAnchor.Stretch:
                    return 0f;
                default:
                    return 0.5f;
            }
        }
    }
    public float MaxY
    {
        get
        {
            switch(verticalAnchor)
            {
                case VerticalAnchor.Top:
                    return 1.0f;
                case VerticalAnchor.Middle:
                    return 0.5f;
                case VerticalAnchor.Bottom:
                    return 0f;
                case VerticalAnchor.Stretch:
                    return 1.0f;
                default:
                    return 0.5f;
            }
        }
    }

}