目录
本篇文章来分享一下Unity如何制作更换字体的插件,可以快速更换场景中所有字体,更换所有预制体中的字体,更换指定路径下预制体中的字体。
1.前置知识
1.1 EditorWindow
1)目的
自定义Unity功能插件,在Unity编辑器中显示,点击功能按钮后,弹出对应的窗口,可以在编辑器界面上直接进行操作。
2)使用方式
①自定义的类继承EditorWindow
②类中自定义一个静态方法ShowWindow,用于获取或创建EditorWindow窗口实例并显示它。这个方法用public static修饰,并且用MenuItem属性标记([MenuItem("Tools/Change Font")])。在该方法中调用EditorWindow.GetWindow方法。
③EditorWindow.GetWindow是获取或创建自定义编辑器窗口的静态方法,用于创建自定义的编辑器
1.2 OnGUI()
1)目的
自定义窗口布局,OnGUI属于Unity生命周期中的方法,可以看一下Unity生命周期。
2)使用方式
GUILayout:用于运行时和编辑器模式下的GUI元素布局。
EditorGUILayout:EditorGUILayout是GUILayout的扩展,增加了针对编辑器的特定功能。专门用于Unity编辑器窗口中创建和布局用户界面,在EditorWindow和自定义Editor脚本中使用。
1.3 AssetDatabase
1)目的
对项目中的资源(Assets)进行查找,修改等操作。
AssetDatabase是Unity编辑器中的一个静态类,提供了与项目中的资源(Assets)进行交互的功能。通 AssetDatabase,可以执行各种与资源管理相关的操作,包括创建、删除、移动、重命名资源,甚至检索资源的路径或信息等。主要用于编辑器脚本和自定义编辑器工具,对资源进行管理和操作。
2)使用方式
AssetDatabase.CreateAsset: 创建一个新的资产并保存到项目中。
AssetDatabase.ImportAsset: 强制导入或重新导入指定路径的资产。
AssetDatabase.DeleteAsset: 删除指定路径的资产。
AssetDatabase.MoveAsset: 移动资产到新的路径。
AssetDatabase.GetAssetPath: 获取指定对象的资源路径。
AssetDatabase.LoadAssetAtPath: 从指定路径加载资源对象。
AssetDatabase.Refresh: 刷新 AssetDatabase,以便 Unity 重新加载资源的变化。
AssetDatabase.SaveAssets: 保存对资源的修改。
AssetDatabase.FindAssets: 根据搜索条件(如标签、类型)查找资源。
AssetDatabase.GUIDToAssetPath: 将资源的GUID(全局唯一标识符)转换为其在项目中的路径。
1.4 PrefabUtility
1)目的
对资源中的预制体进行编辑、创建等操作。
PrefabUtility是Unity编辑器中的一个静态类,用于操作和管理预制体(Prefab)。提供了对预制体的编辑、创建和应用操作的功能。PrefabUtility主要用于编辑器脚本,允许在编写自定义工具和自动化流程时对预制体进行各种操作。
2)使用方式
PrefabUtility.GetPrefabAssetType: 获取指定对象的预制体类型。
PrefabUtility.GetPrefabInstanceHandle: 获取预制体实例的句柄,用于编辑和修改实例。
PrefabUtility.ApplyPrefabInstance: 将对预制体实例所做的更改应用到预制体资产。
PrefabUtility.RevertPrefabInstance: 将预制体实例恢复为原始预制体资产的状态。
PrefabUtility.InstantiatePrefab: 实例化预制体资产并返回其实例。
PrefabUtility.SaveAsPrefabAsset: 将游戏对象保存为新的预制体资产。
PrefabUtility.IsPartOfImmutablePrefab: 判断一个游戏对象是否是一个不可变预制体(Immutable Prefab)的部分。不可变预制体是指无法修改其内容的预制体,通常用于在特定场景中保护预制体的完整性。
2.代码
using System.Linq;
using TMPro;
using UnityEditor;
using UnityEngine;
public class ChangeFont : EditorWindow
{
private TMP_FontAsset selectedFont;
private string directory = "Please Enter The Full Path";//相对于项目文件夹的路径 Assets/...
//菜单项
[MenuItem("Tools/Change Font")]
private static void ShowWindow()
{
//获取或创建一个ChangeFont实例,并进行显示
EditorWindow.GetWindow<ChangeFont>("Change Font");
}
//绘制编辑器窗口的界面
private void OnGUI()
{
//提示
EditorGUILayout.LabelField("Select Font:", EditorStyles.boldLabel);
//显示一个下拉列表,让用户选择一个字体
selectedFont = (TMP_FontAsset)EditorGUILayout.ObjectField(selectedFont, typeof(TMP_FontAsset), false);
//添加一个按钮,点击按钮时更换所有字体
if (GUILayout.Button("Apply All Fonts In Scene"))
{
if (selectedFont != null)
{
ChangeAllFonts(selectedFont);
}
else
{
Debug.LogWarning("Please select a font first!");
}
}
EditorGUILayout.LabelField("");
if (GUILayout.Button("Apply All Fonts In All Prefabs"))
{
if (selectedFont != null)
{
ChangeFontsInAllPrefabs(selectedFont);
}
else
{
Debug.LogWarning("Please select a font first!");
}
}
EditorGUILayout.LabelField("");
//输入文本框
directory = EditorGUILayout.TextField("Specified Directory", directory);
if (GUILayout.Button("Apply All Fonts In Prefabs In Directory"))
{
if (selectedFont != null)
{
if (directory != null && directory != "Please enter the full path")
{
ChangeFontsInPrefabsInDirectory(selectedFont, directory);
}
else
{
Debug.LogWarning("Please enter a directory!");
}
}
else
{
Debug.LogWarning("Please select a font first!");
}
}
}
/// <summary>
/// 更换场景中所有文本的字体
/// </summary>
/// <param name="font">选择的字体</param>
private static void ChangeAllFonts(TMP_FontAsset font)
{
//得到场景中的所有TMP_Text,并更换TMP_Text的字体
TMP_Text[] allTexts = GameObject.FindObjectsOfType<TMP_Text>();
foreach (TMP_Text text in allTexts)
{
text.font = font;
}
if (allTexts.Length > 0)
{
//用于刷新AssetDatabase的缓存和数据,使得最新的资源信息和项目状态能够在编辑器中正确显示和更新
AssetDatabase.Refresh();
Debug.Log("Changed all fonts in scene to: " + font.name);
}
else
{
Debug.Log("There are no fonts to change");
}
}
/// <summary>
/// 更换所有预制体中的字体
/// </summary>
/// <param name="font">选择的字体</param>
private static void ChangeFontsInAllPrefabs(TMP_FontAsset font)
{
//查找所有预制体,并返回预制体资源的GUID(全局唯一标识符)数组
string[] prefabPaths = AssetDatabase.FindAssets("t:Prefab");
foreach (string prefabPath in prefabPaths)
{
//将资源的GUID(全局唯一标识符)转换为资源在项目中的路径
string path = AssetDatabase.GUIDToAssetPath(prefabPath);
//从指定路径加载资源对象
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
//预制体不为空 并且 预制体 不是 不可变的
if (prefab != null && !PrefabUtility.IsPartOfImmutablePrefab(prefab))
{
//获取预制体中的所有 TextMeshPro 文本组件
TMP_Text[] texts = prefab.GetComponentsInChildren<TMP_Text>(true);
foreach (var text in texts)
{
text.font = font;
}
//保存修改后的预制体
PrefabUtility.SaveAsPrefabAsset(prefab, path);
}
}
if (prefabPaths.Length > 0)
{
AssetDatabase.Refresh();
Debug.Log("Changed all fonts in scene to: " + font.name);
}
else
{
Debug.Log("There are no fonts to change");
}
}
/// <summary>
/// 更换指定目录下的预制体中的字体
/// </summary>
/// <param name="font">选择的字体</param>
/// <param name="directory">指定的目录,Assets/...</param>
private static void ChangeFontsInPrefabsInDirectory(TMP_FontAsset font, string directory)
{
//AssetDatabase.FindAssets查找指定文件夹下的所有预制体路径
//"t:Prefab" :查找条件,表示查找类型为预制体(Prefab)的资源
//new[] { directory } : 指定查找的文件夹路径,如 "Assets/Resources"
//Select : LINQ 方法,用于对查找到的资源进行转换
//AssetDatabase.GUIDToAssetPath将资源的 GUID 转换为实际的资源路径
string[] prefabPaths = AssetDatabase.FindAssets("t:Prefab", new[] { directory }).Select(AssetDatabase.GUIDToAssetPath).ToArray();
foreach (string path in prefabPaths)
{
//从指定路径加载资源对象
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
//预制体不为空 并且 预制体 不是 不可变的
if (prefab != null && !PrefabUtility.IsPartOfImmutablePrefab(prefab))
{
//更换预制体中所有文本组件的字体
TMP_Text[] prefabTexts = prefab.GetComponentsInChildren<TMP_Text>(true);
foreach (var text in prefabTexts)
{
text.font = font;
}
//保存预制体更改
PrefabUtility.SaveAsPrefabAsset(prefab, PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab), out bool success);
if (success)
{
AssetDatabase.Refresh();
Debug.Log($"Saved prefab: {prefab.name}");
}
else
{
Debug.LogWarning($"Failed to save prefab: {prefab.name}");
}
}
}
if (prefabPaths.Length > 0)
{
Debug.Log("Changed all fonts in prefabs in " + directory + " to: " + font.name);
}
else
{
Debug.Log("There are no fonts to change");
}
}
}
3.测试
在菜单选择“Change Font”,会弹出对应的窗口
选择想要更换的字体,点击应用按钮即可进行更换。①“Apply All Fonts In Scene”:更换场景中所有字体;②“Apply All Fonts In All Prefabs”:更换所有预制体中的字体;③“Apply All Fonts In Prefabs In Directory”:更换指定路径下预制体中的字体,该目录相对于项目文件夹的路径,如Assets/...
好了,本次的分享到这里就结束啦,希望对你有所帮助,优秀~