← Zurück


Dirty Unity: Array Einträge im Inspector verschieben

by Totally Not Alex
12. März 2019


Heyho,

heute Mal die Einführung zu einer kleinen Serie: Dirty Unity, in welcher ich zukünftig kleine, nützliche C# Code Snippets teilen werde. Diese Serie richtet sich also an (wer hätte das gedacht?) Unity3D-Entwickler und diejenigen, die Entwickler werden wollen oder einfach nur aus anderen Gründen mit Unity arbeiten. „Dirty Unity“ heißt das Ganze deswegen, weil die Lösungen häufig nicht die elegantesten oder performantesten sind und weil sie Probleme lösen, die es wohl gar nicht in Unity geben sollte.

Thema heute ist ein Editor Skript, welches Context Menu Einträge für Array Elemente im Inspector hinzufügt, die es ermöglichen das Element im Array zu verschieben. Das Ganze sieht dann bei Rechtsklick wie folgt aus:

Verrückter Twist dabei: „Down“ und „Up“ bedeutet, dass sich das Element um einen Index nach oben/unten bewegt und sich daher in der Hierarchie andersrum bewegt. Wow, so unintuitive!

using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace AlienCore
{
	public static class MoveArrayElementEditor
	{
		[InitializeOnLoadMethod]
		static void Start ()
		{
			// For more information visit: https://docs.unity3d.com/ScriptReference/EditorApplication-contextualPropertyMenu.html
			EditorApplication.contextualPropertyMenu += OnPropertyContextMenu;
		}

		static void OnPropertyContextMenu (GenericMenu menu, SerializedProperty property)
		{
			if (property == null) return;

			// Path of an array is "PropertyName.Array.data[arraylength]", so let's look if the property is an array
			string propertyPath = property.propertyPath;
			if (!propertyPath.Contains (".Array.data[") || !propertyPath.EndsWith ("]")) return;

			// Split the property path and find out the array length
			string[] fullPathSplit = propertyPath.Split ('.');
			string ending = fullPathSplit [fullPathSplit.Length - 1];
			int index = 0;
			if (!int.TryParse (ending.Replace ("data[", "").Replace ("]", ""), out index)) return;

			// Rebuild the path without the ".Array.data[arraylength]" stuff
			string pathToArray = string.Empty;
			for (int i = 0; i < fullPathSplit.Length - 2; i++)
			{
				if (i < fullPathSplit.Length - 3)
				{
					pathToArray = string.Concat (pathToArray, fullPathSplit [i], ".");
				}
				else
				{
					pathToArray = string.Concat (pathToArray, fullPathSplit [i]);
				}
			}

			// Get the serialized target object and the property of the array with the path
			Object targetObject = property.serializedObject.targetObject;
			SerializedObject serializedTargetObject = new SerializedObject (targetObject);

			SerializedProperty serializedArray = serializedTargetObject.FindProperty (pathToArray);
			int arrayLength = serializedArray.arraySize;

			if (serializedArray == null) return;

			// Show context menu entry only if the user can move it up or down
			if (index > 0)
			{
				menu.AddItem (new GUIContent ("Move Array Element Down"), false,
				              () => MoveDown (serializedTargetObject, serializedArray, index));
			}

			if (index < arrayLength - 1)
			{
				menu.AddItem (new GUIContent ("Move Array Element Up"), false,
				              () => MoveUp (serializedTargetObject, serializedArray, index));
			}
		}

		static public void MoveDown (SerializedObject target, SerializedProperty array, int index)
		{
			array.MoveArrayElement (index, index - 1);
			target.ApplyModifiedProperties ();
		}

		static public void MoveUp (SerializedObject target, SerializedProperty array, int index)
		{
			array.MoveArrayElement (index, index + 1);
			target.ApplyModifiedProperties ();
		}
	}
}

Der Code steht selbstverständlich zur freien Nutzung!




← Zurück