版本:Unity 6 (6000.0)
语言:英语
使用 C# 脚本创建自定义编辑器窗口
查看数据持久性

创建自定义检视器

版本: 2022.3+

虽然您的 MonoBehaviour 和 ScriptableObjects 有一个默认的 检视器一个 Unity 窗口,显示有关当前选定游戏对象、资源或项目设置的信息,允许您检查和编辑值。 更多信息
查看 词汇表
,但您可能希望为您的类编写一个自定义检视器。自定义检视器可以帮助您执行以下操作

  • 创建脚本属性的更人性化的表示形式。
  • 组织和分组属性。
  • 根据用户的选择显示或隐藏 UI(用户界面) 允许用户与您的应用程序进行交互。Unity 当前支持三种 UI 系统。 更多信息
    查看 词汇表
    的部分。
  • 提供有关单个设置和属性含义的额外信息。

示例概述

本示例为 MonoBehaviour 类创建自定义检视器。它同时使用 C# 脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间推移修改组件属性并以任何您喜欢的方式响应用户输入。 更多信息
查看 词汇表
和 UI Builder 来创建 UI。自定义检视器还具有自定义的 属性绘制器一个 Unity 功能,允许您使用脚本上的属性或通过控制特定可序列化类的外观来自定义检视器窗口中某些控件的外观 更多信息
查看 词汇表

自定义检视器显示 Car 类的属性,包括制造商、制造年份、颜色和轮胎列表。检视器使用 PropertyField 控件显示 Car 类的属性,并使用自定义属性绘制器显示 Tire 类的属性。

您可以在此 GitHub 存储库 中找到本示例创建的完整文件。

先决条件

本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发人员。在开始之前,请熟悉以下内容

创建一个新的 MonoBehaviour

要创建自定义检视器,首先定义一个从 MonoBehaviour 继承的自定义类。自定义类表示一个具有多个属性的简单 car

  1. 在 Unity 中使用任何模板创建一个项目。

  2. 在您的 项目窗口一个窗口,显示您的 Assets 文件夹的内容(项目选项卡) 更多信息
    查看 词汇表
    中,创建一个名为 create-a-custom-inspector 的文件夹来存储所有文件。

  3. 使用以下内容创建一个名为 Car.cs 的 C# 脚本

    using UnityEngine;
    
    public class Car : MonoBehaviour
    {
         public string m_Make = "Toyota";
         public int m_YearBuilt = 1980;
         public Color m_Color = Color.black;
    }
    
  4. 场景场景包含游戏环境和菜单。将每个唯一的场景文件视为一个唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,本质上是分段设计和构建游戏。 更多信息
    查看 词汇表
    中创建一个新的 游戏对象Unity 场景中的基本对象,可以代表角色、道具、场景、相机、路点等。游戏对象的功

    Default Inspector for the Car object
    汽车对象的默认检视器

创建一个自定义检视器脚本

要为任何序列化对象创建自定义检视器,您需要创建一个从 Editor 基类派生的类,并向其添加 CustomEditor 属性。此属性让 Unity 知道此自定义检视器代表哪个类。

注意:自定义检视器脚本必须位于 Editor 文件夹或仅限编辑器的程序集定义中。这是因为 UnityEditor 命名空间对于创建自定义检视器至关重要,在这些区域之外无法访问它。如果您尝试在不遵守此规则的情况下创建独立构建,则构建过程将失败。

  1. create-a-custom-inspector 文件夹中创建一个名为 Editor 的文件夹。

  2. Editor 文件夹中创建一个名为 Car_Inspector.cs 的 C# 脚本,内容如下

    using UnityEditor;
    using UnityEditor.UIElements;
    using UnityEngine.UIElements;
    
    [CustomEditor(typeof(Car))]
    public class Car_Inspector : Editor
    {
    }
    
  3. 选择已附加 Car 组件的游戏对象。默认检视器将显示。

  4. 要替换默认检视器,在 Car_Inspector 类中,添加以下代码以覆盖 CreateInspectorGUI() 并返回一个新的 视觉元素视觉树的一个节点,它实例化或派生自 C# VisualElement 类。您可以设置外观、定义行为,并将其显示在屏幕上作为 UI 的一部分。 更多信息
    查看 词汇表
    ,其中包含 UI

    public override VisualElement CreateInspectorGUI()
    {
         // Create a new VisualElement to be the root of our Inspector UI.
         VisualElement myInspector = new VisualElement();
    
         // Add a simple label.
         myInspector.Add(new Label("This is a custom Inspector"));
    
         // Return the finished Inspector UI.
         return myInspector;
    }
    
  5. 选择已附加 Car 组件的游戏对象。现在,检视器显示标签 This is a custom Inspector 而不是默认检视器。

    Custom Inspector with a label
    具有标签的自定义检视器

使用 UI Builder 创建自定义检视器 UI

您可以使用 UI Builder 创建自定义检视器 UI,并使用 C# 脚本从 UXML 文件加载和实例化 UI。

  1. 要打开 UI Builder,请选择 窗口 > UI 工具包 > UI Builder

  2. 选择 文件 > 新建 以创建一个新的视觉树资源。

    Custom Inspector with a label
    具有标签的自定义检视器
  3. 在 UI Builder 中启用仅限编辑器的控件,请选择 层次结构 视图中的 <unsaved file>*.uxml,然后选中 编辑器扩展创作 复选框。

    Custom Inspector with a label
    具有标签的自定义检视器
  4. 拖动一个标签控件到 层次结构。这将向视觉树添加一个标签控件。

    Custom Inspector with a label
    具有标签的自定义检视器
  5. 在标签控件的检视器面板中,更新标签文本。

    Custom Inspector with a label
    具有标签的自定义检视器
  6. 选择 文件 > 保存,并将视觉树保存为 Car_Inspector_UXML.uxmlAssets/create-a-custom-inspector 文件夹。

在自定义检视器中使用 UXML

要在自定义检视器中使用您创建的 UXML 文件,请将该文件分配给自定义检视器,并在 CreateInspectorGUI() 函数中加载和克隆它,并将其添加到视觉树。为此,您可以使用 CloneTree 方法。您可以将任何 VisualElement 作为参数传递,以充当创建元素的父元素。

  1. Car_Inspector.cs 中,在您的脚本中为 VisualTreeAsset 创建一个公共变量,并将 Car_Inspector_UXML.uxml 分配给它。

    public VisualTreeAsset m_InspectorXML;
    
  2. CreateInspectorGUI() 方法更新为以下内容

    public override VisualElement CreateInspectorGUI()
    {
         // Create a new VisualElement to be the root of our Inspector UI.
         VisualElement myInspector = new VisualElement();
    
         // Add a simple label.
         myInspector.Add(new Label("This is a custom Inspector"));
    
         // Load the UXML file.
         m_InspectorXML= AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/create-a-custom-inspector/Car_Inspector_UXML.uxml");
    
         // Instantiate the UXML.
         myInspector = m_InspectorXML.Instantiate();
    
         // Return the finished Inspector UI.
         return myInspector;
    }
    
  3. 选择已附加 Car 组件的游戏对象。现在,car 组件的检视器显示两个标签:一个通过脚本,另一个通过 UI Builder/UXML。

    Custom Inspector with two labels label
    具有两个标签的自定义检视器

绑定一个文本字段

此自定义检视器显示 Car 类的所有属性。当用户修改任何 UI 控件时,Car 类实例内的值会发生变化。为此,请将 UI 控件添加到视觉树并将其绑定到类的各个属性。

要将控件绑定到序列化属性,请将属性分配给控件的 binding-path 字段。当您创建自定义检视器时,绑定是自动的。 CreateInspectorGUI() 在您返回视觉树后会进行隐式绑定。有关更多信息,请参阅 序列化对象数据绑定

  1. 双击 Car_Inspector_UXML.uxml 以在 UI Builder 中打开它。

  2. 添加一个 文本字段控件文本字段控件向用户显示一段非交互式文本,例如标题、其他 GUI 控件的标签或说明。 更多信息
    查看 词汇表

    Add a text field to the UI
    向 UI 添加一个文本字段
  3. 在文本字段的检视器面板中,将标签文本设置为 Make of the car

  4. 将绑定路径设置为 m_Make

    Bind a property to a control in UI Builder
    在 UI Builder 中将属性绑定到控件
  5. 样式类列表 添加样式类 unity-base-field__aligned,以便文本字段与检视器窗口中的其他字段对齐。有关更多信息,请参阅 BaseField

    Add a style class to the text field
    向文本字段添加样式类
  6. 在 UI Builder 中,选择 文件 > 保存

  7. 选择已附加 Car 组件的游戏对象。现在,car 组件的检视器显示 Make of the car 文本字段。文本字段绑定到 Car 类的 m_Make 属性。

    Custom Inspector showing a text field
    显示文本字段的自定义检视器

绑定一个属性字段

要显示 Car 类的属性,请为每个字段添加一个控件。控件必须与属性类型匹配。例如,您必须将 int 绑定到整数字段或整数滑块。

除了根据属性类型添加特定控件外,您还可以使用通用 PropertyField 控件。此控件适用于大多数类型的序列化属性,并为该属性类型生成默认的检视器 UI。

PropertyField 的优势在于,当您在脚本中更改变量类型时,检视器 UI 会自动调整。但是,您无法在 UI Builder 中预览控件,因为在将视觉树绑定到序列化对象之前,控件类型是未知的。

  1. 双击 Car_Inspector_UXML.uxml 以在 UI Builder 中打开它。

  2. Car类的m_YearBuilt属性添加一个PropertyField控件,并设置绑定路径和标签文本。

    Add a property field in UI Builder
    在UI Builder中添加一个属性字段。
  3. 在**样式类列表**中添加样式类unity-base-field__aligned

  4. Car类的m_Color属性添加一个PropertyField控件,并设置绑定路径和标签文本。

  5. 在**样式类列表**中添加样式类unity-base-field__aligned

  6. 在 UI Builder 中,选择 文件 > 保存

  7. 选择具有Car组件的游戏对象。现在,car组件的检查器将显示“建造年份”和“油漆颜色”属性字段。

    Custom Inspector with property fields
    带有属性字段的自定义检查器

创建自定义属性绘制器

自定义属性绘制器是针对自定义可序列化类的自定义检查器UI。如果该可序列化类是另一个序列化对象的的一部分,则自定义UI会在检查器中显示该属性。在UI工具包中,如果存在自定义属性绘制器,则PropertyField控件将显示该属性的自定义属性绘制器。

  1. create-a-custom-inspector文件夹中,创建一个名为Tire.cs的新脚本,内容如下

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
        
    [System.Serializable]
    public class Tire
    {
        public float m_AirPressure = 21.5f;
        public int m_ProfileDepth = 4;
    }
        
    
  2. Car.cs中,向Car类添加一个Tire列表。完成后的Car.cs文件如下所示

    using UnityEngine;
        
    public class Car : MonoBehaviour
    {
        public string m_Make = "Toyota";
        public int m_YearBuilt = 1980;
        public Color m_Color = Color.black;
        
        // This car has four tires.
        public Tire[] m_Tires = new Tire[4];
    }
    
  3. PropertyField控件适用于所有标准属性类型,还支持自定义可序列化类和数组。要显示汽车轮胎的属性,请在Car_Inspector_UXML.uxml中添加另一个PropertyField,并将其绑定到m_Tires。完成后的Car_Inspector_UXML.uxml文件如下所示

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
        <ui:TextField picking-mode="Ignore" label="Make of the car" value="filler text" binding-path="m_Make" class="unity-base-field__aligned" />
        <uie:PropertyField binding-path="m_YearBuilt" label="Year Built" class="unity-base-field__aligned" />
        <uie:PropertyField binding-path="m_Color" label="Paint Color" class="unity-base-field__aligned" />
        <uie:PropertyField label="Tires" binding-path="m_Tires" class="unity-base-field__aligned" />
        <ui:Foldout text="Default Inspector" value="false" name="Default_Inspector" />
    </ui:UXML>
        
    
  4. 选择具有Car组件的游戏对象。现在,car组件的检查器将显示“轮胎”属性字段。

    Use a PropertyField control to display an array
    使用PropertyField控件显示数组

为自定义属性绘制器创建UI

您可以创建自定义属性绘制器来自定义列表中各个Tire元素的外观。自定义属性绘制器不从Editor基类派生,而是从PropertyDrawer类派生。

您可以使用C#脚本或UXML创建属性的UI。此示例使用C#脚本创建自定义UI。要为自定义属性创建UI,请覆盖CreatePropertyGUI方法。

  1. Editor文件夹中,创建一个名为Tire_PropertyDrawer.cs的新脚本,内容如下

    using UnityEditor;
    using UnityEditor.UIElements;
    using UnityEngine.UIElements;
        
    [CustomPropertyDrawer(typeof(Tire))]
    public class Tire_PropertyDrawer : PropertyDrawer
    {
        public override VisualElement CreatePropertyGUI(SerializedProperty property)
        {
            // Create a new VisualElement to be the root the property UI.
            var container = new VisualElement();
        
            // Create drawer UI using C#.
            var popup = new UnityEngine.UIElements.PopupWindow();
            popup.text = "Tire Details";
            popup.Add(new PropertyField(property.FindPropertyRelative("m_AirPressure"), "Air Pressure (psi)"));
            popup.Add(new PropertyField(property.FindPropertyRelative("m_ProfileDepth"), "Profile Depth (mm)"));
            container.Add(popup);
        
            // Return the finished UI.
            return container;
        }
    }
    
  2. 选择具有Car组件的游戏对象。现在,car组件的检查器将显示带有自定义属性绘制器的“轮胎”属性字段。

    Inspector using a custom property drawer
    使用自定义属性绘制器的检查器

创建一个默认检查器

创建一个Foldout控件来显示默认检查器UI。要将默认检查器UI附加到Foldout,您必须获取对其的引用。您可以使用UQuery从检查器的可视化树中检索Foldout的可视化元素,并使用FillDefaultInspector方法InspectorElement类将默认检查器UI附加到Foldout控件。

  1. 双击Car_Inspector_UXML.uxml文件,在UI Builder中打开它。

  2. 向UI中添加一个Foldout控件,将其命名为Default_Inspector,并设置标签文本。

    Foldout for the default Inspector
    用于默认检查器的Foldout
  3. Car_Inspector.cs文件中,更新CreateInspectorGUI()方法以获取对Default_Inspector Foldout的引用,并将默认检查器UI附加到它。完成后的Car_Inspector.cs文件如下所示

    using UnityEditor;
    using UnityEditor.UIElements;
    using UnityEngine.UIElements;
        
    [CustomEditor(typeof(Car))]
    public class Car_Inspector : Editor
    {
        public VisualTreeAsset m_InspectorXML;
        public override VisualElement CreateInspectorGUI()
        {
            // Create a new VisualElement to be the root of the Inspector UI.
            VisualElement myInspector = new VisualElement();
        
            // Load the reference UXML.
            m_InspectorXML= AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/create-a-custom-inspector/Car_Inspector_UXML.uxml");
        
            // Instantiate the UXML.
            myInspector = m_InspectorXML.Instantiate();
        
            // Get a reference to the default Inspector Foldout control.
            VisualElement InspectorFoldout = myInspector.Q("Default_Inspector");
        
            // Attach a default Inspector to the Foldout.
            InspectorElement.FillDefaultInspector(InspectorFoldout, serializedObject, this);
        
            // Return the finished Inspector UI.
            return myInspector;
        }
    }
        
    
  4. 选择具有Car组件的游戏对象。现在,car组件的检查器将显示“默认检查器”Foldout,其中包含默认检查器UI。

    Inspector with a default Inspector
    带有默认检查器的检查器

其他资源

使用 C# 脚本创建自定义编辑器窗口
查看数据持久性