by
Totally Not Alex
12. March 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!