Show a draggable point into the scene linked to a Vector3 field using the Handle API in Unity Editor

ProGM
2 min readFeb 11, 2018

--

I’m always searching for new ways to improve the editing within the editor in Unity. One common issue in my projects is: making it easier to define the coordinates of a Serialized field that represents a point in the scene (i.e. a serialized Vector3)

For instance, assuming I have a script that spawns a certain prefab in the scene in 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 is to make easier to move the SpawnPosition point inside the Scene.

My first approach was to use the OnGizmosSelected method, showing a colored sphere in the scene editor, to indicate the point position, then change manually the Vector3 values until I achieve the correct position. However, it wasn’t very comfortable to edit.

Inspecting this great plugin sources, I discovered the Unity Editor’s Handles API, a set of methods to spawn interactable objects within the scene, like points, resizable shapes and more.

So I tried to define a custom editor script to show a Handle on generic points, so I can reuse it in many scripts easily.

Here’s how I did it:

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 a 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 to CustomEditor. This says to unity to instantiate this Editor script to all classes that inherit 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 type DraggableType defined in the current object property.
  • I use serializedObject.ApplyModifiedProperties (); to apply the movement done by the handle. It also creates a history entry, so you can use ctrl+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 videogames. Check it out!
Hope you can find it useful!

--

--

ProGM

Web Developer in the day, Game Developer in the night. Cofounder at https://monade.io & Founder @elfgamesworks http://elfgame.com