killapp/Assets/Editor/BatchFontReplacer.cs

197 lines
6.4 KiB
C#
Raw Normal View History

2026-06-17 15:42:55 +08:00
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using System.Collections.Generic;
using System.IO;
namespace Kill.Editor
{
/// <summary>
/// 批量字体替换工具
/// 一次性替换项目中所有 Text 组件的字体
/// </summary>
public class BatchFontReplacer : EditorWindow
{
private Font targetFont;
private bool includeInactive = true;
private bool includePrefabs = true;
private Vector2 scrollPosition;
private List<string> modifiedObjects = new List<string>();
[MenuItem("Tools/批量替换字体")]
static void OpenWindow()
{
GetWindow<BatchFontReplacer>("批量替换字体");
}
void OnGUI()
{
GUILayout.Label("批量替换字体工具", EditorStyles.boldLabel);
EditorGUILayout.Space();
// 选择目标字体
targetFont = (Font)EditorGUILayout.ObjectField(
"目标字体", targetFont, typeof(Font), false);
if (targetFont == null)
{
EditorGUILayout.HelpBox("请选择一个中文字体文件", MessageType.Warning);
return;
}
EditorGUILayout.Space();
// 选项
includeInactive = EditorGUILayout.Toggle("包含未激活的物体", includeInactive);
includePrefabs = EditorGUILayout.Toggle("包含预制体资源", includePrefabs);
EditorGUILayout.Space();
// 按钮
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("替换场景中的 Text", GUILayout.Height(30)))
{
ReplaceFontsInScene();
}
if (GUILayout.Button("替换预制体中的 Text", GUILayout.Height(30)))
{
ReplaceFontsInPrefabs();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
if (GUILayout.Button("一键替换全部", GUILayout.Height(40)))
{
ReplaceAllFonts();
}
EditorGUILayout.Space();
// 显示修改记录
if (modifiedObjects.Count > 0)
{
GUILayout.Label($"已修改 {modifiedObjects.Count} 个对象:", EditorStyles.boldLabel);
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(200));
foreach (var obj in modifiedObjects)
{
EditorGUILayout.LabelField(obj);
}
EditorGUILayout.EndScrollView();
}
}
/// <summary>
/// 替换场景中的所有 Text
/// </summary>
private void ReplaceFontsInScene()
{
if (targetFont == null) return;
modifiedObjects.Clear();
int count = 0;
// 获取场景中的所有 Text
Text[] texts = Resources.FindObjectsOfTypeAll<Text>();
foreach (var text in texts)
{
// 只处理场景中的物体
if (!text.gameObject.scene.IsValid()) continue;
// 检查是否未激活
if (!includeInactive && !text.gameObject.activeInHierarchy) continue;
// 替换字体
if (text.font != targetFont)
{
Undo.RecordObject(text, "Replace Font");
text.font = targetFont;
EditorUtility.SetDirty(text);
modifiedObjects.Add($"[场景] {text.gameObject.name}");
count++;
}
}
Debug.Log($"[批量替换字体] 场景中共替换了 {count} 个 Text 组件");
}
/// <summary>
/// 替换所有预制体中的 Text
/// </summary>
private void ReplaceFontsInPrefabs()
{
if (targetFont == null) return;
modifiedObjects.Clear();
int count = 0;
// 查找所有预制体文件
string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets" });
foreach (string guid in prefabGuids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
if (prefab == null) continue;
// 获取预制体中的所有 Text
Text[] texts = prefab.GetComponentsInChildren<Text>(true);
bool modified = false;
foreach (var text in texts)
{
if (text.font != targetFont)
{
text.font = targetFont;
modified = true;
count++;
}
}
// 保存修改
if (modified)
{
EditorUtility.SetDirty(prefab);
modifiedObjects.Add($"[预制体] {path}");
}
}
// 保存所有修改
AssetDatabase.SaveAssets();
Debug.Log($"[批量替换字体] 预制体中共替换了 {count} 个 Text 组件");
}
/// <summary>
/// 一键替换全部
/// </summary>
private void ReplaceAllFonts()
{
if (targetFont == null)
{
EditorUtility.DisplayDialog("错误", "请先选择一个字体", "确定");
return;
}
if (EditorUtility.DisplayDialog("确认",
"这将替换项目中所有 Text 组件的字体,是否继续?",
"确定", "取消"))
{
ReplaceFontsInScene();
ReplaceFontsInPrefabs();
EditorUtility.DisplayDialog("完成",
$"共替换了 {modifiedObjects.Count} 个对象",
"确定");
}
}
}
}
#endif