您的位置:首页 > 移动开发 > Unity3D

Unity扩展Editor菜单:提供一个统一的接口,来让策划调节prefab里相关脚本的数值

2017-06-29 16:24 585 查看
扩展Editor的目的:提供一个统一的接口,来让策划调节prefab里相关脚本的数值,避免策划直接调整数值时不小心修改了prefab里其他组件的设置 

思路: 
1、创建1个EditorWindow 
2、Project里选择相应的目录或者文件,处理得到目录Directory 
3、获取Directory下所有的prefab文件,得到一个文件名数组 
4、给出文件名的下拉选择框,根据选择得到index,进而可以得到文件在Assets里的Path 
5、根据Path加载Asset,获取其所有的MonoBehaviour组件,给出下拉选择框 
6、显示所选择的MonoBehaviour的所有public的属性 

using UnityEngine;

using UnityEditor;

using System;

using System.Collections;

using System.Collections.Generic;

using System.Reflection;

public class ExposeProperties

{

    public static void Expose(System.Object obj)

    {

        Expose(GetProperties(obj));

    }

    public static void Expose(ScriptProperty[] properties)

    {

        GUILayoutOption[] emptyOptions = new GUILayoutOption[0];

        EditorGUILayout.BeginVertical(emptyOptions);

        foreach (ScriptProperty property in properties)

        {

            EditorGUILayout.BeginHorizontal();

            switch (property.Type)

            {

                case SerializedPropertyType.Integer:

                    property.SetValue(EditorGUILayout.IntField(property.Name, (int)property.GetValue(), emptyOptions));

                    break;

                case SerializedPropertyType.Float:

                    property.SetValue(EditorGUILayout.FloatField(property.Name, (float)property.GetValue(), emptyOptions));

                    break;

                case SerializedPropertyType.Boolean:

                    property.SetValue(EditorGUILayout.Toggle(property.Name, (bool)property.GetValue(), emptyOptions));

                    break;

                case SerializedPropertyType.String:

                    property.SetValue(EditorGUILayout.TextField(property.Name, (String)property.GetValue(), emptyOptions));

                    break;

                case SerializedPropertyType.Vector2:

                    property.SetValue(EditorGUILayout.Vector2Field(property.Name, (Vector2)property.GetValue(), emptyOptions));

                    break;

                case SerializedPropertyType.Vector3:

                    property.SetValue(EditorGUILayout.Vector3Field(property.Name, (Vector3)property.GetValue(), emptyOptions));

                    break;

                case SerializedPropertyType.Enum:

                    property.SetValue(EditorGUILayout.EnumPopup(property.Name, (Enum)property.GetValue(), emptyOptions));

                    break;

                default:

                    break;

            }

            EditorGUILayout.EndHorizontal();

        }

        EditorGUILayout.EndHorizontal();

    }

    public static ScriptProperty[] GetProperties(System.Object obj)

    {

        List<ScriptProperty> properties = new List<ScriptProperty>();

        FieldInfo[] infos = obj.GetType().GetFields();

        foreach (FieldInfo info in infos)

        {

            SerializedPropertyType type = SerializedPropertyType.Integer;

            if (ScriptProperty.GetPropertyType(info, out type))

            {

                ScriptProperty property = new ScriptProperty(obj, info, type);

                properties.Add(property);

            }

        }

        return properties.ToArray();

    }

}

public class ScriptProperty

{

    System.Object m_Instance;

    FieldInfo m_Info;

    SerializedPropertyType m_Type;

    public SerializedPropertyType Type

    {

        get { return m_Type; }

    }

    public string Name

    {

        get { return ObjectNames.NicifyVariableName(m_Info.Name); }

    }

    public ScriptProperty(System.Object instance, FieldInfo info, SerializedPropertyType propertyType)

    {

        m_Instance = instance;

        m_Info = info;

        m_Type = propertyType;

    }

    public System.Object GetValue()

    {

        return m_Info.GetValue(m_Instance);

    }

    public void SetValue(System.Object obj)

    {

        m_Info.SetValue(m_Instance, obj);

    }

    public static bool GetPropertyType(FieldInfo info, out SerializedPropertyType propertyType)

    {

        propertyType = SerializedPropertyType.Generic;

        Type type = info.FieldType;

        if (type == typeof(int))

        {

            propertyType = SerializedPropertyType.Integer;

            return true;

        }

        if (type == typeof(float))

        {

            propertyType = SerializedPropertyType.Float;

            return true;

        }

        if (type == typeof(bool))

        {

            propertyType = SerializedPropertyType.Boolean;

            return true;

        }

        if (type == typeof(string))

        {

            propertyType = SerializedPropertyType.String;

            return true;

        }

        if (type == typeof(Vector2))

        {

            propertyType = SerializedPropertyType.Vector2;

            return true;

        }

        if (type == typeof(Vector3))

        {

            propertyType = SerializedPropertyType.Vector3;

            return true;

        }

        if (type.IsEnum)

        {

            propertyType = SerializedPropertyType.Enum;

            return true;

        }

        return false;

    }

}

using UnityEngine;

using UnityEditor;

using System.IO;

using System.Collections;

using System.Collections.Generic;

using System.Reflection;

public class PrefabEditor : EditorWindow

{

    [MenuItem("Prefab/Editor")]

    static void OpenEditor()

    {

        EditorWindow.GetWindow(typeof(PrefabEditor));

    }

    private static string extension = ".prefab";

    private static string assetTopFolder = "Assets/";

    private string destinationPath;

    private string[] childrenNames;

    private int childIndex;

    private int componentIndex;

    void OnGUI()

    {

        DrawSeparator();

        string oldPath = destinationPath;           // keep old path for comparision purpose

        // process selection in project

        string selectionPath = GetSelectionPath();

        string selectionName = Path.GetFileNameWithoutExtension(selectionPath);

        destinationPath = GetDirectory(selectionPath);

        if (destinationPath == null)

        {

            EditorGUILayout.LabelField("You must select a folder first");

            return;

        }

        bool isDirectory = false;                   // original selection is a directory or file

        if (destinationPath == selectionPath)

            isDirectory = true;

        destinationPath = destinationPath.Substring(assetTopFolder.Length);

        EditorGUILayout.LabelField("Directory: ", destinationPath);

        if (destinationPath != oldPath)

        {

            childrenNames = GetFiles(destinationPath, "*" + extension, true);

            childIndex = GetSelectionIndex(selectionName, childrenNames);

            componentIndex = 0;

        }

        else if (!isDirectory)

        {

            childIndex = GetSelectionIndex(selectionName, childrenNames);

        }

        if (childrenNames.Length > 0)

        {

            int lastIndex = childIndex;             // keep old index to check if we switch to another one, which reset componentIndex

            childIndex = EditorGUILayout.Popup("Choose Asset: ", childIndex, childrenNames);

            if (childIndex != lastIndex)

            {

                componentIndex = 0;

            }

            string assetPath = Path.Combine(assetTopFolder + destinationPath, childrenNames[childIndex] + extension);

            GameObject asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Object)) as GameObject;

            // asset must not be null, since the assetPath is always a reasonable path, so i don't test it for null

            Selection.activeObject = asset;     // make asset as active object

            ExposeAsset(asset);

        }

        else

        {

            EditorGUILayout.LabelField("No prefab found!");

        }

    }

    void OnSelectionChange()

    {

        Repaint();

    }

    string GetSelectionPath()

    {

        string path = null;

        Object[] selections = Selection.GetFiltered(typeof(Object), SelectionMode.Assets);

        if (selections != null && selections.Length > 0)

            path = AssetDatabase.GetAssetPath(selections[0]);

        return path;

    }

    string GetDirectory(string path)

    {

        string directory = path;

        if (directory != null && Path.GetExtension(directory) != "")

        {

            directory = Path.GetDirectoryName(directory);

        }

        return directory;

    }

    int GetSelectionIndex(string selectionName, string[] names)

    {

        int index = 0;

        foreach (string name in names)

        {

            if (selectionName == name)

            {

                return index;

            }

            index++;

        }

        return 0;   // if not found, return 0

    }

    string[] GetFiles(string relativePath, string pattern, bool topOnly = true)

    {

        string[] names = null;

        SearchOption option = topOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories;

        string path = Path.Combine(Application.dataPath, relativePath);

        try

        {

            string[] files = Directory.GetFiles(path, pattern, option);

            names = new string[files.Length];

            for (int i = 0; i < files.Length; ++i)

                names[i]= Path.GetFileNameWithoutExtension(files[i]);

        }

        catch (DirectoryNotFoundException e)

        {

            Debug.LogError(e);

        }

        return names;

    }

    void ExposeAsset(GameObject asset)

    {

        MonoBehaviour[] scripts = asset.GetComponents<MonoBehaviour>();

        if (scripts != null && scripts.Length > 0)

        {

            List<string> names = new List<string>();

            foreach (MonoBehaviour scr in scripts)

            {

                string scriptName = ObjectNames.NicifyVariableName(scr.GetType().ToString());

                names.Add(scriptName);

            }

            componentIndex = EditorGUILayout.Popup("Choose Component: ", componentIndex, names.ToArray());

            MonoBehaviour script = scripts[componentIndex];

            DrawSeparator();

            ExposeProperties.Expose(script);

            GUILayout.Space(20f);

            if (GUILayout.Button("Save"))

            {

                EditorUtility.SetDirty(script);     // very important: save script component to disk

            }

        }

    }

    void DrawSeparator()

    {

        GUILayout.Space(12f);

        if (Event.current.type == EventType.Repaint)

        {

            Texture2D tex = EditorGUIUtility.whiteTexture;

            Rect rect = GUILayoutUtility.GetLastRect();

            GUI.color = new Color(0f, 0f, 0f, 0.25f);

            GUI.DrawTexture(new Rect(0f, rect.yMin + 6f, Screen.width, 4f), tex);

            GUI.DrawTexture(new Rect(0f, rect.yMin + 6f, Screen.width, 1f), tex);

            GUI.DrawTexture(new Rect(0f, rect.yMin + 9f, Screen.width, 1f), tex);

            GUI.color = Color.white;

        }

    }

}

注意:两个脚本必须同时放在Editor文件夹下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐