作者最新更新

游戏开发工具

UnityEditor编辑之自定义窗口

676

94 次收藏2024-08-30 21:41:27发布

在Unity中我们常常扩展各种编辑窗口,创建自己的自定义编辑器窗口,这些窗口可以自由浮动,也可以作为选项卡停靠,就像 Unity 界面中的原生窗口一样。

在Unity中创建自定义窗口通常是通过UnityEditor的EditorWindow类来实现的。以下是创建一个简单自定义窗口的步骤和示例代码:

1.jpg

添加功能步骤:

1、创建一个继承自EditorWindow的新C#脚本。

2、添加一个静态方法来打开窗口。

3、在此方法中,使用GetWindow<自定义窗口类>()打开窗口,并重写窗口的OnGUI方法来定义窗口界面。

示例代码:

using UnityEngine;
using UnityEditor;
 
public class CustomWindow : EditorWindow
{
    // 添加窗口菜单项
    [MenuItem("MyWindow/Open Custom Window")]
    public static void OpenWindow()
    {
        // 打开窗口
        GetWindow<CustomWindow>("My Custom Window");
    }
 
    private void OnGUI()
    {
        // 在这里定义窗口界面
        GUILayout.Label("Hello, this is my custom window!");
        if (GUILayout.Button("Click Me"))
        {
            // 处理按钮点击事件
            Debug.Log("Button Clicked!");
        }
    }
}


将上述代码保存到项目中的Editor文件夹下的C#脚本文件中(如果没有此文件夹,请创建一个)。然后,您可以通过Unity编辑器顶部菜单的"MyWindow"路径来打开您的自定义窗口。每次运行Unity编辑器时,都会检查Editor文件夹中的脚本,并根据MenuItem属性添加相应的菜单项。


目标: 

1、了解一些属性的使用 

2、创建一个自定义窗口 


最终目标: 

利用学到的东西制作自己的工具(自定义的窗口、Inspector、菜单、插件等等)。


一、EditorWindow编辑器窗口类

1、在 Unity 中,EditorWindow 和 ScriptableWizard 都是用于创建自定义编辑器界面的类。

2、EditorWindow 是用于创建自定义编辑器窗口的类,可以包含自定义的 GUI 元素和逻辑。它通常用于创建工具窗口、面板或者其他自定义的编辑器界面。

3、ScriptableWizard 是用于创建向导式界面的类,可以帮助用户完成特定的任务。通常用于引导用户完成一系列步骤,例如创建新的资产、配置项目设置等。与 EditorWindow 相比,向导更加注重交互性和引导性,常用于流程化的操作步骤。


二、EditorWindow参数总览
常用参数描述
position窗口在屏幕空间中的理想位置。
titleContent用于绘制 EditorWindow 标题的 GUIContent。
Close关闭编辑器窗口。
Show显示 EditorWindow 窗口。
ShowAsDropDown显示包含下拉菜单和样式的窗口。
ShowAuxWindow在辅助窗口中显示编辑器窗口。
ShowModal显示模态编辑器窗口。
ShowNotification显示通知消息。
ShowPopup使用弹出式框架显示编辑器窗口。
ShowUtility将 EditorWindow 显示为浮动实用程序窗口。
CreateWindow创建类型为 T 的 EditorWindow。
FocusWindowIfItsOpen聚焦发现的第一个指定类型的 EditorWindow(如果已打开)。
GetWindow返回当前屏幕上的第一个 windowType 类型的 EditorWindow。
GetWindowWithRect返回当前屏幕上第一个 t 类型的 EditorWindow。
HasOpenInstances检查编辑器窗口是否已打开。
OnBecameInvisible在窗口从容器视图中删除或在 EditorWindow 的选项卡式集合中不再可见后调用。
OnBecameVisible将窗口添加到容器视图后调用。
OnDestroy调用 OnDestroy 以关闭 EditorWindow 窗口。
OnFocus在窗口获得键盘焦点时调用。
OnGUI在此处实现您自己的 Editor GUI。
OnHierarchyChange处理程序,用于在层级视图中的对象或对象组发生更改时发送的消息。
OnInspectorUpdateOnInspectorUpdate 以每秒 10 帧的速度调用,以便检视面板有机会进行更新。
OnLostFocus在窗口失去键盘焦点时调用。
OnProjectChange处理程序,用于在项目状态发生更改时发送的消息。
OnSelectionChange每当选择发生更改时调用。


三、EditorWindow 的生命周期

1、打开

OnEnable():当打开界面的时候调用

OnFocus():当该窗口被聚焦(点击该窗口)

2、打开中

OnGUI():当渲染 UI 的时候调用

OnSelectionChange():当选择发生更改时调用,选中的可选项(在 Project 和 Hierarchy 视图中)

OnInspectorUpdate():当属性界面更新时,几乎一直在更

OnHierarchyChange():当场景层次界面发生改变时调用 ");// 在 Hierarchy 界面改变(增加、减少物体)

OnProjectChange():当项目发生更改时调用 ");// 在 Project 视图删除、增加文件

OnValidate():当拖拽式赋值时调用

3、关闭

OnLostFocus():从该窗口离开时调用(点击非窗口外其他地方)

OnDisable():当隐藏的时候调用

OnDestroy():当销毁的时候调用


四、CreateWindow、GetWindow、GetWindowWithRect

1、在 Unity 编辑器中,CreateWindow()GetWindow() 和 GetWindowWithRect() 是用于处理窗口的函数,但它们的功能和使用场景有所不同。

1、CreateWindow():这个函数通常用于创建一个新的窗口。在 Unity 编辑器中,这可能涉及到创建一个新的 Inspector 窗口、Console 窗口或其他自定义窗口。CreateWindow () 需要指定窗口类型(例如 WindowType.Inspector 或 WindowType.Console)以及其他可能的参数,如窗口标题和大小。

3、GetWindow()::这个函数用于获取一个已经存在的窗口。它通常用于需要引用已打开的窗口的情况,例如,你可能想关闭一个已经打开的 Inspector 窗口。

4、GetWindowWithRect()::这个函数比较特殊,它不仅仅是为了获取一个窗口,而且还要通过一个指定的矩形区域获取。这对于需要在给定屏幕区域中查找和操作窗口非常有用。比如你可能想在指定的屏幕区域查找 Console 窗口。

5、在使用这些函数时,通常需要注意以下几点:

CreateWindow() 用于创建新窗口,而 GetWindow() 和 GetWindowWithRect() 用于获取已存在的窗口。

GetWindow() 和 GetWindowWithRect() 通常用于操作已打开的窗口,例如关闭它们或获取它们的引用。

GetWindowWithRect() 特别适用于在特定屏幕区域查找窗口,这在处理多显示器或多窗口环境时非常有用。

代码示例

using UnityEditor;
using UnityEngine;

public class WindowExample : EditorWindow
{
    private static WindowExample window;//窗体实例

    //显示窗体
    [MenuItem("MyWindow/Second Window")]
    private static void ShowWindow()
    {
        window = EditorWindow.GetWindow<WindowExample>("Window Example");
        window.Show();
    }

    //显示时调用
    private void OnEnable()
    {
        Debug.Log("OnEnable");
    }

    //绘制窗体内容
    private void OnGUI()
    {
        EditorGUILayout.LabelField("Your Second Window", EditorStyles.boldLabel);
    }

    //固定帧数调用
    private void Update()
    {
        Debug.Log("Update");
    }

    //隐藏时调用
    private void OnDisable()
    {
        Debug.Log("OnDisable");
    }

    //销毁时调用
    private void OnDestroy()
    {
        Debug.Log("OnDestroy");
    }
}

1.jpg

五、ScriptableWizard参数总览

Unity为开发者提供了一个简单的快速创建对话框窗体的方式,只需要继承自ScriptableWizard类,我们容易发现ScriptableWizard实际上是继承自EditorWindow,只是做了一层封装,该类窗体一般用于快捷功能的操作,例如统一修改场景中多个对象的位置等信息。

常用参数描述
createButtonName允许您设置向导的 Create 按钮上显示的文本。
errorString允许您设置向导的错误文本。
helpString允许您设置向导的帮助文本。
isValid允许您启用向导 Create 按钮,或者将其禁用,从而使用户无法点击。
otherButtonName允许您设置向导的可选 Other 按钮上显示的文本。忽略此参数将不显示该按钮。
OnWizardCreate当用户单击 Create 按钮时,将调用此函数。
OnWizardOtherButton允许您在用户单击 Others 按钮时提供操作。
OnWizardUpdate在向导打开或者用户在向导中更改内容时,将调用此函数。


六、区别OnWizardCreate、OnWizardOtherButton、OnWizardUpdate

OnWizardCreate:

当向导被创建时调用。

通常用于初始化向导的状态或设置。

OnWizardOtherButton:

当用户在向导界面上点击非标准按钮(如 “下一步”、“上一步” 或自定义按钮)时调用。

你可以根据需要重写此方法以处理非标准按钮的点击事件。

OnWizardUpdate:

在向导的当前步骤被更新时调用。

通常用于根据用户输入或其他条件更新向导的当前步骤内容。

代码样例

using UnityEditor;
using UnityEngine;

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

    [MenuItem("GameObject/Create Light Wizard")]
    static void CreateWizard()
    {
        ScriptableWizard.DisplayWizard<WindowExample>("Create Light", "Create", "Apply");
        如果您不想使用辅助按钮,只需将其省略即可:
        //ScriptableWizard.DisplayWizard<WizardCreateLight>("Create Light", "Create");
    }
    //显示在向导窗口里的变量
    public float speedValue = 10;
    public bool canShoot = true;

    //用户单击创建按钮进行调用,固定用法,点击后向导窗口关闭
    private void OnWizardCreate()
    {
        Debug.Log("Create : Change By Value");
        //一般在这里做最终的处理
        //比如在这里可以获取选中的全部object,再利用向导窗口里填写的变量批量改变文件数值
    }

    //用户单击自定义其他按钮时进行调用,固定用法,点击后向导窗口不会关闭
    private void OnWizardOtherButton()//在这里是一个初始化数据的功能
    {
        Debug.Log("Clear");
        speedValue = 0;
        canShoot = false;
        ShowNotification(new GUIContent("数据已经初始化完毕"));
        //该功能用来弹出一个小提示通知信息,几秒后自动消失
    }

    //打开向导或者更改向导里的内容时进行调用,固定用法
    private void OnWizardUpdate()
    {
        Debug.Log("Change");
        //当在向导窗口里一些操作错误或者不规范时,可以通过设置helpString和errorString来进行提示操作人员
        helpString = "文中某某变量填写规范为"XXXX+DDDD+SS"";
        errorString = "文中某某变量填写不规范";

        //编辑器模式下,可以使用EditorPrefs进行数据的存取,用法与游戏运行时PlayerPrefs用法一致
        EditorPrefs.SetFloat("key", speedValue);

    }

    //当在工程里选中操作有变化时进行调用
    private void OnSelectionChange()
    {
        OnWizardUpdate();
    }
}

1.jpg

七、PopupWindow弹出窗口

用于显示从 PopupWindowContent 继承的弹出窗口的类。

弹出窗口没有边距,不可拖动,也无法调节大小。此外,它们还会在失去焦点时自动关闭。它们用于显示短暂的信息或选项。

编辑器中的弹出窗口的一个示例是编辑器“Scene View”工具栏中的“Scene View Effects”选项:

1.jpg


下面是一个自定义弹出窗口的示例,此弹出窗口通过编辑器窗口中的一个按钮显示。该弹出窗口具有三个开关值,并会在失去焦点时自动关闭。此示例以两个脚本的形式提供。第一个脚本定义可通过菜单项打开的编辑器窗口。该编辑器窗口具有一个可显示弹出窗口的按钮。第二个脚本以一个单独的类的形式定义弹出窗口本身的内容。

首先,下面是启动弹出窗口的简单编辑器窗口的代码:

using UnityEngine;
using UnityEditor;
public class EditorWindowWithPopup : EditorWindow
{
    // Add menu item
    [MenuItem("Example/Popup Example")]
    static void Init()
    {
        EditorWindow window = EditorWindow.CreateInstance<EditorWindowWithPopup>();
        window.Show();
    }

    Rect buttonRect;
    void OnGUI()
    {
        {
           GUILayout.Label("Editor window with Popup example", EditorStyles.boldLabel);
           if (GUILayout.Button("Popup Options", GUILayout.Width(200)))
           {
             PopupWindow.Show(buttonRect, new PopupExample());
           }
           if (Event.current.type == EventType.Repaint) 
               buttonRect = GUILayoutUtility.GetLastRect();
        }
    }
}

1.jpg

接下来,下面是弹出窗口本身的代码:

using UnityEngine;
using UnityEditor;
public class PopupExample : PopupWindowContent
{
    bool toggle1 = true;
    bool toggle2 = true;
    bool toggle3 = true;
	
    public override Vector2 GetWindowSize()
    {
        return new Vector2(200, 150);
    }

    public override void OnGUI(Rect rect)
    {
        GUILayout.Label("Popup Options Example", EditorStyles.boldLabel);
        toggle1 = EditorGUILayout.Toggle("Toggle 1", toggle1);
        toggle2 = EditorGUILayout.Toggle("Toggle 2", toggle2);
        toggle3 = EditorGUILayout.Toggle("Toggle 3", toggle3);
    }

    public override void OnOpen()
    {
        Debug.Log("Popup opened: " + this);
    }

    public override void OnClose()
    {
        Debug.Log("Popup closed: " + this);
    }
}

2.jpeg

以上每段代码应另存为以其类名称命名的单独文件。这些代码都不是行为,因此无需将它们放在游戏对象上。将它们放在项目中后,通过转到新的“Example”菜单并选择“Popup Example”即可试用。然后,单击新编辑器窗口中的按钮可显示弹出选项窗口

八、PopupWindow参数总览

受保护的函数

OnDisable请参阅 ScriptableObject.OnEnable。
OnEnable请参阅 ScriptableObject.OnDisable。

静态函数

Show显示具有给定 PopupWindowContent 的弹出窗口。

继承的成员

静态变量

focusedWindow当前已获得键盘焦点的 EditorWindow。(只读)
mouseOverWindow当前在鼠标光标下的 EditorWindow。(只读)

变量

autoRepaintOnSceneChange窗口是否会在场景每次发生变化时自动重绘?
maximized此窗口是否已最大化?
maxSize此窗口的最大大小。
minSize此窗口的最小大小。
position窗口在屏幕空间中的理想位置。
titleContent用于绘制 EditorWindow 标题的 GUIContent。
wantsMouseEnterLeaveWindow检查是否已在此编辑器窗口的 GUI 中收到 MouseEnterWindow 和 MouseLeaveWindow 事件。
wantsMouseMove检查是否已在此编辑器窗口的 GUI 中收到 MouseMove 事件。
hideFlags该对象应该隐藏、随场景一起保存还是由用户修改?
name对象的名称。

公共函数

BeginWindows标记所有弹出窗口的开始区域。
Close关闭编辑器窗口。
EndWindows关闭由 EditorWindow.BeginWindows 开始的窗口组。
Focus将键盘焦点移动到另一个 EditorWindow。
RemoveNotification停止显示通知消息。
Repaint重绘窗口。
SendEvent将事件发送到窗口。
Show显示 EditorWindow 窗口。
ShowAsDropDown显示包含下拉菜单和样式的窗口。
ShowAuxWindow在辅助窗口中显示编辑器窗口。
ShowNotification显示通知消息。
ShowPopup使用弹出式框架显示编辑器窗口。
ShowUtility将 EditorWindow 显示为浮动实用程序窗口。
GetInstanceID返回对象的实例 ID。
ToString返回对象的名称。

静态函数

FocusWindowIfItsOpen聚焦发现的第一个指定类型的 EditorWindow(如果已打开)。
GetWindow返回当前屏幕上第一个 t 类型的 EditorWindow。
GetWindowWithRect返回当前屏幕上第一个 t 类型的 EditorWindow。
Destroy移除 GameObject、组件或资源。
DestroyImmediate立即销毁对象 /obj/。强烈建议您改用 Destroy。
DontDestroyOnLoad在加载新的 Scene 时,请勿销毁 Object。
FindObjectOfType返回第一个类型为 type 的已加载的激活对象。
FindObjectsOfType返回所有类型为 type 的已加载的激活对象的列表。
Instantiate克隆 original 对象并返回克隆对象。
CreateInstance创建脚本化对象的实例。

运算符

bool该对象是否存在?
operator !=比较两个对象是否引用不同的对象。
operator ==比较两个对象引用,判断它们是否引用同一个对象。

消息

Awake在新窗口打开时调用。
OnDestroy调用 OnDestroy 以关闭 EditorWindow 窗口。
OnFocus在窗口获得键盘焦点时调用。
OnGUI在此处实现您自己的 Editor GUI。
OnHierarchyChange处理程序,用于在层级视图中的对象或对象组发生更改时发送的消息。
OnInspectorUpdateOnInspectorUpdate 以每秒 10 帧的速度调用,以便检视面板有机会进行更新。
OnLostFocus在窗口失去键盘焦点时调用。
OnProjectChange处理程序,用于在项目状态发生更改时发送的消息。
OnSelectionChange每当选择发生更改时调用。
Update在所有可见窗口上每秒调用多次。
Awake当 ScriptableObject 脚本启动时调用此函数。
OnDestroy当脚本化对象将销毁时调用此函数。