使用Unity Editor中的Handle API在链接到Vector3字段的场景中显示可拖动的点

我一直在寻找新的方法来改进Unity编辑器中的编辑。 我的项目中的一个常见问题是:简化定义代表场景中某个点的序列化字段(即序列化Vector3)的坐标

例如,假设我有一个脚本可以在场景中的某个位置生成某个预制件:

using UnityEngine; 
using System.Collections;
public class ExampleBehavior : MonoBehaviour {
public Vector3 SpawnPosition;
public GameObject SpawnableObject;
public void Spawn() {
Instantiate(SpawnableObject, SpawnPosition, Quaternion.identity);
}
}

我的目标是SpawnPosition在场景内移动SpawnPosition点的过程。

我的第一种方法是使用OnGizmosSelected方法(在场景编辑器中显示一个彩色球体)来指示点位置,然后手动更改Vector3的值,直到获得正确的位置。 但是编辑起来不是很舒服。

检查了这个很棒的插件源之后,我发现了Unity Editor的Handles API,这是在场景中产生可交互对象(例如点,可调整大小的形状等)的一组方法。

因此,我尝试定义一个自定义编辑器脚本以在通用点上显示一个Handle ,以便可以轻松地在许多脚本中重用它。

这是我的做法:

首先,我定义了一个新的PropertyAttribute ,因此可以使用它在编辑器上启用此行为:

 public class DraggablePoint : PropertyAttribute {} 

然后,我为所有MonoBehaviors定义了一个自定义编辑器脚本,该脚本将迭代每个属性以搜索DraggablePoint ,并显示其句柄:

 [CustomEditor(typeof(MonoBehaviour), true)] 
public class DraggablePointDrawer : Editor {
[CustomEditor(typeof(MonoBehaviour), true)]
public class DraggablePointDrawer : Editor {
readonly GUIStyle style = new GUIStyle(); void OnEnable(){
style.fontStyle = FontStyle.Bold;
style.normal.textColor = Color.white;
}
void OnEnable(){
style.fontStyle = FontStyle.Bold;
style.normal.textColor = Color.white;
}
public void OnSceneGUI () {
var property = serializedObject.GetIterator ();
while (property.Next (true)) {
if (property.propertyType == SerializedPropertyType.Vector3) {
var field = serializedObject.targetObject.GetType ().GetField (property.name);
if (field == null) {
continue;
}
var draggablePoints = field.GetCustomAttributes (typeof(DraggablePoint), false);
if (draggablePoints.Length > 0) {
Handles.Label(property.vector3Value, property.name);
property.vector3Value = Handles.PositionHandle (property.vector3Value, Quaternion.identity);
serializedObject.ApplyModifiedProperties ();
}
}
}
}
}
public void OnSceneGUI () {
var property = serializedObject.GetIterator ();
while (property.Next (true)) {
if (property.propertyType == SerializedPropertyType.Vector3) {
var field = serializedObject.targetObject.GetType ().GetField (property.name);
if (field == null) {
continue;
}
var draggablePoints = field.GetCustomAttributes (typeof(DraggablePoint), false);
if (draggablePoints.Length > 0) {
Handles.Label(property.vector3Value, property.name);
property.vector3Value = Handles.PositionHandle (property.vector3Value, Quaternion.identity);
serializedObject.ApplyModifiedProperties ();
}
}
}
}
}

注意:

  • 我将true作为第二个参数传递给CustomEditor 。 这是为了统一地将此编辑器脚本实例化到继承自MonoBehavior(每个统一脚本组件)的所有类。
  • 我正在使用serializedObject.GetIterator ()对脚本的每个属性进行迭代。
  • 我使用反射来检查在当前对象属性中定义的DraggableType类型的任何PropertyAttribute
  • 我使用serializedObject.ApplyModifiedProperties (); 应用手柄完成的运动。 它还会创建一个历史记录条目,因此您可以使用ctrl+z回滚运动

我认为结果非常酷!

这是一个例子:

这是完整的代码示例:
https://gist.github.com/ProGM/226204b2a7f99998d84d755ffa1fb39a

我正在为电子游戏使用此脚本。 一探究竟!
希望您能发现它有用!