我的Github:https://github.com/LanslotChung/Unity3d-Editor-Extensions
专门在Github上记录我写的一些编辑器扩展工具,这是Searcher的源码
///作者:Lanslot Chung /// QQ:1935941005 /// EMail:exlanslotchung@gmail.com /// 如有错漏或新的想法,欢迎联系本人一起探讨 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; public class Searcher:EditorWindow{ #region Menu [MenuItem("Tools/Searcher %f")] static void ShowWindow(){ var searcher = EditorWindow.GetWindow<Searcher>(true); searcher.titleContent = new GUIContent("Seacher"); searcher.Show(); } #endregion //采用反射的方式避免了硬编码 //你可以随意添加更多的搜索方式,只需在脚本添加实现一个名为: //DisplayAllGameObjectsBy+搜索方式的方法即可 private enum Mode{ Name,Type,FieldName,FieldValue,Tag,Layer } private Mode currentMode = Mode.Name; private string searchText = string.Empty; private List<GameObject> searchedGameObjects = new List<GameObject>(); private Vector2 scrollPosition; void OnGUI(){ EditorGUILayout.LabelField(new GUIContent("Keyword:"),EditorStyles.boldLabel); searchText = SearchField(searchText); //if(string.IsNullOrEmpty(searchText.Trim())) return; EditorGUILayout.LabelField(new GUIContent("Search By:"),EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(GUILayout.Width(this.position.width - 5)); for(int i = 0;i < GetEnumCount(typeof(Mode));i++){ string label = GetEnumItemName(typeof(Mode),i); GUI.backgroundColor = Color.white; if((int)currentMode == i) GUI.backgroundColor = Color.green; if(GUILayout.Button(new GUIContent(label))){ currentMode = (Mode)i; searchedGameObjects.Clear(); } } EditorGUILayout.EndHorizontal(); GUI.backgroundColor = Color.white; if(GUILayout.Button(new GUIContent("Done"))){ if(!string.IsNullOrEmpty(searchText)){ scrollPosition = Vector2.zero; InvokeMethodByName(typeof(Searcher),"DisplayAllGameObjectBy" + currentMode.ToString(),new object[]{searchText}); } } scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); if(searchedGameObjects != null){ foreach(var item in searchedGameObjects){ if(item == null) continue; GUI.backgroundColor = Color.white; if(Selection.activeObject == item) GUI.backgroundColor = Color.green; if(GUILayout.Button(new GUIContent(item.name))){ if(item == null) continue; EditorGUIUtility.PingObject(item); Selection.activeObject = item; } } } EditorGUILayout.EndScrollView(); } private void DisplayAllGameObjectByName(string name){ List<GameObject> allGameObjects = GetAllSceneObjectsWithInactive(); searchedGameObjects = allGameObjects.Where(go => go.name.ToLower().Contains(name.ToLower())).OrderBy(go => go.name).ToList(); } private void DisplayAllGameObjectByType(string type){ List<GameObject> allGameObjects = GetAllSceneObjectsWithInactive(); searchedGameObjects = allGameObjects.Where(go => go.GetComponents<Component>().Where(cp => cp.GetType().ToString().ToLower().Contains(type)).Count() > 0 ).OrderBy(go => go.name).ToList(); } //这个方法一直很难写,始终获取不到Unity自带的Component的字段名,有好的方法可以通知我 //思路:获取所有Component,取出所有的Type,并且去重,然后逐个检查Type是否包含搜索内容 //只要包含了,就在所有问题中搜索Attach了这个Type的物体 private void DisplayAllGameObjectByFieldName(string fieldName){ List<GameObject> allGameObjects = GetAllSceneObjectsWithInactive(); List<System.Type> components = allGameObjects.SelectMany(go => go.GetComponents<Component>()).Select(com => com.GetType()).Distinct().ToList(); components = components.Where(com =>{ var fields = com.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).ToList(); if(fields == null || fields.Count <= 0) return false; return fields.Select(fi => fi.Name.ToLower()).Contains(fieldName.ToLower()); }).ToList(); searchedGameObjects = allGameObjects.Where(go => go.GetComponents<Component>().Select(com => com.GetType()).Intersect(components).Count() > 0).ToList(); } //同上一个方法,获取不到Unity自带的Component的字段 //思路:获取所有的Component后,逐个获取Component的所有字段,判断存在字段木有,有的话对比 //字段的值是否包含搜索内容,但是要记得去掉括号里的类型值,比如名为GameObject的物体会和类型 //的GameObject重叠,导致搜索错误 private void DisplayAllGameObjectByFieldValue(string fieldValue){ List<GameObject> allGameObjects = GetAllSceneObjectsWithInactive(); List<Component> components = allGameObjects.SelectMany(go => go.GetComponents<Component>()).ToList(); searchedGameObjects = components.Where(com => { var fields = com.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public).ToList(); if(fields == null || fields.Count <= 0) return false; return fields.Where(fi => { var value = fi.GetValue(com); if(value == null) return false; var valueName = value.ToString().ToLower(); //不会写正则表达式 var reg = new Regex(@"(([^)]*))").Match(valueName); if(reg.Success){ var valueType = reg.Result("$1"); valueName = valueName.Replace("(" + valueType + ")",""); } return valueName.Contains(fieldValue.ToLower()); }).Count() > 0; }).Select(com => com.gameObject).ToList(); } private void DisplayAllGameObjectByTag(string tag){ List<GameObject> allGameObjects = GetAllSceneObjectsWithInactive(); searchedGameObjects = allGameObjects.Where(go => go.tag.ToLower().Contains(tag.ToLower())).OrderBy(go => go.name).ToList(); } private void DisplayAllGameObjectByLayer(string layer){ List<GameObject> allGameObjects = GetAllSceneObjectsWithInactive(); var possibleLayer = GetAllLayers().Where(ly => ly.ToLower().Contains(layer)).ToList(); searchedGameObjects = allGameObjects.Where(go => possibleLayer.Contains(LayerMask.LayerToName(go.layer))).OrderBy(go => go.name).ToList(); } #region Util //很气,Unity把这个控件给隐藏起来了 private string SearchField(string value, params GUILayoutOption[] options) { MethodInfo info = typeof(EditorGUILayout).GetMethod("ToolbarSearchField", BindingFlags.NonPublic | BindingFlags.Static, null, new System.Type[] { typeof(string), typeof(GUILayoutOption[]) }, null); if (info != null) { value = (string)info.Invoke(null, new object[] { value, options }); } return value; } //获取枚举类型的子项数量,用于动态UI的创建 private int GetEnumCount(System.Type enumType){ return System.Enum.GetNames(enumType).GetLength(0); } //获取枚举类型的名称,结合反射用于动态增加搜索方式及UI private string GetEnumItemName(System.Type enumType,int itemIndex){ return System.Enum.GetName(enumType,itemIndex); } //用于获取所有Hierarchy中的物体,包括被禁用的物体 private List<GameObject> GetAllSceneObjectsWithInactive() { var allTransforms = Resources.FindObjectsOfTypeAll(typeof(Transform)); var previousSelection = Selection.objects; Selection.objects = allTransforms.Cast<Transform>() .Where(x => x != null ) .Select(x => x.gameObject) //如果你只想获取所有在Hierarchy中被禁用的物体,反注释下面代码 //.Where(x => x != null && !x.activeInHierarchy) .Cast<UnityEngine.Object>().ToArray(); var selectedTransforms = Selection.GetTransforms( SelectionMode.Editable | SelectionMode.ExcludePrefab); Selection.objects = previousSelection; return selectedTransforms.Select(tr =>tr.gameObject).ToList(); } //利用反射调用新增的搜索方法 private void InvokeMethodByName(System.Type type,string methodName,object[] value){ type.GetMethod(methodName,BindingFlags.NonPublic | BindingFlags.Instance) .Invoke(this,value); } //获取所有的Layer private List<string> GetAllLayers(){ List<string> layers = new List<string>(); for(int i = 0;i <= 31;i++){ var layer = LayerMask.LayerToName(i); if(layer.Length > 0) layers.Add(layer); } return layers; } #endregion }