UnityEditor编辑器扩展代码实现Project搜索的实现功能和切换Component等

Posted avi9111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UnityEditor编辑器扩展代码实现Project搜索的实现功能和切换Component等相关的知识,希望对你有一定的参考价值。

反射实现切换Gameobjecect-Comp

之前介绍过Kinematic Character Controller这个插件

这个插件很容易和另外一个插件混淆,两个作者头像比较相像,而且这个插件的作者不太喜欢露脸(他现在做Dot-CharacterControl去了),几乎网上找到的都是另一个CharacterController插件

但其实这个控件例子不少的,都是走,跑和跳等例子。

而且例子内代码结构是:多个例子场景,则多个命名空间 ,每个命名空间内一个MyController(同名)

整个Kinematic Character Controller,几乎有十几个MyController

咋一看,怎么不使用继承,不太面向对象的感觉,太不专业;但实际上也和面向对象的使用无差

我们的需求来了:一个GameObject 包含一个逻辑 Mono,是否可以直接右键替换?

??切换的同时重点是如何把Mono的SerilizeField(一些关联go)也一并替换,这就是用到反射了

否则,就得一个个场景切换代码,比较麻烦

所以,如下1,原来的Kinematic逻辑,2.切换成自定义代码

整个Component的切换实现,就是利用了反射和Unity Editor的特性

封装了一下代码,可直接调用

//调用方法
//原目標,即使是接口,也可以通过.GetComponent()获取
var currController = go.GetComponent<ICharacterController>();//curr Instance
var motorSource = ReflectionHelper.GetCompField(go,currController.GetType().ToString(),"Motor");
Debug.LogError(motorSource);
static class ReflectionHelper

    /// <summary>
    /// 因为UnityEditor原因,这样获取会获取到,Editor库。。。。(如何 ReflectionHelper 类,不放在Editor,也是不会存在获取到Editor库问题)
    /// </summary>
    public static IEnumerable CreateAllInstancesOf<T>()
    
        return typeof(ReflectionHelper).Assembly.GetTypes() //获取当前类库下所有类型
            //.Where(t => typeof(T).IsAssignableFrom(t)) //获取间接或直接继承t的所有类型
            //.Where(t => !t.IsAbstract && t.IsClass) //获取非抽象类 排除接口继承
            //.Select(t => (T) Activator.CreateInstance(t)); //创造实例,并返回结果(项目需求,可删除)
            .Select(t=>t.FullName);
    
    
    /// <summary>
    ///  (直接指向,所以能获取Unity Runtime库)
    /// </summary>
    /// <returns></returns>
    public static IEnumerable GetAllClasses<T>()
    
       // var name = Selection.activeObject.name;//获取 Scene 中 GameObject
        System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
        var dict = System.IO.Path.GetDirectoryName(assembly.Location);
        assembly = System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(dict, "Assembly-CSharp.dll"));
        return assembly.GetTypes()
                .Where(t => typeof(T).IsAssignableFrom(t)) //获取间接或直接继承t的所有类型
                .Where(t => !t.IsAbstract && t.IsClass) //获取非抽象类 排除接口继承
                .Select(t=>t.FullName)
            ;
    
    /// <summary>
    /// 根据 type 获取go 的 component 的值
    /// </summary>
    /// <param name="go"></param>
    /// <param name="typeString">currController.GetType().ToString()</param>
    /// <param name="name">类的字段 名字</param>
    /// <returns></returns>
    public static object GetCompField(GameObject go, string typeString,string name)
    
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var defaultAssembly = assemblies.First(assembly => assembly.GetName().Name == "Assembly-CSharp");

        Type typSource = defaultAssembly.GetType(typeString);
        var currInstance = go.GetComponent(typSource);
        FieldInfo fieldSource = typSource.GetField(name);
        return fieldSource.GetValue(currInstance);
        
    

    public static bool SetCompField(object obj,object objValue, string typeString, string name)
    
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var defaultAssembly = assemblies.First(assembly => assembly.GetName().Name == "Assembly-CSharp");

        Type typSource = defaultAssembly.GetType(typeString);
        if (typSource == null) return false;
        FieldInfo fieldSource = typSource.GetField(name);
        fieldSource.SetValue(obj,objValue);
        return true;
    

Project View查找的代码实现

void Find(System.Type type)

    //step 1:find ref in assets
     
    //filter all GameObject from assets(so-called 'Prefab')
    var guids = AssetDatabase.FindAssets("t:GameObject");
     
    findResult = new List<string>();
     
    var tp = typeof(GameObject);
     
    foreach (var guid in guids)
    
        var path = AssetDatabase.GUIDToAssetPath(guid);
     
        //load Prefab
        var obj = AssetDatabase.LoadAssetAtPath(path, tp) as GameObject;
     
        //check whether prefab contains script with type 'type'
        if (obj != null)
        
            var cmp = obj.GetComponent(type);
            if (cmp == null)
            
                cmp = obj.GetComponentInChildren(type);
            
            if (cmp != null)
            
                findResult.Add(path);
            
        
    
     
    //step 2: find ref in scenes
     
    //save current scene
    string curScene = EditorApplication.currentScene;
    EditorApplication.SaveScene();
     
    //find all scenes from dataPath
    string[] scenes = Directory.GetFiles(Application.dataPath, "*.unity", SearchOption.AllDirectories);
     
    //iterates all scenes 
    foreach (var scene in scenes)
    
        EditorApplication.OpenScene(scene);
     
        //iterates all gameObjects
        foreach (GameObject obj in FindObjectsOfType<GameObject>())
        
            var cmp = obj.GetComponent(type);
            if (cmp == null)
            
                cmp = obj.GetComponentInChildren(type);
            
            if (cmp != null)
            
                findResult.Add(scene.Substring(Application.dataPath.Length) + "Assets:" + obj.name);
            
        
    
     
    //reopen current scene
    EditorApplication.OpenScene(curScene);
    Debug.Log ("finish");

参考:

C#通过反射获取类中的所有字段和属性 - 董川民 (dongchuanmin.com)

Unity-Find-Script-References 查找脚本的引用_子胤的博客-CSDN博客

以上是关于UnityEditor编辑器扩展代码实现Project搜索的实现功能和切换Component等的主要内容,如果未能解决你的问题,请参考以下文章

UnityEditor编辑器扩展自己实现了一遍SceneView的镜头移动

UnityEditor编辑器扩展开发-自定义Shader入门

UnityEditor编辑器扩展开发-自定义Shader入门

真UnityEditor编辑器扩展之dropdown和风琴式左右布局窗口

UnityEditor编辑器扩展快速导出包用的脚本剔除的代码分享

UnityEditor编辑器扩展-表格功能