编辑器扩展
自定义类型的显示:
public class TestClass { public int value; public string name = ""; } public class TestEditor : EditorWindow { public static TestEditor window = null; [MenuItem("Test/MyEditor &t")] public static void ShowWindow() { window = EditorWindow.GetWindow(typeof(TestEditor), false, "TestEditor") as TestEditor; } private List<TestClass> lst = new List<TestClass>(); private bool showFoldout = true; private Vector2 scrollPosition = Vector2.zero; int count { get { return lst.Count; } set { if(value < lst.Count) { lst.RemoveRange(value, lst.Count - value); } else if(value > lst.Count) { for(int i = 0; i < value; ++i) { lst.Add(new TestClass()); } } } } void OnGUI() { GUILayout.BeginArea(new Rect(0, 0, Screen.width, Screen.height), "", "box"); GUILayout.BeginVertical("box"); scrollPosition = GUILayout.BeginScrollView(scrollPosition, "box"); // 创建自适应滚动条 // 创建折叠标签 showFoldout = EditorGUILayout.Foldout(showFoldout, "Array"); if (showFoldout) { GUILayout.BeginHorizontal(); GUILayout.Label("count", GUILayout.Width(50)); count = System.Convert.ToInt32(GUILayout.TextField(count.ToString())); GUILayout.EndHorizontal(); // 逐行显示数据 for (int i = 0; i < count; ++i) { GUILayout.BeginHorizontal(); GUILayout.Label("name", GUILayout.Width(50)); lst[i].name = GUILayout.TextField(lst[i].name); GUILayout.Label("value", GUILayout.Width(50)); lst[i].value = System.Convert.ToInt32(GUILayout.TextField(lst[i].value.ToString())); GUILayout.EndHorizontal(); } } GUILayout.EndVertical(); GUILayout.EndScrollView(); GUILayout.EndArea(); } }
上述代码在自定义编辑器中显示了自定义结构TestClass的列表,效果如下所示:
有个小细节值得一提,TestClass.name一定要初始化为"",不然现实会报错。
添加Project界面自定义菜单:
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(menuName="Test/CreateMyObject")] public class MyObject : ScriptableObject { // 中心点 public Vector3 Center; // 受击点 public List<Vector3> HitPos = new List<Vector3>(); // 受击点朝向 public List<Vector3> HitDir = new List<Vector3>(); }
获取Hierarchy中gameobject所关联的本地资源prefab:
var prefabSource = PrefabUtility.GetPrefabParent(prefab);
自定义ScriptableObject:
[CreateAssetMenu(menuName = "Test/Numbers")] public class DataNumbers : ScriptableObject { public List<int> Values = new List<int>(); } // 加载 var numberAsset = AssetDatabase.LoadAssetAtPath<DataNumbers>(filePath); for(int i = 0; i < numberAsset.Values.Count; ++i) { Debug.Log(numberAsset.Values[i]); } } // 保存 numberAsset.Values.Add(1); numberAsset.Values.Add(2); numberAsset.Values.Add(3); EditorUtility.SetDirty(numberAsset); AssetDatabase.SaveAssets();
SceneView显示当前鼠标位置:
using UnityEngine; using UnityEditor; public class WildTerrainEditor : EditorWindow { private void OnEnable() { SceneView.onSceneGUIDelegate -= OnSceneGUI; SceneView.onSceneGUIDelegate += OnSceneGUI; } private void OnDestroy() { SceneView.onSceneGUIDelegate -= OnSceneGUI; } private void OnSceneGUI(SceneView sceneView) { UpdateMousePosition(); Handles.BeginGUI(); GUI.color = Color.red; GUI.Label(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y - 20, 100, 20), SceneViewMousPos.ToString()); Handles.EndGUI(); } private void UpdateMousePosition() { Event e = Event.current; Ray r = Camera.current.ScreenPointToRay(new Vector3(e.mousePosition.x, -e.mousePosition.y + Camera.current.pixelHeight)); Vector3 mousePos = r.origin; SceneViewMousPos = mousePos; } }
统一调整渲染深度信息:
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace James { [ExecuteInEditMode] public class UniformRenderDepth : MonoBehaviour { private const int Invalid = -10000; public string SortingLayerName; // 空表示不设置 public int SortingOrder = Invalid; // -10000表示不设置 public int RenderQueue = Invalid; // -10000表示不设置 private void Start() { Set(); } [ContextMenu("Set")] public void Set() { Renderer[] renderers = GetComponentsInChildren<Renderer>(true); foreach (var r in renderers) { if (RenderQueue != Invalid) { if (Application.isPlaying) { r.material.renderQueue = RenderQueue; } else { r.sharedMaterial.renderQueue = RenderQueue; } } if (string.IsNullOrEmpty(SortingLayerName) == false) { r.sortingLayerName = SortingLayerName; } if (SortingOrder != Invalid) { r.sortingOrder = SortingOrder; } } } [ContextMenu("Get")] public void Get() { Renderer[] renderers = GetComponentsInChildren<Renderer>(true); foreach (var r in renderers) { if (Application.isPlaying) { RenderQueue = r.material.renderQueue; } else { RenderQueue = r.sharedMaterial.renderQueue; } SortingLayerName = r.sortingLayerName; SortingOrder = r.sortingOrder; break; } } } }
子节点自动排布脚本:
public class AutoSetGroup : MonoBehaviour { public Vector2 size = Vector2.one; public Vector2Int num = Vector2Int.one; [ContextMenu("Set")] public void Execute() { float hHalfSize = size.x / (2 * num.x); float vHalfSize = size.y / (2 * num.y); Vector2 topLeftPos = new Vector2(- 0.5f * size.x + hHalfSize, 0.5f * size.y - vHalfSize); int total = num.x * num.y; for(int i = 0; i < total; ++i) { if(i >= transform.childCount) return; var tran = transform.GetChild(i); int xIdx = i % num.x; int yIdx = i / num.x; var pos = tran.localPosition; pos.x = topLeftPos.x + xIdx * hHalfSize * 2; pos.y = topLeftPos.y - yIdx * vHalfSize * 2; tran.localPosition = pos; } } }
统计shader变种数量
using System; using System.Reflection; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; namespace AOE.Editor { public class ShaderVariantInfo { public string name; public int num; } public class Statistic_ShaderVariants : EditorWindow { private static EditorWindow window; private static List<ShaderVariantInfo> lst = new List<ShaderVariantInfo>(); private static int shaderNum = 0; private static int variantNum = 0; private Vector2 m_scrollPos = Vector2.zero; public static Texture2D m_texRight = null; public static Texture2D m_texWrong = null; public static Texture2D m_texPlay = null; private void OnEnable() { m_texPlay = EditorGUIUtility.FindTexture("forward@2x"); m_texRight = EditorGUIUtility.FindTexture("FilterSelectedOnly"); m_texWrong = EditorGUIUtility.FindTexture("d_P4_DeletedLocal"); } private void OnDisable() { m_texRight = null; m_texWrong = null; } [MenuItem("Tools/ShaderVariants")] public static void Execute() { if (window == null) window = (Statistic_ShaderVariants)GetWindow(typeof(Statistic_ShaderVariants)); window.minSize = new Vector2(300, 300); var tex = EditorGUIUtility.FindTexture("d_WelcomeScreen.AssetStoreLogo"); window.titleContent = new GUIContent("Searcher", tex); window.Show(); } private void OnGUI() { GUILayout.BeginVertical(); if (GUILayout.Button(new GUIContent("Scan", m_texPlay), GUILayout.Height(30))) { Scan(); } if (lst.Count > 0) { using (new GUILayout.HorizontalScope()) { GUILayout.Label($"Shader总数:{shaderNum}", GUILayout.Width(110), GUILayout.Height(30)); GUILayout.Label($"Shader变种数量:{variantNum}", GUILayout.Height(30)); } using (new GUILayout.HorizontalScope()) { GUILayout.Label("变重数量", GUILayout.Width(110), GUILayout.Height(30)); GUILayout.Label("Shader路径(点击可选中)", GUILayout.Height(30)); } using (new GUILayout.VerticalScope("box")) { using (var scrollView = new GUILayout.ScrollViewScope(m_scrollPos)) { m_scrollPos = scrollView.scrollPosition; foreach (var info in lst) { using (new GUILayout.HorizontalScope()) { GUILayout.Label(info.num.ToString(), GUILayout.Width(100), GUILayout.Height(30)); var tex = info.num <= 32 ? m_texRight : m_texWrong; if (GUILayout.Button(new GUIContent(info.name, tex), "label", GUILayout.Height(30))) { Selection.activeObject = AssetDatabase.LoadAssetAtPath<Shader>(info.name); } } } } } } GUILayout.EndVertical(); } private void Scan() { lst.Clear(); shaderNum = 0; variantNum = 0; Assembly asm = Assembly.GetAssembly(typeof(UnityEditor.SceneView)); System.Type shaderUtil = asm.GetType("UnityEditor.ShaderUtil"); MethodInfo method = shaderUtil.GetMethod("GetVariantCount", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); var shaderList = AssetDatabase.FindAssets("t:Shader", null); shaderNum = shaderList.Length; EditorUtility.DisplayProgressBar("Shader统计文件", "正在写入统计文件中...", 0f); int idx = 0; foreach (var str in shaderList) { EditorUtility.DisplayProgressBar("Shader统计文件", "正在写入统计文件中...", idx / shaderList.Length); var path = AssetDatabase.GUIDToAssetPath(str); Shader shader = AssetDatabase.LoadAssetAtPath(path, typeof(Shader)) as Shader; var variantCount = method.Invoke(null, new System.Object[] { shader, true }); int num = int.Parse(variantCount.ToString()); lst.Add(new ShaderVariantInfo() { name = path, num = num }); variantNum += num; ++idx; } EditorUtility.ClearProgressBar(); lst.Sort((a, b) => b.num.CompareTo(a.num)); } } }