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
}

 

转载于:https://www.cnblogs.com/CodeSnippet/p/8036472.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值