Unity编辑器扩展

unity是一个强大的编辑器。 我们可以通过一些代码扩展它,达到提高工作效率的目的。

在开始写代码之前, 我们需要先知道一些前置知识。

  1. 命名空间。Unity的运行时和编辑器类分别存储在不同的Assemblies里:UnityEngine 和 UnityEditor。编写编辑器之前,需要 using UnityEditor
  2. 当想在编辑器中执行脚本时, 可以使用 attribute:[ExecuteInEditMode]通知编辑器, 被描述类的 OnGUI 和 Update 等函数在编辑模式也会被调用。
  3. 当代码在运行时和编辑器都需要执行时,可以使用 #if UNITY_EDITOR … #endif 宏来对编辑器代码做特殊处理。

本文主要介绍了以下几个方法:
- MenuItem
- AddComponentMenu
- ContextMenu
- ScriptableObject
- EditorWindow
- Editor
- ScriptableWizard

其中 MenuItem, AddComponentMenu, ContextMenu 并不会用到 UnityEditor 命名空间。

ScriptableObject, EditorWindow, Editor, ScriptableWizard 需要使用 UnityEditor 命名空间。


[MenuItem(“dir/name”)]:MenuItem属性允许您将菜单项添加到主菜单和 inspector context 菜单。

https://docs.unity3d.com/ScriptReference/MenuItem.html

  1. MenuItem必须定义子菜单, 如[MenuItem(“dir”)] 是不行的。
  2. MenuItem 属性必须写在一个静态方法之前;
using UnityEditor;
using UnityEngine;
public class t_MenuItem : MonoBehaviour {
    [MenuItem("MyMenu/Do Something")]
    static void DoSomething() {
        Debug.Log("Doing Something...");
    }

    [MenuItem("MyMenu/Log Selected Transform Name")]
    static void LogSelectedTransformName() {
        Debug.Log("Selected Transform is on " + Selection.activeTransform.gameObject.name + ".");
    }

    [MenuItem("MyMenu/Log Selected Transform Name", true)]
    static bool ValidateLogSelectedTransformName() {
        return Selection.activeTransform != null;
    }

    [MenuItem("MyMenu/Do Something with a Shortcut Key %g")]
    static void DoSomethingWithAShortcutKey() {
        Debug.Log("Doing something with a Shortcut Key...");
    }

}

效果todo1

效果todo2

效果todo3


AddComponentMenu:在组件菜单中加item

[AddComponentMenu(“UI/Image”, 11)]:AddComponentMenu属性允许您将脚本放置在“组件”菜单中的任何位置,而不仅仅是“组件 - >脚本”菜单中。

https://docs.unity3d.com/ScriptReference/AddComponentMenu.html

using UnityEngine;

[AddComponentMenu("Transform/Follow Transform")]
public class t_AddComponentMenu : MonoBehaviour {
}

效果todo1

效果todo2


ContextMenu:添加上下文命令

在Inspector窗口对应的附加脚本栏中,当用户选择上下文菜单,对应的函数就会被执行。这对于通过脚本来自动设置场景数据是非常有用的。这种函数必须是非静态函数。

https://docs.unity3d.com/ScriptReference/ContextMenu.html

using UnityEngine;

public class TestContext : MonoBehaviour {
    [ContextMenu("Test Context")]
    void DoSomething() {
        Debug.Log("david say Test Context");
    }
}

效果


ScriptableObject

ScriptableObject:

官方文档:https://docs.unity3d.com/ScriptReference/ScriptableObject.html

A class you can derive from if you want to create objects that don’t need to be attached to game objects.

如果要创建不需要附加到游戏对象的对象,那么就派生自这个类。

类似于 Menu 中的 GameObject

这里实现一个创建子节点的 MenuItem, 步骤如下:
1. 继承 ScriptableObject
2. 静态函数前加 [MenuItem(“dir/name”)]

代码如下:

using UnityEngine;
using UnityEditor;
using System.Collections;

public class Edi_ScriptableObject : ScriptableObject {
    [MenuItem("Dod/Add Child")]
    static void MenuAddChild() {
        Transform[] transforms = Selection.GetTransforms(SelectionMode.TopLevel | SelectionMode.OnlyUserModifiable);

        foreach (Transform transform in transforms) {
            GameObject newChild = new GameObject("child");
            newChild.transform.parent = transform;
        }
    }
}

效果如下:
todo

todo


EditorWindow:

EditorWindow 是命名空间 UnityEditor 下的, 继承自 ScriptableObject。

官方文档:https://docs.unity3d.com/ScriptReference/EditorWindow.html

通过继承这个类,来创建一个 editor 窗口。在unity界面, 你可以创建自定义的editor窗口, 他们可以是悬浮的, 也可以像标签页一样固定。

  • 优点:可以加入Unity的排版。
  • 缺点:容易处在其他窗口之后,看不见

编辑器窗口通常是使用一个菜单项打开。

这里创建一个自定义窗口, 步骤如下:
1. 继承自 EditorWindow, 类名就是你创建的窗口的名字。
2. 静态函数前加[MenuItem(“dir/name”)], 函数体内是创建窗口的函数。
3. OnGUI函数里写窗口结构

代码如下:

using UnityEngine;
using UnityEditor;

public class Edi_MyWindow : EditorWindow {
    string myString = "Hello World";
    bool groupEnabled;
    bool myBool = true;
    float myFloat = 1.23f;

    [MenuItem("Dod/Edi_MyWindow")]
    static void Init() {
        Edi_MyWindow window = (Edi_MyWindow)EditorWindow.GetWindow(typeof(Edi_MyWindow));
        window.Show();
    }

    void OnGUI() {
        // 标签
        GUILayout.Label("Base Settings", EditorStyles.boldLabel);
        // 填写框
        myString = EditorGUILayout.TextField("Text Field", myString);

        // 可选区域开始
        groupEnabled = EditorGUILayout.BeginToggleGroup("Optional Settings", groupEnabled);
        // 单选框
        myBool = EditorGUILayout.Toggle("Toggle", myBool);
        // 滑动条
        myFloat = EditorGUILayout.Slider("Slider", myFloat, -3, 3);
        EditorGUILayout.EndToggleGroup();
        // 可选区域结束
    }
}

效果图:
todo

todo


Editor:

Editor 是命名空间 UnityEditor 下的, 继承自 ScriptableObject。

官方文档:https://docs.unity3d.com/ScriptReference/Editor.html

派生自定义编辑器的基类。 使用它为您的对象创建自己的定制的 inspectors 和 editor。

看下来自官方文档的例子:

using UnityEngine;
using System.Collections;

// This is not an editor script.
public class MyPlayer : MonoBehaviour {
    public int armor = 75;
    public int damage = 25;
    public GameObject gun;

    void Update() {
        // Update logic here...
    }
}

将 MyPlayer 脚本挂到一个空的 GameObject 上。
效果图如下:

todo

下面创建我们的自定义面板, 步骤如下:
1. 继承自 Editor
2. [CustomEditor(typeof(MyPlayer))]

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(MyPlayer))]
public class Edi_MyEdi : Editor {

    public override void OnInspectorGUI() {
        MyPlayer mp = (MyPlayer)target;

        mp.damage = EditorGUILayout.IntSlider("Damage", mp.damage, 0, 100);
        ProgressBar(mp.damage / 100.0f, "Damage");

        mp.armor = EditorGUILayout.IntSlider("Armor", mp.armor, 0, 100);
        ProgressBar(mp.armor / 100.0f, "Armor");

        bool allowSceneObjects = !EditorUtility.IsPersistent(target);
        mp.gun = (GameObject)EditorGUILayout.ObjectField("Gun Object", mp.gun, typeof(GameObject), allowSceneObjects);
    }

    void ProgressBar(float value, string label) {
        Rect rect = GUILayoutUtility.GetRect(18, 18, "TextField");
        EditorGUI.ProgressBar(rect, value, label);
        EditorGUILayout.Space();
    }
}

效果图如下:


ScriptableWizard:

ScriptableWizard 是命名空间 UnityEditor 下的, 继承自 ScriptableObject。

官方文档:https://docs.unity3d.com/ScriptReference/ScriptableWizard.html

从这个类派生出来创建一个编辑器向导。

主要用来做向导。有2个按钮,一个是Create,另一个是Other。
OnWizardUpdate
OnWizardCreate
OnWizardOtherButton

  • 优点:有定制功能,并且永远处于最上层显示
    如果有EditorWindow想要最上层显示的话, 把继承EditorWindow直接换成ScriptableWizard,把
    MyWinClass window = (MyWinClass)EditorWindow.GetWindow (typeof(MyWinClass));
    替换为
    ScriptableWizard.DisplayWizard< MyWinClass > (“Title”);
    即可。
// Creates a simple wizard that lets you create a Light GameObject
// or if the user clicks in "Apply", it will set the color of the currently
// object selected to red

using UnityEditor;
using UnityEngine;

public class WizardCreateLight : ScriptableWizard
{
    public float range = 500;
    public Color color = Color.red;

    [MenuItem("GameObject/Create Light Wizard")]
    static void CreateWizard()
    {
        ScriptableWizard.DisplayWizard<WizardCreateLight>("Create Light", "Create", "Apply");
        //If you don't want to use the secondary button simply leave it out:
        //ScriptableWizard.DisplayWizard<WizardCreateLight>("Create Light", "Create");
    }

    void OnWizardCreate()
    {
        GameObject go = new GameObject("New Light");
        Light lt = go.AddComponent<Light>();
        lt.range = range;
        lt.color = color;
    }

    void OnWizardUpdate()
    {
        helpString = "Please set the color of the light!";
    }

    // When the user pressed the "Apply" button OnWizardOtherButton is called.
    void OnWizardOtherButton()
    {
        if (Selection.activeTransform != null)
        {
            Light lt = Selection.activeTransform.GetComponent<Light>();

            if (lt != null)
            {
                lt.color = Color.red;
            }
        }
    }
}


参考文档:

【风宇冲】Unity3d编辑器拓展

【Unity】ScriptableObject的介绍

Unity编辑器扩展-菜单项


如有错误,欢迎指出。

email:dxmdxm1992#gmail.com

blog: http://blog.csdn.net/david_dai_1108

猜你喜欢

转载自blog.csdn.net/david_dai_1108/article/details/72809615