[Unity Editor] Show a draggable point into the scene linked to a Vector2/Vector3 field
I was always wondering if it's possible to show a draggable point in the scene to position
For instance, assuming I have a script that should spawn a certain prefab in the scene with a certain position:
using UnityEngine;
using System.Collections;
public class ExampleBehavior : MonoBehaviour {
public Vector3 SpawnPosition;
public GameObject SpawnableObject;
public void Spawn() {
Instantiate(SpawnableObject, SpawnPosition, Quaternion.identity);
}
}
My goal was to make easier to move the SpawnPosition
point inside the Scene. My first approach was to use the OnGizmosSelected
method, and show a colored sphere in the scene editor, to indicate the point position. However it was not so comfortable to edit.
Inspecting this great plugin, I discovered the great Unity Editor's Handles API
So I tried to define a custom editor script to show an Handle
on generic points, so I can reuse it in many script easily.
First of all, I defined a new PropertyAttribute
, so I can use it to enable this behavior on the editor:
public class DraggablePoint : PropertyAttribute {}
Then I defined a custom editor script, for all MonoBehaviors
, that iterates every property in search of a DraggablePoint
, showing an handle for it:
[CustomEditor(typeof(MonoBehaviour), true)]
public class DraggablePointDrawer : Editor {
readonly GUIStyle style = new GUIStyle();
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 ();
}
}
}
}
}
Note that:
- I'm passing
true
as a second parameter toCustomEditor
. This says to unity to instantiate this Editor script to all classes that inherits from MonoBehavior (every unity script component). - I'm using
serializedObject.GetIterator ()
to iterate on every property of the script. - I use Reflection to check for any
PropertyAttribute
of typeDraggableType
defined in the current object property. - I use
serializedObject.ApplyModifiedProperties ();
to apply the movement done by the handle. It also creates an history entry, so you can usectrl+z
to rollback the movement
I think that the result is very cool!
Here's an example:
And here's the complete code example:
https://gist.github.com/ProGM/226204b2a7f99998d84d755ffa1fb39a
I'm using this script for my videogame. Check it out!
Hope you can find it useful!
Written by ProGM
Related protips
1 Response
Very useful script. Here's the updated version. Now it handles Vector2 and arrays as well. Thank you!
https://gist.github.com/RubenPineda/51d0ca3120a89f7fe5080c05905cb80d