Last active
February 29, 2024 16:02
-
-
Save FleshMobProductions/6d520cf36ea0cf8d4172baf373bef500 to your computer and use it in GitHub Desktop.
Unity PropertyDrawer for selecting animation state names of AnimationControllers in the inspector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Place file in your main project, outside of an Editor folder | |
using UnityEngine; | |
namespace FMPUtils.Types | |
{ | |
[System.Serializable] | |
public class AnimationStateNameSelection | |
{ | |
public Animator animator; | |
public string animationName; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Place file in your project, inside of an "Editor" folder | |
using FMPUtils.Types; | |
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEditor.Animations; | |
using UnityEngine; | |
namespace FMPUtils.Editor | |
{ | |
[CustomPropertyDrawer(typeof(AnimationStateNameSelection))] | |
public class AnimationStateNameSelectionDrawer : PropertyDrawer | |
{ | |
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) | |
{ | |
return EditorGUIUtility.singleLineHeight * 2f; | |
} | |
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) | |
{ | |
EditorGUI.BeginProperty(position, GUIContent.none, property); | |
SerializedProperty animatorProp = property.FindPropertyRelative(nameof(AnimationStateNameSelection.animator)); | |
SerializedProperty animationNameProp = property.FindPropertyRelative(nameof(AnimationStateNameSelection.animationName)); | |
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); | |
Rect line1Rect = position; // Assignment copy since this is a struct | |
line1Rect.height = EditorGUIUtility.singleLineHeight; | |
Rect line1PrefixRect = line1Rect; | |
float animatorPrefixLabelWidth = 80f; | |
line1PrefixRect.width = animatorPrefixLabelWidth; | |
Rect line1ValueRect = line1Rect; | |
line1ValueRect.x = line1PrefixRect.x + line1PrefixRect.width; | |
line1ValueRect.width = line1Rect.width - line1PrefixRect.width; | |
EditorGUI.LabelField(line1PrefixRect, "Animator"); | |
animatorProp.objectReferenceValue = EditorGUI.ObjectField(line1ValueRect, animatorProp.objectReferenceValue, typeof(Animator), true); | |
if (animatorProp.objectReferenceValue != null) | |
{ | |
// Adjust the rect to draw contents one line below: | |
Rect line2Rect = position; | |
line2Rect.height = EditorGUIUtility.singleLineHeight; | |
line2Rect.y = position.y + EditorGUIUtility.singleLineHeight; | |
List<string> stateNames = new List<string>(); | |
string prevAnimationName = animationNameProp.stringValue; | |
Animator animator = animatorProp.objectReferenceValue as Animator; | |
AnimatorController animatorController = animator.runtimeAnimatorController as AnimatorController; | |
// TODO: since there can be multiple animation layers it would be good to offer an additional dropdown for the layer selection | |
// before selecting the animation state name. | |
// States of substate machines seem to be included too but perhaps explore a way to better display/visualize it | |
AnimatorControllerLayer[] layers = animatorController.layers; | |
foreach (AnimatorControllerLayer layer in layers) | |
{ | |
foreach (ChildAnimatorState state in layer.stateMachine.states) | |
{ | |
string stateName = state.state.name; | |
if (!stateNames.Contains(stateName)) | |
stateNames.Add(stateName); | |
} | |
} | |
if (stateNames.Count == 0) | |
{ | |
EditorGUI.LabelField(line2Rect, "No states in AnimationController found"); | |
} | |
else | |
{ | |
int selectedIndex = stateNames.IndexOf(prevAnimationName); | |
if (selectedIndex == -1) | |
selectedIndex = 0; | |
selectedIndex = EditorGUI.Popup(line2Rect, "State Name", selectedIndex, stateNames.ToArray()); | |
if (selectedIndex >= 0) | |
{ | |
animationNameProp.stringValue = stateNames[selectedIndex]; | |
} | |
else | |
{ | |
animationNameProp.stringValue = string.Empty; | |
} | |
} | |
} | |
EditorGUI.EndProperty(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment