-
-
Save ProGM/226204b2a7f99998d84d755ffa1fb39a to your computer and use it in GitHub Desktop.
using System; | |
using UnityEngine; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
#endif | |
public class DraggablePoint : PropertyAttribute {} | |
#if UNITY_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; | |
} | |
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 (); | |
} | |
} | |
} | |
} | |
} | |
#endif |
using UnityEngine; | |
using System.Collections; | |
public class ExampleBehavior : MonoBehaviour { | |
[DraggablePoint] public Vector3 SpawnPosition; | |
public GameObject SpawnableObject; | |
public void Spawn() { | |
Instantiate(SpawnableObject, SpawnPosition, Quaternion.identity); | |
} | |
} |
Here's a quick modification I made up to handle arrays. It gets a bit busy with lots of elements but it does what I need.
Thanks for the original @ProGM !
It's only lightly tested (aka one object with a few points in an array)
using System;
using UnityEngine;
using System.Reflection;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class DraggablePoint : PropertyAttribute { }
#if UNITY_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;
}
public void OnSceneGUI()
{
SerializedProperty property = serializedObject.GetIterator();
while (property.Next(true))
{
if (property.propertyType == SerializedPropertyType.Vector3)
{
handleVectorProperty(property);
}
else if (property.isArray)
{
for (int x = 0; x < property.arraySize; x++)
{
SerializedProperty element = property.GetArrayElementAtIndex(x);
if (element.propertyType != SerializedPropertyType.Vector3)
{
//Break early if we're not an array of Vector3
break;
}
handleVectorPropertyInArray(element, property, x);
}
}
}
}
void handleVectorProperty(SerializedProperty property)
{
FieldInfo field = serializedObject.targetObject.GetType().GetField(property.name);
if (field == null)
{
return;
}
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();
}
}
void handleVectorPropertyInArray(SerializedProperty property, SerializedProperty parent, int index)
{
FieldInfo parentfield = serializedObject.targetObject.GetType().GetField(parent.name);
if (parentfield == null) //Check parent is not null
{
return;
}
var draggablePoints = parentfield.GetCustomAttributes(typeof(DraggablePoint), false);
if (draggablePoints.Length > 0)
{
Handles.Label(property.vector3Value, parent.name + "[" + index + "]"); //Print the Array field name and its index
property.vector3Value = Handles.PositionHandle(property.vector3Value, Quaternion.identity);
serializedObject.ApplyModifiedProperties();
}
}
}
#endif
How can you do the same but for Arrays or Lists of Vector3? Thank you.
Sorry accidentally didn't comment to you directly but have a look at my comment:
https://gist.github.com/ProGM/226204b2a7f99998d84d755ffa1fb39a#gistcomment-3266712
Soooo back again.... Made another version that puts handles relative to the parent. So if you move the game object around the handles will move relative to the parent rather than being in world space.
using System;
using UnityEngine;
using System.Reflection;
#if UNITY_EDITOR
using UnityEditor;
#endif
///Handles relative to game object
public class DraggablePointRelative : PropertyAttribute { }
#if UNITY_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;
}
public void OnSceneGUI()
{
SerializedProperty property = serializedObject.GetIterator();
while (property.Next(true))
{
if (property.propertyType == SerializedPropertyType.Vector3)
{
handleVectorProperty(property);
}
else if (property.isArray)
{
for (int x = 0; x < property.arraySize; x++)
{
SerializedProperty element = property.GetArrayElementAtIndex(x);
if (element.propertyType != SerializedPropertyType.Vector3)
{
//Break early if we're not an array of Vector3
break;
}
handleVectorPropertyInArray(element, property, x);
}
}
}
}
void handleVectorProperty(SerializedProperty property)
{
FieldInfo field = serializedObject.targetObject.GetType().GetField(property.name);
if (field == null)
{
return;
}
var draggablePoints = field.GetCustomAttributes(typeof(DraggablePoint), false);
if (draggablePoints.Length > 0)
{
Handles.Label(property.vector3Value + ((MonoBehaviour)target).transform.position, property.name);
property.vector3Value = Handles.PositionHandle(property.vector3Value + ((MonoBehaviour)target).transform.position, Quaternion.identity) - ((MonoBehaviour)target).transform.position;
serializedObject.ApplyModifiedProperties();
}
}
void handleVectorPropertyInArray(SerializedProperty property, SerializedProperty parent, int index)
{
FieldInfo parentfield = serializedObject.targetObject.GetType().GetField(parent.name);
if (parentfield == null)
{
return;
}
var draggablePoints = parentfield.GetCustomAttributes(typeof(DraggablePoint), false);
if (draggablePoints.Length > 0)
{
Handles.Label(property.vector3Value + ((MonoBehaviour)target).transform.position, parent.name + "[" + index + "]");
property.vector3Value = Handles.PositionHandle(property.vector3Value + ((MonoBehaviour)target).transform.position, Quaternion.identity) - ((MonoBehaviour)target).transform.position;
serializedObject.ApplyModifiedProperties();
}
}
}
#endif
public class DraggablePoint : PropertyAttribute {}
should not be defined in a script inside the Editor
folder but somewhere inside a Script
or Assets
folder. Otherwise you'll be forced to place all the script using this inside the Editor
folder
I realise I'm replying a year and a half later, but I'm trying to adapt this to be able to edit Vector3 arrays in scriptable objects. I'm using SOs to generate spawn points for a mobile game and being able to edit them quickly in the scene view would be useful, rather than doing so in the inspector.
I'm assuming I need to use the OnOpenAsset to access assets as opposed to game objects but I keep hitting brick walls. Anybody managed to do this?
How can you do the same but for Arrays or Lists of Vector3? Thank you.