Note: It’s strongly recommended to use the UI Toolkit to extend the Unity Editor, as it provides a more modern, flexible, and scalable solution than IMGUI.
为了加快应用程序开发,请为常用组件创建自定义编辑器。本页面展示了如何创建一个简单的脚本以使游戏对象始终看向一个点。
//C# 示例 (LookAtPoint.cs)
using UnityEngine;
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
进入运行模式后,脚本所附加到的游戏对象现在会将自身朝向设置为“Look At Point”属性的坐标。编写编辑器脚本时,让某些脚本在编辑模式期间执行通常很有用(此时未运行您的应用程序)。为此,请向类添加 ExecuteInEditMode
属性,如下所示:
//C# 示例 (LookAtPoint.cs)
using UnityEngine;
[ExecuteInEditMode]
public class LookAtPoint : MonoBehaviour
{
public Vector3 lookAtPoint = Vector3.zero;
void Update()
{
transform.LookAt(lookAtPoint);
}
}
现在,如果在 Editor 中移动游戏对象或者在 Inspector 中更改“Look At Point”的值,则游戏对象将更新其旋转,以便其看向世界空间中的目标点。
上文演示了如何在编辑时运行简单脚本;但仅凭此还不足以创建自己的 Editor 工具。下一步需要为您刚创建的脚本创建__自定义编辑器__。
在 Unity 中创建脚本时,默认情况下,此脚本继承自 MonoBehaviour,因此可作为附加到游戏对象的组件。将一个组件放置在游戏对象上时,Inspector 会显示一个默认界面,可用于查看和编辑每个公共变量,例如:整数、浮点数或字符串。
LookAtPoint 组件的 Inspector 在默认情况下的外观如下:
自定义编辑器是一个单独脚本,可将此默认布局替换为您选择的任何编辑器控件。
要为 LookAtPoint 脚本创建自定义编辑器,请执行以下操作:
//C# 示例 (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
serializedObject.ApplyModifiedProperties();
}
}
该类必须继承自 Editor。CustomEditor 属性告知 Unity 应该作为哪个组件的编辑器。CanEditMultipleObjects 属性告诉 Unity 您可以使用此编辑器来选择多个对象并同时更改所有对象。
Unity 在 Inspector 中显示编辑器时将执行 OnInspectorGUI 中的代码。可以在此处插入任何 GUI 代码,原理就像 OnGUI 一样,不过是在 Inspector 内运行。编辑器会定义可用于访问所检查游戏对象的目标属性。
使用新编辑器时,LookAtPoint 组件的 Inspector 的外观如下:
这看起来非常相似(但现在不存在“Script”字段,因为编辑器脚本未添加任何 Inspector 代码来显示它)。
但是,现在可以在编辑器脚本中控制 Inspector 的显示方式,可以使用所喜欢的任何代码来布局 Inspector 字段,允许用户调整值,甚至显示图形或其他可视元素。实际上,在 Unity Editor 中看到的所有 Inspector(包括更复杂的 Inspector,例如地形系统和动画导入设置)都是使用同一 API 生成的。在创建自己的自定义编辑器时可以访问此 API。
下面是一个简单示例,用于扩展编辑器脚本以显示一条消息,指示目标点在游戏对象之上还是之下:
//C# 示例 (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
serializedObject.ApplyModifiedProperties();
if (lookAtPoint.vector3Value.y > (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Above this object)");
}
if (lookAtPoint.vector3Value.y < (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Below this object)");
}
}
}
这就是 LookAtPoint 组件的 Inspector 的外观,其中显示了一条消息来指明目标点在游戏对象之上还是之下。
可以全面访问所有 IMGUI 命令来绘制任何类型的界面,包括使用 Editor 窗口中的摄像机来渲染场景。
您可以向 Scene 视图添加额外的代码。为此,请在自定义编辑器中实现 OnSceneGUI。
OnSceneGUI 的运行方式很像 OnInspectorGUI,只不过在 Scene 视图中运行而已。为了方便您创建自己的编辑控件,可以使用在 Handles 类中定义的函数。其中的所有函数都是为 3D 模式的 Scene 视图设计的。
//C# 示例 (LookAtPointEditor.cs)
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(LookAtPoint))]
[CanEditMultipleObjects]
public class LookAtPointEditor : Editor
{
SerializedProperty lookAtPoint;
void OnEnable()
{
lookAtPoint = serializedObject.FindProperty("lookAtPoint");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(lookAtPoint);
if (lookAtPoint.vector3Value.y > (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Above this object)");
}
if (lookAtPoint.vector3Value.y < (target as LookAtPoint).transform.position.y)
{
EditorGUILayout.LabelField("(Below this object)");
}
serializedObject.ApplyModifiedProperties();
}
public void OnSceneGUI()
{
var t = (target as LookAtPoint);
EditorGUI.BeginChangeCheck();
Vector3 pos = Handles.PositionHandle(t.lookAtPoint, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Move point");
t.lookAtPoint = pos;
t.Update();
}
}
}
如果要添加 2D GUI 对象(例如:GUI 或 EditorGUI),需要将这些对象包裹在 Handles.BeginGUI() 和 Handles.EndGUI() 的调用中。
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.