UnityEditor:通过反射实现的Class过滤器编辑器

来源:互联网 发布:java简易订餐系统 编辑:程序博客网 时间:2024/06/07 02:17
之前因为策划有在Game运行模式时动态修改脚本,在退出后脚本参数保存的需求,用于在场景中动态地调整参数。研究了一下之前老外实现的一个插件PlayModePersist,也就是一个在运行模式下进行保存数据的插件。
PlayModePersist 这款插件不知道什么原因已经从Appstore下架了。有需要的同学可以自行下载。
通过阅读这款插件的源码,学到了两个比较有趣的实现:
1. 通过反射获取所有应用类,做成编辑器以供筛选。
2. 运行模式下,实时保存数据。

今天这篇文章就是学习第一个的方法。

首先,它完成后大概是这个样子的:


普通查找

模糊查找



关于编辑器的学习总结,由于本人很赖之前虽然一直想总结下,但是其实别人已经总结的很好啦,就一直搁置了。。。
想要学习的同学可以参考下面文章
拓展自定义编辑器窗口(EditorGUILayout类)
http://www.cnblogs.com/caymanlu/p/5722549.html

上代码,注释了主要的功能模块

using System;using UnityEngine;using UnityEditor;using System.Reflection;using System.Collections.Generic;using System.Text.RegularExpressions; public class FilterTestWindow : EditorWindow{    private const string mDefaultKey = "Filter_Test";    private static List<FilterTestObject> mDefaultTypeList;    private static List<string> mSelectedTypeList;     string mSearchPath = "";        //检索字段    Vector2 scrollPos;              //滚动条位置    bool isShowOnlyEnabled = false; //仅显示选中的类     [MenuItem("Window/Filter Test Settings")]    static void Init()    {        if (mSelectedTypeList == null)            LoadDefaults();        FilterTestWindow window = (FilterTestWindow)EditorWindow.GetWindow(typeof(FilterTestWindow), true, "Filter Test");        window.minSize = new Vector2(325, 300);   //限制最小尺寸        //window.maxSize = new Vector2(325, 800); //限制最大尺寸    }     //通过EditorPrefs的key 收集选中类型信息    static void LoadDefaults()    {        mSelectedTypeList = new List<string>();        string rawDefaults = EditorPrefs.GetString(mDefaultKey);        string[] classParts = rawDefaults.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);         foreach (string classPart in classParts)        {            mSelectedTypeList.Add(classPart.Trim());        }    }     public void OnEnable()    {        if (mDefaultTypeList == null)        {            mDefaultTypeList = new List<FilterTestObject>();            Assembly asm = typeof(Component).Assembly;            Dictionary<string, bool> tempTypeList = new Dictionary<string, bool>();            string tempTypeName;            string tempNamespace;            string[] words;             //加入选中类型  分离命名空间和类名            foreach (string defaultTypeName in mSelectedTypeList)            {                words = defaultTypeName.Split('.');                if (words.Length == 1)                {                    tempNamespace = "";                    tempTypeName = defaultTypeName;                }                else                {                    tempNamespace = words[0];                    tempTypeName = words[1];                }                mDefaultTypeList.Add(new FilterTestObject(tempNamespace, tempTypeName, true));                tempTypeList.Add(tempTypeName, true);            }             //加入UnityEngine默认类型            foreach (Type type in asm.GetTypes())            {                if (typeof(Component).IsAssignableFrom(type))                {                    if (type != typeof(Component) && type != typeof(Behaviour) && type != typeof(MonoBehaviour))                    {                        if (!tempTypeList.ContainsKey(type.Name))                        {                            mDefaultTypeList.Add(new FilterTestObject("UnityEngine", type.Name, false));                            tempTypeList.Add(type.Name, false);                        }                    }                }            }             //加入所有自定义类型            Assembly[] currDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies();            string asmPath;             foreach (Assembly currDomainAsm in currDomainAssemblies)            {                asmPath = currDomainAsm.CodeBase;                if (asmPath.EndsWith("Assembly-UnityScript.dll") || asmPath.EndsWith("Assembly-CSharp.dll"))                {                    foreach (System.Type type in currDomainAsm.GetTypes())                    {                        if (typeof(MonoBehaviour).IsAssignableFrom(type))                        {                            if (!tempTypeList.ContainsKey(type.Name))                            {                                mDefaultTypeList.Add(new FilterTestObject("", type.Name, false));                                tempTypeList.Add(type.Name, false);                            }                        }                    }                }            }             //按字母顺序排列            SortList();        }    }     private static void SortList()    {        FilterTestComparer comparer = new FilterTestComparer();         mDefaultTypeList.Sort(comparer);    }     //绘制窗口    public void OnGUI()    {        GUILayout.Label("Filter Test Window", EditorStyles.boldLabel);        EditorGUILayout.Space();        mSearchPath = EditorGUILayout.TextField(new GUIContent("Filter"), mSearchPath, GUILayout.Width(300.0f));        EditorGUILayout.Space();         //开始滚动条布局        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false, GUILayout.Width(300), GUILayout.Height(position.height - 140));        int listCount = 0;         //加入简易正则筛选测试        bool bRegexMode = false;        Regex regex = null;        string regexStr = "";        if (mSearchPath.StartsWith("*"))        {            bRegexMode = true;            regexStr = "\\w" + mSearchPath.Substring(1, mSearchPath.Length - 1).ToLower();            regex = new Regex(regexStr);        }         foreach (FilterTestObject testObj in mDefaultTypeList)        {            //正则测试条件            if (mSearchPath == "" || bRegexMode && regex.Match(testObj.TypeName.ToLower()).Success|| testObj.TypeName.ToLower().StartsWith(mSearchPath.ToLower()))            //if (mSearchPath == "" || autoPersistObj.TypeName.ToLower().StartsWith(mSearchPath.ToLower()))            {                if (!isShowOnlyEnabled || testObj.IsSelected)                {                    GUILayout.BeginHorizontal(GUILayout.Width(250));                    GUILayout.Label(testObj.TypeName, GUILayout.Width(200));                     if (!testObj.IsSelected)                    {                        if (GUILayout.Button("Add"))                        {                            AddDefault(testObj.GetFullClassName());                            testObj.IsSelected = true;                            if (EditorApplication.isPlaying || EditorApplication.isPaused)                            {                                //Do Something...For Extension                            }                        }                    }                    else                    {                        if (GUILayout.Button("Remove"))                        {                            RemoveDefault(testObj.GetFullClassName());                            testObj.IsSelected = false;                            if (EditorApplication.isPlaying || EditorApplication.isPaused)                            {                                //Do Something...For Extension                            }                        }                    }                    GUILayout.EndHorizontal();                    listCount++;                }            }        }         //筛选提示        if (listCount == 0)        {            if (isShowOnlyEnabled && mSearchPath == "")            {                GUILayout.Label("No Components Are Selected");            }            else            {                GUILayout.Label("Please Broaden Your Search");            }        }        EditorGUILayout.EndScrollView();        EditorGUILayout.Space();         EditorGUILayout.BeginHorizontal();        GUILayout.Label("Show Only Enabled");  //仅显示选中类        isShowOnlyEnabled = EditorGUILayout.Toggle(isShowOnlyEnabled, GUILayout.ExpandWidth(true));        EditorGUILayout.EndHorizontal();        EditorGUILayout.Space();         EditorGUILayout.BeginHorizontal();        if (mSelectedTypeList.Count > 0)        {            EditorGUILayout.Space();            if (GUILayout.Button("Remove All"))//移除所有选中            {                foreach (FilterTestObject obj in mDefaultTypeList)                {                    if (obj.IsSelected)                    {                        RemoveDefault(obj.GetFullClassName());                        obj.IsSelected = false;                    }                }            }        }        EditorGUILayout.Space();        if (GUILayout.Button("Print"))        //简易拓展功能 打印所有选中类型        {            foreach (FilterTestObject obj in mDefaultTypeList)            {                if (obj.IsSelected)                {                    Debug.Log(obj.GetFullClassName());                }            }        }        EditorGUILayout.Space();        EditorGUILayout.EndHorizontal();        EditorGUILayout.Space();    }     public static void AddDefault(string className)    {        if (!mSelectedTypeList.Contains(className))        {            mSelectedTypeList.Add(className);            SaveDefaults();        }    }     public static void RemoveDefault(string className)    {        if (mSelectedTypeList.Contains(className))        {            mSelectedTypeList.Remove(className);            SaveDefaults();        }    }     //保存信息到EditorPrefs    private static void SaveDefaults()    {        string defaultStr = string.Join("|", mSelectedTypeList.ToArray());        EditorPrefs.SetString(mDefaultKey, defaultStr);    }} public class FilterTestObject{    private string typeName;    private string namespaceStr;     private bool isSelected;    public bool IsSelected    {        get { return isSelected; }        set { isSelected = value; }    }     public FilterTestObject(string namespaceStr, string typeName, bool bSelected)    {        this.typeName = typeName;        this.namespaceStr = namespaceStr;        this.isSelected = bSelected;    }    public string TypeName    {        get { return typeName; }    }     public string GetFullClassName()    {        if (namespaceStr.Length > 0) return namespaceStr + "." + typeName;        else return typeName;    }} public class FilterTestComparer : IComparer<FilterTestObject>{    public int Compare(FilterTestObject x, FilterTestObject y)    {        if (x == null) return (y == null ? 0 : -1);        if (y == null) return 1;        return x.TypeName.CompareTo(y.TypeName);    }}

将以上脚本放在Editor文件夹下即可使用。



测试中用的是比较简单的正则做的模糊查找(其实只是蛋疼添加的功能),还有加入、移除按钮后的特殊处理大家可以自行扩展。

插件中的作用是,将选中类型注册到需要保存类型的List中,在结束运行模式后筛选的类型数据将会实时通过PropertyInfo、FieldInfo进行保存


在运行模式下保存数据的功能将在下篇文章补上 :)

已更新:

 Unity3D 如何在退出运行模式后保存修改数据


阅读全文
0 0
原创粉丝点击