Unity用户手册-EditorWindow

Unity Editor扩展概览

​ unity editor是一个通用的编辑器,提供了unity内部对象的创建,预览,编辑的功能及可视化界面。但对于特定类型的游戏开发可能还不能完全满足需求,还要根据程序,策划和美术的需求来进行扩展。常用的一些扩展包括打包界面,特定游戏对象的编辑界面,技能编辑器界面,自定义的场景编辑界面,美术资源导入批量设置等等。unity提供了丰富的接口来帮助开发者定制需求的功能。

​ 用于扩展editor的类需要放到名字为“Editor"的文件夹中,这个文件夹可以直接放到”Assets“文件夹下,也可以是项目目录任何文件夹下的子文件夹,比如”Assets/BigWorld/Editor"。

几种类型的扩展

​ unity提供了由简单到复制的多种编辑器扩展功能,下面给大家进行介绍常用的4种。

扩展工具栏菜单

​ 使用MenuItem特性扩展工具栏菜单。此扩展方法可以单独使用执行某些功能,也可以和其他窗口扩展功能一起使用,打开其他窗口。

using UnityEngine;
using System.Collections;
using UnityEditor;

public class ArtResChecker
{

    [MenuItem("ArtResChecker/CheckArtRes")]
    static public void ATestCheckArtResFunction()
    {
        CheckTextures();
          CheckMeshes();
          ...
    }
}

​ 代码1-1

​ 代码1-1是一个简单的示例。使用"MenuItem"需要引入"UnityEditor"命名空间。这样会在菜单栏中出现"ArtResChecker"菜单,点击下拉菜单中的"CheckArtRes"项,会执行”ATestCheckArtResFunction"函数。

​ 也可以扩展在已有的菜单中进行扩展,如代码1-2所示在“GameObject"菜单中增加了一项"AddChild"。

using UnityEngine;
using System.Collections;
using UnityEditor;

public class ArtResChecker
{
    [MenuItem("GameObject/AddChild")]
    static void ATestAddChildFunction()
    {
        Transform[] transforms = Selection.GetTransforms(SelectionMode.Unfiltered);
        foreach(var tf in transforms)
        {
            GameObject newGo = new GameObject("_Child");
            newGo.transform.parent = tf;
        }
    }
}

​ 代码1-2

​ 这个扩展脚本从菜单的“GameObject->Add Child”启动,功能是给Hierarchy窗口中选中的对GameObject添加一个名字为“_Child”的子GameObject,这样可以免去从Hierarchy窗口的根节点拖拽新创建的GameObject到当前选中节点的麻烦,因为在Unity3D编辑器中,创建一个EmptyObject会在Hierarchy窗口的根节点出现,无论当前选中的节点对象是哪个。

使用ScriptableWizard类进行扩展

​ unity提供的一个编辑器向导窗口扩展模板,继承这个类并重写里面的几个消息响应函数就可以快速创建一个编辑器窗口类。通过ScriptableWizard.DisplayWizard函数可以快速创建这个向导窗口。

​ 这个向导窗口只支持小于或等于两个按钮的定制(即提供的消息响应函数只有两个按钮的)。显示的按钮名字通过ScriptableWizard.DisplayWizard函数传入。下面介绍API中的消息响应函数:

  • OnWizardCreate 两个按钮事件中的一个,当传入ScriptableWizard.DisplayWizard函数中"createButtonName"参数对应的按钮被点击时调用。
  • OnWizardOtherButton 两个按钮事件中的一个,当传入ScriptableWizard.DisplayWizard函数中"otherButtonName"参数对应的按钮被点击时调用。
  • OnWizardUpdate 当向导窗口打开时或者用户改变窗口内容时都会被调用。一般会在这里显示帮助文字和进行内容有效性验证。也可以动态改变按钮状态。

还有一个可能被复写的函数是DrawWizardGUI当向导窗口需要更新用户界面时会被调用来绘制内容。

下面看一个使用ScriptableWizard类进行扩展的例子:

// 当点击"Info"按钮时显示两个对象的距离,当点击"Finish!"按钮时关闭窗口
using UnityEngine;
using UnityEditor;

public class ScriptableWizardOnWizardOtherButton : ScriptableWizard
{
    public Transform firstObject = null;
    public Transform secondObject = null;

    [MenuItem("Example/Show OnWizardOtherButton Usage")]
    static void CreateWindow()
    {
        ScriptableWizard.DisplayWizard("Click info to know the distance between the objects",
            typeof(ScriptableWizardOnWizardOtherButton), "Finish!", "Info");
    }

    void OnWizardUpdate()
    {
        if (firstObject == null || secondObject == null)
        {
            isValid = false;
            errorString = "Select the objects you want to measure";
        }
        else
        {
            isValid = true;
            errorString = "";
        }
    }

    // Called when you press the "Info" button.
    void OnWizardOtherButton()
    {
        float distanceObjs = Vector3.Distance(firstObject.position, secondObject.position);
        EditorUtility.DisplayDialog(
            "The distance between the objects is: " + distanceObjs + " Units",
            "",
            "Ok");
    }

    // Called when you press the "Finish!" button.
    void OnWizardCreate()
    {
    }
}

​ 代码1-3

运行时窗口如图1-1所示:

​ 图1-1

使用Editor Windows类进行扩展

​ 完全自定义窗口,根据需求定义窗口内容和布局。使用时继承EditorWindow类,重写“OnGUI”函数。例子如代码1-4

using UnityEngine;
using UnityEditor;

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

    // Add menu named "My Window" to the Window menu
    [MenuItem("Window/My Window")]
    static void Init()
    {
        // Get existing open window or if none, make a new one:
        MyWindow window = (MyWindow)EditorWindow.GetWindow(typeof(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();
    }
}

​ 代码1-4

窗口打开是如图1-2所示:

​ 图1-2

扩展自定义组件的Inspector窗口

​ 自己写的继承于"MonoBehaviour"的类,在Inspector窗口中有默认的显示方式,但有些情况下不直观,也无法满足编辑的需求,需要显示上进一步。这是可以继承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...
    }
}

​ 代码1-5

​ 比如代码1-5所示定义了一个组件,其显示方式默认如图1-3所示,但如果想要显示如果1-4所示就要对其进行扩展。如代码1-6所示

​ 图1-3

​ 图1-4

using UnityEditor;
using UnityEngine;
using System.Collections;

// Custom Editor using SerializedProperties.
// Automatic handling of multi-object editing, undo, and prefab overrides.
[CustomEditor(typeof(MyPlayer))]
[CanEditMultipleObjects]
public class MyPlayerEditor : Editor
{
    SerializedProperty damageProp;
    SerializedProperty armorProp;
    SerializedProperty gunProp;

    void OnEnable()
    {
        // Setup the SerializedProperties.
        damageProp = serializedObject.FindProperty("damage");
        armorProp = serializedObject.FindProperty("armor");
        gunProp = serializedObject.FindProperty("gun");
    }

    public override void OnInspectorGUI()
    {
        // Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
        serializedObject.Update();

        // Show the custom GUI controls.
        EditorGUILayout.IntSlider(damageProp, 0, 100, new GUIContent("Damage"));

        // Only show the damage progress bar if all the objects have the same damage value:
        if (!damageProp.hasMultipleDifferentValues)
            ProgressBar(damageProp.intValue / 100.0f, "Damage");

        EditorGUILayout.IntSlider(armorProp, 0, 100, new GUIContent("Armor"));

        // Only show the armor progress bar if all the objects have the same armor value:
        if (!armorProp.hasMultipleDifferentValues)
            ProgressBar(armorProp.intValue / 100.0f, "Armor");

        EditorGUILayout.PropertyField(gunProp, new GUIContent("Gun Object"));

        // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
        serializedObject.ApplyModifiedProperties();
    }

    // Custom GUILayout progress bar.
    void ProgressBar(float value, string label)
    {
        // Get a rect for the progress bar using the same margins as a textfield:
        Rect rect = GUILayoutUtility.GetRect(18, 18, "TextField");
        EditorGUI.ProgressBar(rect, value, label);
        EditorGUILayout.Space();
    }
}

​ 代码1-6

​ 使用CustomEditor特性把继承于Editor的类绑定到自己定义的组件类上。并重写"OnInspectorGUI"函数。如果需要自动处理多个对象的编辑,undo和prefab的覆盖,可以用SerializedObjectSerializedProperty来关联原来类中的要进行编辑的成员。如果不需要上面说的自动处理功能也可以不用关联而直接用自定义组件中的成员变量。

​ 如果需要在"Scene"视图中显示相应内容,需要重写OnSceneGUI。可以参考Unity Manual Custom Editors中“Scene View Additions”。

​ 如果组件中用到了自定义的C#类,也可以自定义其在组件中的显示方式,这时就用到了Property Drawers。具体使用方法也可以参考Unity Manual Property Drawers

常用布局API

​ 在上面的介绍中介绍了几种扩展编辑器的方法,有的有窗口显示,有的没有。在有窗口显示的扩展方法中,又要如何定义自己的窗口布局呢?下面介绍两个常用的类:EditorGUIEditorGUILayout类。EditorGUILayout类是自动布局的EditorGUI类。EditorGUI类的API都需要传入Rect参数来定义控件的显示范围,EditorGUILayout类会根据样式来自动对齐控件。具体的API请自行查阅unity文档,这里汇总了一些控件的API和其功能。

其他编辑器API

​ 上面介绍了编辑器如何扩展,下面介绍在编辑器扩展过程中经常会用到的一些类。

​ 我们在做编辑器时常用到"Undo"和"Redo"功能。Undo类提供了给特定对象注册"undo"操作。

​ unity中的shader都有自己的默认显示界面,如果想自定义shader的显示界面,可以继承ShaderGUI并重写"OnGUI"函数。具体用法详见ShaderGUI

​ Prefab是unity中经常用到的资源,用PrefabUtility可以方便的对其进行创建,修改及其他常用操作。

​ 编辑器中也常对场景进行操作,EditorSceneManager提供了常用的打开,关闭,保存,设置成未保存状态,合并场景等一系列对场景的操作。

​ 当想获得当前选中对象时可以用Selection

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值