Programming Serendipity

プログラミングを中心に種々雑多に書き留めます

Unity上のTextのフォントを一括で変更するエディタ拡張

全てのTextコンポーネントのフォントを一斉に指定したフォントに置き換えるスクリプトです。

FontReplacer.csというスクリプトを"Editor"という名前のフォルダの下に新規作成して以下の内容を記述し、メニューバーからTools > Replace All Fontsを選び、フォントを選択してボタンを押すと、全てのテキストが選択したフォントになります。

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using UnityEditor.SceneManagement;

public class MyFont : ScriptableObject
{
    public Font font;
}

public class FontReplacer : EditorWindow 
{
    static SerializedProperty sp;

    [MenuItem("Tools/Replace All Fonts")]
    public static void ShowWindow()
    {
        EditorWindow a = EditorWindow.GetWindow(typeof(FontReplacer), true, "Font Replacer");
        var obj = ScriptableObject.CreateInstance<MyFont>();
        var serializedObject = new UnityEditor.SerializedObject(obj);

        sp = serializedObject.FindProperty("font");

        Debug.Log("font " + sp.propertyType);
    }

    void OnGUI()
    {
        EditorGUILayout.PropertyField(sp);
        if (GUILayout.Button("Replace All Fonts"))
        {
            Debug.Log("you are trying to replace all fonts to new one");

            var textComponents = Resources.FindObjectsOfTypeAll(typeof(Text)) as Text[];
            foreach (var component in textComponents)
            {
                component.font = sp.objectReferenceValue as Font;
            }
            // ※追記 : シーンに変更があることをUnity側に通知しないと、シーンを切り替えたときに変更が破棄されてしまうので、↓が必要
            EditorSceneManager.MarkAllScenesDirty();
        }
    }
}

似たようなスクリプトはいくつかweb上に見つかりますが、テキストを列挙する部分でFindObjectsOfType()を使っているものがあり、これだと今アクティブでないテキストが変換対象になりませんでした。そこでこちらではResources.FindObjectsOfTypeAll()を使って非アクティブなテキストも対象にしています。(逆に、アクティブなテキストだけ変えたいときや、一部だけ変えたいときに他のオブジェクトを非アクティブにしてFindObjectsOfType()を使うというやり方もありですね)
ちなみに、Object.FindObjectsOfTypeAll()もありますが、Unityが内部的に使用するシーンビューカメラなども対象になってしまうため非推奨のようです。