Vector4 Property Drawers

Hey guys,

Just wanted to post some code I wrote in order to make Vector4’s work with property drawers. Hope you find it helpful.

Cheers,
Tom.

using UnityEngine;

public class CompactAttribute : PropertyAttribute
{
}
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(CompactAttribute))]
public class CompactDrawer : PropertyDrawer
{
	public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
	{
		System.Type objectType = prop.serializedObject.targetObject.GetType();
		System.Type propertyType = objectType.GetField(prop.name).FieldType;
		
		if (propertyType == typeof(Vector4))
		{
			SerializedProperty xProp = prop.FindPropertyRelative("x");
			SerializedProperty yProp = prop.FindPropertyRelative("y");
			SerializedProperty zProp = prop.FindPropertyRelative("z");
			SerializedProperty wProp = prop.FindPropertyRelative("w");
			Vector4 vector4Value = new Vector4(xProp.floatValue, yProp.floatValue, zProp.floatValue, wProp.floatValue);
			
			EditorGUIUtility.LookLikeControls();
			position.x += 4;
			position.width -= 8;
			EditorGUI.BeginChangeCheck();
			vector4Value = EditorGUI.Vector4Field(position, label.text, vector4Value);
			if (EditorGUI.EndChangeCheck())
			{
				xProp.floatValue = vector4Value.x;
				yProp.floatValue = vector4Value.y;
				zProp.floatValue = vector4Value.z;
				wProp.floatValue = vector4Value.w;
			}
		}
		else
		{
			switch (prop.propertyType)
			{
			case SerializedPropertyType.Vector2:
				{
					EditorGUIUtility.LookLikeControls();
					position.x += 4;
					position.width -= 8;
					EditorGUI.BeginChangeCheck();
					Vector2 vector2Value = EditorGUI.Vector2Field(position, label.text, prop.vector2Value);
					if (EditorGUI.EndChangeCheck())
					{
						prop.vector2Value = vector2Value;
					}
				}
				break;
			case SerializedPropertyType.Vector3:
				{
					EditorGUIUtility.LookLikeControls();
					position.x += 4;
					position.width -= 8;
					EditorGUI.BeginChangeCheck();
					Vector3 vector3Value = EditorGUI.Vector3Field(position, label.text, prop.vector3Value);
					if (EditorGUI.EndChangeCheck())
					{
						prop.vector3Value = vector3Value;
					}
				}
				break;
			default:
				{
					Debug.LogError("Compact attribute only works for Vector2, Vector3 and Vector4");
				}
				break;
			}
		}
	}
	
	public override float GetPropertyHeight(SerializedProperty prop, GUIContent label)
	{
		return base.GetPropertyHeight(prop, label) * 2 + 4;
    }
}
2 Likes

Thanks!

You do know that this post is 8+ years old? The SerializedProperty supports Vector4 natively for ages. So there’s no need for a reflection based hack that will break as soon as your property is nested or inside an array.

  • Vector4 did not work with SerializedProperty (or maybe you can show code that does work?)
  • My Vector4’s are in an array and work fine.

Thanks to OP for the post, even being 8 years old, solved the problem with my custom property drawers.

What exactly do you mean by that? What did not work? The SerializedProperty class has a vector4Value, that works exactly like the vector 2 and 3 version. Vector4 values are also natively supported by the default editor / inspector. So what exact issues do you have?

Ok I see the problem. Because I’m rendering a custom property drawer, I need to reference the SerializedProperty not the vector4Value.

Vector4 is Offset & Size:

Calling EditorGUI.FloatField for vector4Value.x did not allow for saving changes made to the float. For this, I had to use
SerializedProperty xProp = property.FindPropertyRelative(“offset”).FindPropertyRelative(“x”);

OP was helpful as I couldn’t figure how to get SerializedProperty of the Vector4 which required calling 2 FindPropertyRelative, first for the custom class and second for the Vector4.