赞
踩
【Unity编辑器扩展】UI变量代码自动生成工具(编辑器扩展干货/大幅提高效率)_TopGames的博客-CSDN博客_unity编辑器扩展工具
比如,项目的UI界面Prefab都拼好了,突然要求更换所有文字字体. 再比如,我用Ferr2D Terrain Tool费劲九牛二虎之力拖出了一百多关地形,突然发现Unity自带的SpriteShape2D更好用,又节省资源.如果一个一个手动修改,还不得把人累死,更何况也很难保证不存在漏网之鱼. OK,所以我觉得,懒惰挺好的,因为它是我寻找高效工作方式的动力?
首先,在做批处理之前必须要清楚一个问题,那就是手动修改Prefab的步骤. 批处理无非就是用代码自动化重复这些步骤,强大的Unity编辑器已经留好了这些操作的API, 通过手动可以执行的操作也都可以通过API来完成.
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- using TMPro;
- using UnityEditor;
-
- public class PrefabTools : EditorWindow
- {
- private static Font toFont;
- private static TMP_FontAsset tmFont;
-
- [MenuItem("Game Framework/Replace Font")]
- public static void ShowWin()
- {
- EditorWindow.CreateInstance<PrefabTools>().Show();
- }
- private void OnGUI()
- {
- GUILayout.Space(10);
- toFont = (Font)EditorGUILayout.ObjectField(new GUIContent("Font:"),toFont, typeof(Font), true, GUILayout.MinWidth(100f));
- tmFont = (TMP_FontAsset)EditorGUILayout.ObjectField(new GUIContent("TMP_FontAsset:"),tmFont, typeof(TMP_FontAsset), true, GUILayout.MinWidth(100f));
- terrTemplate = (GameObject)EditorGUILayout.ObjectField(new GUIContent("SpriteShape Template"), terrTemplate, typeof(GameObject), true, GUILayout.MinWidth(100f));
- terrPfb = (GameObject)EditorGUILayout.ObjectField(new GUIContent("Terr Prefab"), terrPfb, typeof(GameObject), true, GUILayout.MinWidth(100f));
- GUILayout.Space(10);
- if (GUILayout.Button("Replace Font"))
- {
- //ReplaceFont();
- }
- if (GUILayout.Button("Replace SpriteShape"))
- {
-
- //ReplaceTerr();
- //CreateJoints();
- //FindAllScripts();
- }
- }
- }
- string[] sdirs = { "Assets/MainGame/Prefabs/UI" };
- var asstIds = AssetDatabase.FindAssets("t:Prefab", sdirs);
- for (int i = 0; i < asstIds.Length; i++)
- {
- string path = AssetDatabase.GUIDToAssetPath(asstIds[i]);
- var pfb = AssetDatabase.LoadAssetAtPath<GameObject>(path);
- }
- var texts = pfb.GetComponentsInChildren<Text>(true);
- foreach (var item in texts)
- {
- item.font = toFont;
- }
- var tmTexts = pfb.GetComponentsInChildren<TextMeshProUGUI>(true);
- foreach (var item in tmTexts)
- {
- item.font = tmFont;
- }
PrefabUtility.SavePrefabAsset(pfb, out bool success);
当然还可以显示一个进度条,给用户一些反馈.
- public static void ReplaceFont()
- {
- EditorUtility.DisplayProgressBar("Progress", "Replace Font...", 0);
- var asstIds = AssetDatabase.FindAssets("t:Prefab", sdirs);
- int count = 0;
- for (int i = 0; i < asstIds.Length; i++)
- {
- string path = AssetDatabase.GUIDToAssetPath(asstIds[i]);
- var pfb = AssetDatabase.LoadAssetAtPath<GameObject>(path);
- //var pfb = PrefabUtility.InstantiatePrefab(pfbFile) as GameObject;//不涉及增删节点,不用实例化
- var texts = pfb.GetComponentsInChildren<Text>(true);
- foreach (var item in texts)
- {
- item.font = toFont;
- }
- var tmTexts = pfb.GetComponentsInChildren<TextMeshProUGUI>(true);
- foreach (var item in tmTexts)
- {
- item.font = tmFont;
- }
- PrefabUtility.SavePrefabAsset(pfb, out bool success);
- if (success)
- {
- count++;
- }
- EditorUtility.DisplayProgressBar("Replace Font Progress", pfb.name, count / (float)asstIds.Length);
- }
- EditorUtility.ClearProgressBar();
- }
我用的Unity版本是2019.2.3f1, 2D SpriteShape目前还是预览版, 但是不影响它的方便好用. Unity论坛有详细介绍:SpriteShape
原理: 实际上就是把已经拖好的Ferr2D Terrain地形的顶点给SpriteShape用.
需要注意的是,这里需要对prefab增/删节点, Unity是不允许修改prefab实例的结构的,它会提示让你打开prefab进行修改. 而这个双击打开Prefab的操作就是对应API, PrefabUtility.LoadPrefabContents(asset_path), 通过这个API打开Prefab就可以任意修改prefab结构了.
完整方法代码:
- public static void ReplaceTerr()
- {
- EditorUtility.DisplayProgressBar("Progress", "Replace SpriteShape...", 0);
- string[] dirs = { "Assets/MainGame/Prefabs/Entity/Levels" };
- var asstIds = AssetDatabase.FindAssets("t:Prefab", dirs);
- int count = 0;
- for (int i = 0; i < asstIds.Length; i++)
- {
- string path = AssetDatabase.GUIDToAssetPath(asstIds[i]);
- var lvRoot = PrefabUtility.LoadPrefabContents(path);
- var terrs = lvRoot.GetComponentsInChildren<Ferr2DT_PathTerrain>();
- bool changed = terrs.Length > 0;
- for (int j = 0; j < terrs.Length; j++)
- {
- var terr = terrs[j];
- var spShape = PrefabUtility.InstantiatePrefab(terrTemplate, terr.transform.parent) as GameObject;
- spShape.name = string.Format("SpriteShape_{0}", j);
- spShape.transform.position = terr.transform.position;
- spShape.transform.rotation = terr.transform.rotation;
- spShape.transform.localScale = Vector3.one;
- var spline = spShape.GetComponent<UnityEngine.U2D.SpriteShapeController>().spline;
- spline.Clear();
- var pathDt = terr.PathData;
- var points = pathDt.GetPathRaw();
- int rawIndex = spline.GetPointCount() - 1;
- for (int pindex = 0; pindex < points.Count; pindex++)
- {
- var p = points[pindex] * terr.transform.localScale;
- spline.InsertPointAt(pindex, p);
- }
- spShape.GetComponent<UnityEngine.U2D.SpriteShapeController>().BakeCollider();
- var logic = terr.GetComponent<PhysicsTarget>();
- if (null != logic)
- {
- if (UnityEditorInternal.ComponentUtility.CopyComponent(logic))
- {
- UnityEditorInternal.ComponentUtility.PasteComponentAsNew(spShape);
- }
- }
- }
- for (int index = terrs.Length - 1; index >= 0; index--)
- {
- DestroyImmediate(terrs[index].gameObject);
- }
- if (changed)
- {
- PrefabUtility.SaveAsPrefabAsset(lvRoot, path);
- }
-
- PrefabUtility.UnloadPrefabContents(lvRoot);
- count++;
- EditorUtility.DisplayProgressBar("Replace SpriteShape Progress", path, count / (float)asstIds.Length);
- }
- EditorUtility.ClearProgressBar();
- }
代码中还有两个比较常用的API, 就是组件的复制和粘贴,不用一个一个修改替换组件的属性了,复制粘贴即可,非常方便.
- UnityEditorInternal.ComponentUtility.CopyComponent(logic)
- UnityEditorInternal.ComponentUtility.PasteComponentAsNew(spShape);
功能如图:
代码和原理都非常简单,却能数倍提高效率,以后要多多研究编辑器扩展方面了?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。