• Unity查找功能编辑器扩展Searcher


    我的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
    }
  • 相关阅读:
    20200807日报
    20200806日报
    《大道至简》读书感悟
    20200805日报
    20200804日报
    20200803日报
    20200802日报
    vue中mounted内如何调完异步方法再渲染
    小程序画布识别iPhone11
    np.meshgrid() 生成网格坐标函数
  • 原文地址:https://www.cnblogs.com/CodeSnippet/p/8036472.html
Copyright © 2020-2023  润新知