从此基类派生以创建自定义检查器或您自定义对象的编辑器。
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... } }
例如,使用自定义编辑器更改脚本在检查器中的外观。
您可以使用 CustomEditor 属性将编辑器附加到自定义组件。
有多种方法可以设计自定义编辑器。如果希望编辑器支持多对象编辑,则可以使用 CanEditMultipleObjects 属性。与其直接修改脚本变量,不如使用 SerializedObject 和 SerializedProperty 系统来编辑它们,因为这会自动处理多对象编辑、撤消和预制覆盖。如果使用此方法,用户可以在层次结构窗口中选择多个资源,并同时更改所有资源的值。
您可以使用 UIElements 构建自定义 UI,也可以使用 IMGUI。要使用 UIElements 创建自定义检查器,您必须覆盖 Editor.CreateInspectorGUI Editor 类上的方法。要使用 IMGUI 创建自定义检查器,您必须覆盖 Editor.OnInspectorGUI Editor 类上的方法。如果您使用 UIElements 并且已覆盖 Editor.CreateInspectorGUI ,则在同一编辑器上使用 Editor.OnInspectorGUI 的任何现有的 IMGUI 实现都将被忽略。
这是一个自定义检查器的示例
检查器中的自定义编辑器。
using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; [CustomEditor(typeof(MyPlayer))] public class MyPlayerEditor : Editor { const string resourceFilename = "custom-editor-uie"; public override VisualElement CreateInspectorGUI() { VisualElement customInspector = new VisualElement(); var visualTree = Resources.Load(resourceFilename) as VisualTreeAsset; visualTree.CloneTree(customInspector); customInspector.styleSheets.Add(Resources.Load($"{resourceFilename}-style") as StyleSheet); return customInspector; } }
以下示例定义了 uxml 中自定义检查器的布局。该定义作为资源加载,并且 VisualTreeAsset.CloneTree 方法将层次结构放入 VisualElement 对象中。
InspectorWindow 将实例化一个包含自定义检查器的 InspectorElement 。 InspectorElement 将在自定义检查器上调用 Bind,将其绑定到 MyPlayer 对象。
<UXML xmlns="UnityEngine.UIElements" xmlns:e="UnityEditor.UIElements"> <VisualElement class="player-property"> <VisualElement class="slider-row"> <Label class="player-property-label" text="Damage"/> <VisualElement class="input-container"> <SliderInt class="player-slider" name="damage-slider" high-value="100" direction="Horizontal" binding-path="damage"/> <e:IntegerField class="player-int-field" binding-path="damage"/> </VisualElement> </VisualElement> <e:ProgressBar class="player-property-progress-bar" name="damage-progress" binding-path="damage" title="Damage"/> </VisualElement>
<VisualElement class="player-property"> <VisualElement class="slider-row"> <Label class="player-property-label" text="Armor"/> <VisualElement class="input-container"> <SliderInt class="player-slider" name="armor-slider" high-value="100" direction="Horizontal" binding-path="armor"/> <e:IntegerField class="player-int-field" binding-path="armor"/> </VisualElement> </VisualElement> <e:ProgressBar class="player-property-progress-bar" name="armor-progress" binding-path="armor" title="Armor"/> </VisualElement>
<e:PropertyField class="gun-field" binding-path="gun" label="Gun Object"/> </UXML>
当数据更改时,UIElements 会自动更新 UI,反之亦然。要绑定数据并自动更新数据和 UI,请设置“绑定路径”属性的值。
检查器的样式在 uss 中完成。
.slider-row { flex-direction: row; justify-content: space-between; margin-top: 4px; } .input-container { flex-direction: row; flex-grow: .6; margin-right: 4px; } .player-property { margin-bottom: 4px; } .player-property-label { flex:1; margin-left: 16; } .player-slider { flex:3; margin-right: 4px; } .player-property-progress-bar { margin-left: 16px; margin-right: 4px; } .player-int-field { min-width: 48px; } .gun-field { justify-content: space-between; margin-left: 16px; margin-right: 4px; margin-top: 6px; flex-grow: .6; }
这是一个使用 IMGUI 和多选的自定义检查器的示例
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 (); } }
如果不需要自动处理多对象编辑、撤消和预制覆盖,则编辑器可以直接修改脚本变量,而无需使用 SerializedObject 和 SerializedProperty 系统,如下面的 IMGUI 示例所示。
using UnityEditor; using UnityEngine; using System.Collections;
// Example script with properties. public class MyPlayerAlternative : MonoBehaviour { public int damage; public int armor; public GameObject gun;
// ...other code... }
// Custom Editor the "old" way by modifying the script variables directly. // No handling of multi-object editing, undo, and Prefab overrides! [CustomEditor (typeof(MyPlayerAlternative))] public class MyPlayerEditorAlternative : Editor {
public override void OnInspectorGUI() { MyPlayerAlternative mp = (MyPlayerAlternative)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); }
// 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 (); } }
hasUnsavedChanges | 此属性指定在检查器重建之前,编辑器是否提示用户保存或放弃未保存的更改。 |
saveChangesMessage | 如果提示用户保存,则向用户显示的消息。 |
serializedObject | 表示正在检查的对象或对象的 SerializedObject。 |
target | 正在检查的对象。 |
targets | 正在检查的所有对象的数组。 |
CreateInspectorGUI | 实现此方法以创建自定义 UIElements 检查器。 |
CreatePreview | 实现此方法以创建自定义 UIElements 检查器预览。 |
DiscardChanges | 放弃对编辑器内容的未保存更改。 |
DrawDefaultInspector | 绘制内置检查器。 |
DrawHeader | 调用此函数以绘制编辑器的标题。 |
DrawPreview | 预览绘制的第一个入口点。 |
GetInfoString | 实现此方法以在资源预览的顶部显示资源信息。 |
GetPreviewTitle | 如果您想更改预览区域的标签,请覆盖此方法。 |
HasPreviewGUI | 如果您实现了 OnPreviewGUI,请在子类中覆盖此方法。 |
OnInspectorGUI | 实现此函数以创建自定义检查器。 |
OnInteractivePreviewGUI | 实现以创建您自己的交互式自定义预览。交互式自定义预览用于检查器的预览区域和对象选择器。 |
OnPreviewGUI | 为检查器的预览区域、主编辑器的标题和对象选择器创建自定义预览。您必须实现 Editor.HasPreviewGUI 才能调用此方法。 |
OnPreviewSettings | 如果您想在预览标题中显示自定义控件,请覆盖此方法。 |
RenderStaticPreview | 如果您想渲染静态预览,请覆盖此方法。 |
Repaint | 重新绘制显示此编辑器的任何检查器。 |
RequiresConstantRepaint | 检查此编辑器在其当前状态下是否需要持续重新绘制。 |
SaveChanges | 对编辑器的内容执行保存操作。 |
UseDefaultMargins | 如果您不希望默认边距,请在子类中覆盖此方法以返回 false。 |
ShouldHideOpenButton | 返回检查器中“打开”按钮的可见性设置。 |
CreateCachedEditor | 返回时,previousEditor 是 targetObject 或 targetObjects 的编辑器。该函数要么返回编辑器是否已跟踪对象,要么销毁之前的编辑器并创建一个新的编辑器。 |
CreateCachedEditorWithContext | 使用上下文对象创建缓存的编辑器。 |
CreateEditor | 为 targetObject 或 targetObjects 创建自定义编辑器。 |
CreateEditorWithContext | 使用上下文对象为 targetObject 或 targetObjects 创建自定义编辑器。 |
DrawFoldoutInspector | 使用带有折叠标题的检查器 GUI 绘制 target。 |
HasFrameBounds | 验证是否可以为此编辑器计算自定义边界。 |
OnGetFrameBounds | 获取此编辑器目标的自定义边界。 |
OnSceneGUI | 使编辑器能够在场景视图中处理事件。 |
finishedDefaultHeaderGUI | 在绘制检查器窗口的标题时引发的事件,在绘制默认标题项后。 |
GetInstanceID | 获取对象的实例 ID。 |
ToString | 返回对象的名称。 |
Destroy | 移除游戏对象、组件或资源。 |
DestroyImmediate | 立即销毁对象 obj。强烈建议您改用 Destroy。 |
DontDestroyOnLoad | 加载新场景时不要销毁目标对象。 |
FindAnyObjectByType | 检索类型为 type 的任何活动加载对象。 |
FindFirstObjectByType | 检索类型为 type 的第一个活动加载对象。 |
FindObjectsByType | 检索类型为 type 的所有加载对象的列表。 |
Instantiate | 克隆对象 original 并返回克隆。 |
InstantiateAsync | 捕获原始对象(必须与某个游戏对象相关)的快照,并返回 AsyncInstantiateOperation。 |
CreateInstance | 创建可脚本化对象的实例。 |
bool | 对象是否存在? |
operator != | 比较两个对象是否引用不同的对象。 |
operator == | 比较两个对象引用以查看它们是否引用同一对象。 |
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.