当前位置: 首页 > news >正文

Unity 基于Odin编辑器插件写了一个替换文件夹下所有Prefab中标记的Text或者Image颜色的工具

工具背景:游戏换风格,多个界面的风格颜色需要更换,有些甚至是隐藏的,不好找!

一键替换吧

插件:Odin Inspector and Serializer v3.3.1.13

打开资源替换工具

在这里插入图片描述

点击遍历资源,会查找目录下的所有Prefab里的标记

同时也包括当前打开场景内的标记

在这里插入图片描述
标记脚本为:

using UnityEngine;[DisallowMultipleComponent]
public class ColorMarker : MonoBehaviour
{// 只是个标记组件,不需要内容
}

挂在需要改变的物体上即可

可点击单个替换

也可确定全部替换

代码如下:

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using UnityEditor.SceneManagement;
using UnityEngine.UI;#if TMP_PRESENT
using TMPro;
#endifpublic class ColorReplaceTool : OdinEditorWindow
{private static ColorReplaceTool _instance;private void OnDisable() => _instance = null;public static ColorReplaceTool Instance => _instance;[MenuItem("Tools/颜色替换工具")]private static void OpenWindow() => GetWindow<ColorReplaceTool>("颜色替换工具");[BoxGroup("资源路径(把Unity里的文件拖拽到此)")][FolderPath(AbsolutePath = false, RequireExistingPath = true)][LabelText("Prefab目录(可多个)")]public List<string> newFolders = new() {"Assets/Game/Prefabs/GUI/Resources","Assets/Game/Prefabs/Modules/Resources"};[LabelText("新颜色")]public Color newColor;private string ScenePath = "CurrentScene";protected override void OnEnable(){base.OnEnable();_instance = this;// 解析 #51FD83 颜色if (ColorUtility.TryParseHtmlString("#51FD83", out var color)){newColor = color;}}private void TraverseCurrentSceneObjects(){newFileCount = 0;// 获取所有场景中的根对象var roots = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();foreach (var root in roots){var markers = root.GetComponentsInChildren<ColorMarker>(true);foreach (var marker in markers){Component[] allComponents = marker.GetComponents<Component>();foreach (Component comp in allComponents){if (comp is Renderer renderer && renderer.sharedMaterial != null){newFileCount++;matchedAssets.Add(new ColorReplaceItem{objectName = marker.gameObject.name,ComponentType = comp.GetType().Name,originalColor = renderer.sharedMaterial.color,cPath = GetHierarchyPath(marker.transform),prefabPath = ScenePath,targetComponent = comp,gameObject = marker.gameObject});}else if (comp is Graphic graphic){newFileCount++;matchedAssets.Add(new ColorReplaceItem{objectName = marker.gameObject.name,ComponentType = comp.GetType().Name,originalColor = graphic.color,cPath = GetHierarchyPath(marker.transform),prefabPath =ScenePath,targetComponent = comp,gameObject = marker.gameObject});}
#if TMP_PRESENTelse if (comp is TextMeshProUGUI tmp){newFileCount++;matchedAssets.Add(new ColorReplaceItem{objectName = marker.gameObject.name,ComponentType = comp.GetType().Name,originalColor = tmp.color,cPath = GetHierarchyPath(marker.transform),prefabPath = path});}
#endif}}// 立即刷新 InspectorGUI.FocusControl(null);Repaint(); // 让 OdinEditorWindow 重新绘制Debug.Log($"场景中共找到 {newFileCount} 个 ColorMarker");}}[BoxGroup("操作")][Button("遍历 Prefab")]private void ScanResources(){newFileCount = 0;matchedAssets.Clear();TraverseCurrentSceneObjects();foreach (var VARIABLE in newFolders){string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab", new[] { VARIABLE });foreach (string guid in prefabGuids){string path = AssetDatabase.GUIDToAssetPath(guid);GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);if (prefab == null) continue;GameObject instance = PrefabUtility.InstantiatePrefab(prefab) as GameObject;if (instance == null) continue;foreach (var marker in instance.GetComponentsInChildren<ColorMarker>(true)){Component[] allComponents = marker.GetComponents<Component>();foreach (Component comp in allComponents){if (comp is Renderer renderer && renderer.sharedMaterial != null){newFileCount++;matchedAssets.Add(new ColorReplaceItem{objectName = marker.gameObject.name,ComponentType = comp.GetType().Name,originalColor = renderer.sharedMaterial.color,cPath = GetHierarchyPath(marker.transform),prefabPath = path});}else if (comp is Graphic graphic){newFileCount++;matchedAssets.Add(new ColorReplaceItem{objectName = marker.gameObject.name,ComponentType = comp.GetType().Name,originalColor = graphic.color,cPath = GetHierarchyPath(marker.transform),prefabPath = path});}
#if TMP_PRESENTelse if (comp is TextMeshProUGUI tmp){newFileCount++;matchedAssets.Add(new ColorReplaceItem{objectName = marker.gameObject.name,ComponentType = comp.GetType().Name,originalColor = tmp.color,cPath = GetHierarchyPath(marker.transform),prefabPath = path});}
#endif}}DestroyImmediate(instance);}}showScanSummary = true;GUI.FocusControl(null);Repaint();Debug.Log($"共找到 {matchedAssets.Count} 个带 ColorMarker 的对象");}private string GetHierarchyPath(Transform transform){string path = transform.name;while (transform.parent != null){transform = transform.parent;path = transform.name + "/" + path;}return path;}[BoxGroup("操作")][Button("全部替换颜色并保存")]private void ReplaceAll(){foreach (var item in matchedAssets){ReplaceAndSave(item);}AssetDatabase.SaveAssets();AssetDatabase.Refresh();Debug.Log("替换完毕");}private void ReplaceAndSave(ColorReplaceItem item){if (item.prefabPath.Equals(ScenePath)){//场景里的组件替换颜色if (item.targetComponent == null) return;Undo.RecordObject(item.targetComponent, "Replace Scene Color");Color oldColor = item.originalColor;Color updatedColor = new Color(newColor.r, newColor.g, newColor.b, oldColor.a);if (item.targetComponent is Graphic graphic){graphic.color = updatedColor;EditorUtility.SetDirty(graphic);}
#if TMP_PRESENTelse if (item.targetComponent is TextMeshProUGUI tmp){tmp.color = updatedColor;EditorUtility.SetDirty(tmp);}
#endifelse if (item.targetComponent is Renderer renderer && renderer.sharedMaterial != null){renderer.sharedMaterial.color = updatedColor;EditorUtility.SetDirty(renderer.sharedMaterial);}item.originalColor = updatedColor;EditorSceneManager.MarkSceneDirty(item.gameObject.scene);EditorSceneManager.SaveScene(item.gameObject.scene);UnityEditorInternal.InternalEditorUtility.RepaintAllViews();return;}GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(item.prefabPath);GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);var target = FindByName(instance, item.objectName);if (target != null){bool changed = false;foreach (var comp in target.GetComponents<Component>()){if (comp is Renderer renderer && renderer.sharedMaterial != null){Undo.RecordObject(renderer.sharedMaterial, "Replace Renderer Color");Color oldColor = renderer.sharedMaterial.color;renderer.sharedMaterial.color = new Color(newColor.r, newColor.g, newColor.b, oldColor.a);changed = true;}else if (comp is Graphic graphic){Undo.RecordObject(graphic, "Replace UI Graphic Color");Color oldColor = graphic.color;graphic.color = new Color(newColor.r, newColor.g, newColor.b, oldColor.a);changed = true;}#if TMP_PRESENTelse if (comp is TextMeshProUGUI tmp){Undo.RecordObject(tmp, "Replace TMP Color");tmp.color = newColor;changed = true;}
#endif}if (changed){PrefabUtility.SaveAsPrefabAsset(instance, item.prefabPath);// ✅ 更新 originalColorColor oldColor = item.originalColor;item.originalColor =new Color(newColor.r, newColor.g, newColor.b, oldColor.a);}}DestroyImmediate(instance);}private GameObject FindByName(GameObject root, string name){foreach (Transform t in root.GetComponentsInChildren<Transform>(true)){if (t.name == name) return t.gameObject;}return null;}private bool showScanSummary = false;private int newFileCount = 0;[OnInspectorGUI, PropertyOrder(-1)]private void DrawScanSummaryBox(){if (showScanSummary){EditorGUILayout.HelpBox($"扫描完成,共扫描 {newFileCount} 个新资源,成功匹配 {matchedAssets.Count} 个资源。",MessageType.Info);}}[BoxGroup("结果列表")][ShowInInspector][ListDrawerSettings(ShowPaging = false, DraggableItems = false, Expanded = true)][Searchable][TableList(AlwaysExpanded = true)]private List<ColorReplaceItem> matchedAssets = new();[System.Serializable]public class ColorReplaceItem{[TableColumnWidth(600, Resizable = true)][ReadOnly]public string cPath;[TableColumnWidth(100, Resizable = true)][ReadOnly]public string objectName;[TableColumnWidth(100, Resizable = true)][ReadOnly]public string ComponentType;[TableColumnWidth(100, Resizable = true)][ReadOnly]public Color originalColor;[TableColumnWidth(100, Resizable = true)][Button("替换", ButtonSizes.Medium)]private void Replace(){ColorReplaceTool.Instance?.ReplaceAndSave(this);Debug.Log($"已替换颜色: {objectName}");}[HideInInspector]public string prefabPath;[HideInInspector] public Component targetComponent;[HideInInspector] public GameObject gameObject;public bool isSceneObject => prefabPath == "CurrentScene";[ShowInInspector, TableColumnWidth(80), LabelText("来源")]public string 来源 => isSceneObject ? "场景" : "Prefab";}
}
http://www.dtcms.com/a/290909.html

相关文章:

  • ACOT Buck输出电容大小的计算
  • fibonacci的4种实现
  • Unity之可视化编程VisualScripting快速入门
  • 1553啤酒品牌作为都洲武魂世界格斗冠军赛冠名赞助商
  • Jenkins pipeline触发下游流水线
  • 数据结构:反转字符串(Reversing a String)
  • 052_迭代器(Iterator / ListIterator)
  • HCL 三层知识总结
  • Java 二叉树
  • uniapp+vue3预约时间和日期
  • registry-ui docker搭建私有仓库的一些问题笔记
  • 在React中做过哪些性能优化?
  • java每日精进 7.21【Uel表达式和流程设计】
  • 【Elasticsearch】IndexModule
  • 【沧海拾昧】微分先行PID与中间微分反馈控制
  • 工业网关的应用场景
  • 【正常配置了beast扩展,phpinfo信息也显示了,但是就是不运行】
  • 前端-DOM
  • pandas 的series和dataframe的用法,六个题目
  • 141、环形链表
  • 前后端分离项目进阶1---后端
  • 果园里的温柔之手:Deepoc具身智能如何重塑采摘机器人的“生命感知”
  • Python day20 - 特征降维之奇异值分解
  • 【设计模式C#】工厂方法模式(相比简单工厂模式更加具有灵活性和扩展性的工厂模式)
  • git_guide
  • prometheus主动服务发现机制
  • 在 React 中实现全局防复制hooks
  • Java 解析前端上传 ZIP 压缩包内 Excel 文件的完整实现方案
  • Neo4j 5.x版本的导出与导入数据库
  • 易语言+懒人精灵/按键中控群控教程(手机、主板机、模拟器通用)