Search Unity

Finding all states and transitions using a parameter in the editor

Discussion in 'Animation' started by 00christian00, Nov 30, 2018.

  1. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    I can't find anything on the forum, but I think this should be a common problem.
    Is there any built in way or assets that let you view where a parameter is used in an animator controller?
    Sometime when I look at medium complexity controllers made months ago I can't remember how exactly it's setup and where each parameter is used.
    Isn't there a way to look it up?
    Nobody wrote a script or asset that do it?
     
  2. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    I adapted some old editor script I had. It's very ugly but it works in case somebody need it.
    I removed some personal methods but it should work anyway.
    It's made super quickly so don't complain if it's not proper :p

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using UnityEditor.Animations;
    5. using System.Collections.Generic;
    6. public class AnimatorControllerBrowser : EditorWindow {
    7.    
    8.     List<string> Parameters;
    9.     GameObject SelectedGO;
    10.     [MenuItem("Tools/AnimatorControllerBrowser")]
    11.     public static void ShowWindow() {
    12.         EditorWindow.GetWindow(typeof(AnimatorControllerBrowser));
    13.     }
    14.     public void OnGUI() {
    15.         if (GUILayout.Button("List all Animator States")) {
    16.             FindInSelected();
    17.         }
    18.         GUILayout.Space(10);
    19.         if (GUILayout.Button("Find Parameters"))
    20.         {
    21.             FindParameters();
    22.         }
    23.         GUILayout.Space(10);
    24.         if (Parameters!=null)
    25.         {
    26.             foreach (string paramname in Parameters)
    27.             {
    28.                 if (GUILayout.Button(paramname))
    29.                 {
    30.                     ListStateUsingParameter(paramname);
    31.                 }
    32.             }
    33.         }
    34.        
    35.     }
    36.     void FindParameters()
    37.     {
    38.         GameObject g= Selection.activeGameObject;
    39.         if (g == null) g = SelectedGO;
    40.         if (g == null)
    41.         {
    42.             Debug.Log("Nothing selected");
    43.             return;
    44.         }
    45.             AnimatorController ac = g.GetComponent<Animator>().runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
    46.         if (ac == null) return;
    47.         SelectedGO = g;
    48.         Parameters = new List<string>();
    49.         Parameters.Clear();
    50.         foreach (AnimatorControllerParameter parameter in ac.parameters)
    51.         {
    52.             Parameters.Add(parameter.name);
    53.         }
    54.     }
    55.         void ListStateUsingParameter(string ParamName)
    56.     {
    57.         //LogMan.ClearConsole();
    58.         List<Object> selected = new List<Object>(); ;
    59.         GameObject g = Selection.activeGameObject;
    60.         if (g == null) g = SelectedGO;
    61.         if (g == null)
    62.         {
    63.             Debug.Log("Nothing selected");
    64.             return;
    65.         }
    66.         AnimatorController ac = g.GetComponent<Animator>().runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
    67.         if (ac == null) return;
    68.         SelectedGO = g;
    69.         bool Found = false;
    70.         // Number of layers:
    71.         int layerCount = ac.layers.Length;
    72.            // Debug.Log(string.Format("Layer Count: {0}", layerCount));
    73.             // Names of each layer:
    74.             for (int layer = 0; layer < layerCount; layer++)
    75.             {
    76.                // Debug.Log(string.Format("Layer {0}: {1}", layer, ac.layers[layer].name));
    77.                 // States on layer 0:
    78.                 AnimatorStateMachine sm = ac.layers[layer].stateMachine;
    79.                 for (int i = 0; i < sm.states.Length; i++)
    80.                 {
    81.                     AnimatorState state = sm.states[i].state;
    82.                    
    83.                     foreach (AnimatorStateTransition trans in state.transitions)
    84.                     {
    85.                         foreach(AnimatorCondition cond in trans.conditions)
    86.                         {
    87.                         if (cond.parameter == ParamName)
    88.                         {
    89.                             Debug.Log(string.Format("State  {0} is using the parameter {1}", state.name, ParamName));
    90.                             selected.Add(trans);
    91.                             selected.Add(state);
    92.                             Found = true;
    93.                         }
    94.                     }
    95.                     }
    96.                 }
    97.             }
    98.         if (!Found) Debug.LogError("nothing found");
    99.         else
    100.         {
    101.             Selection.objects = selected.ToArray();
    102.         }
    103.        
    104.     }
    105.     private static void FindInSelected() { // Get a reference to the Animator Controller:
    106.         GameObject[] go = Selection.gameObjects;
    107.         foreach (GameObject g in go) {
    108.             UnityEditor.Animations.AnimatorController ac = g.GetComponent<Animator>().runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
    109.             // Number of layers:
    110.             int layerCount = ac.layers.Length;
    111.             Debug.Log(string.Format("Layer Count: {0}", layerCount));
    112.             // Names of each layer:
    113.             for (int layer = 0; layer < layerCount; layer++) {
    114.                 Debug.Log(string.Format("Layer {0}: {1}", layer, ac.layers[layer].name));
    115.                 // States on layer 0:
    116.                 UnityEditor.Animations.AnimatorStateMachine sm = ac.layers[layer].stateMachine;
    117.                 for (int i = 0; i < sm.states.Length; i++) {
    118.                     UnityEditor.Animations.AnimatorState state = sm.states[i].state;
    119.                     Debug.Log(string.Format("State: {0}", state.name));
    120.                 }
    121.             }
    122.         }
    123.     }
    124. }
    125.  
     
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    That script is essentially what I'd suggest to answer your question, but you might be interested in trying out my Animancer plugin which gives you a system that doesn't depend on pre-made parameters or transitions at all so you would avoid the problem entirely.
     
  4. joe_ftg

    joe_ftg

    Joined:
    Nov 9, 2015
    Posts:
    50
    The above code didn't quite work for me, because it doesn't recurse through the tree, so I've extended it. It also shows parameters used by in states (e.g. speed multiplier) and blend trees. I've also added a separate tab to list all the animation clips used (and by which states).

    Hopefully it helps someone else searching for the same reason :)

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEditor.Animations;
    4. using System.Collections.Generic;
    5.  
    6. public class AnimatorControllerBrowser : EditorWindow
    7. {
    8.     AnimatorController _selectedAnimatorController;
    9.  
    10.     List<string> _layers;
    11.  
    12.     List<string> _parameterNames;
    13.     string _currentParameterInfo;
    14.  
    15.     List<string> _stateNames;
    16.     List<string> _stateInfoList;
    17.     string _currentStateInfo;
    18.  
    19.     Dictionary<AnimationClip, string> _animClipDictionary;
    20.     string _currentAnimClipInfo;
    21.  
    22.     Vector2 _scrollPosParamList;
    23.     Vector2 _scrollPosParamInfo;
    24.     Vector2 _scrollPosStateList;
    25.     Vector2 _scrollPosAnimClipList;
    26.     Vector2 _scrollPosAnimClipInfo;
    27.  
    28.     enum BrowserFilter
    29.     {
    30.         Parameters,
    31.         States,
    32.         Animations,
    33.     }
    34.     string[] k_browserFilterStrings = new string[] { "Parameters", "States", "Animations" };
    35.     BrowserFilter _currentBrowserFilter = BrowserFilter.Parameters;
    36.  
    37.     // ------------------------------------------------------------------------
    38.  
    39.     [MenuItem( "Tools/Animator/Animator Controller Browser" )]
    40.     public static void ShowWindow()
    41.     {
    42.         EditorWindow.GetWindow( typeof( AnimatorControllerBrowser ) );
    43.     }
    44.  
    45.     // ------------------------------------------------------------------------
    46.  
    47.     public void OnGUI()
    48.     {
    49.         AnimatorController previousAnimatorController = _selectedAnimatorController;
    50.         EditorGUILayout.BeginHorizontal();
    51.         _selectedAnimatorController = (AnimatorController)EditorGUILayout.ObjectField( "Animator", _selectedAnimatorController, typeof( AnimatorController ), true );
    52.         if ( GUILayout.Button( "Refresh", GUILayout.MaxWidth( 150.0f ) ) || _selectedAnimatorController != previousAnimatorController )
    53.         {
    54.             Refresh();
    55.         }
    56.         EditorGUILayout.EndHorizontal();
    57.         GUILayout.Space( 10 );
    58.  
    59.         _currentBrowserFilter = (BrowserFilter)GUILayout.Toolbar( (int)_currentBrowserFilter, k_browserFilterStrings, GUILayout.MaxWidth( 700.0f ) );
    60.         GUILayout.Space( 10 );
    61.         if ( _currentBrowserFilter == BrowserFilter.Parameters )
    62.         {
    63.             if ( _parameterNames != null )
    64.             {
    65.                 _scrollPosParamList = GUILayout.BeginScrollView( _scrollPosParamList, GUILayout.MinHeight( 500 ), GUILayout.MaxWidth( 700.0f ) );
    66.  
    67.                 foreach ( string paramname in _parameterNames )
    68.                 {
    69.                     if ( GUILayout.Button( paramname ) )
    70.                     {
    71.                         SetParameterInfo( paramname );
    72.                     }
    73.                 }
    74.                 GUILayout.EndScrollView();
    75.                 GUILayout.Space( 10 );
    76.  
    77.                 if ( _currentParameterInfo != null )
    78.                 {
    79.                     _scrollPosParamInfo = GUILayout.BeginScrollView( _scrollPosParamInfo, GUILayout.MinHeight( 250 ), GUILayout.MaxWidth( 700.0f ) );
    80.  
    81.                     EditorGUILayout.LabelField( _currentParameterInfo, EditorStyles.wordWrappedLabel );
    82.  
    83.                     GUILayout.EndScrollView();
    84.                 }
    85.             }
    86.         }
    87.         else if ( _currentBrowserFilter == BrowserFilter.States )
    88.         {
    89.             if ( _stateNames != null )
    90.             {
    91.                 _scrollPosStateList = GUILayout.BeginScrollView( _scrollPosStateList, GUILayout.MinHeight( 500 ), GUILayout.MaxWidth( 700.0f ) );
    92.  
    93.                 for ( int i = 0; i < _stateNames.Count; i++ )
    94.                 {
    95.                     if ( GUILayout.Button( _stateNames[ i ] ) )
    96.                     {
    97.                         _currentStateInfo = _stateInfoList[ i ];
    98.                     }
    99.                 }
    100.                 GUILayout.EndScrollView();
    101.                 GUILayout.Space( 10 );
    102.  
    103.                 if ( _currentStateInfo != null )
    104.                 {
    105.                     EditorGUILayout.LabelField( _currentStateInfo, EditorStyles.wordWrappedLabel, GUILayout.MaxWidth( 700.0f ) );
    106.                 }
    107.             }
    108.         }
    109.         else if ( _currentBrowserFilter == BrowserFilter.Animations )
    110.         {
    111.             if ( _animClipDictionary != null )
    112.             {
    113.                 _scrollPosAnimClipList = GUILayout.BeginScrollView( _scrollPosAnimClipList, GUILayout.MinHeight( 500 ), GUILayout.MaxWidth( 700.0f ) );
    114.  
    115.                 foreach ( AnimationClip clip in _animClipDictionary.Keys )
    116.                 {
    117.                     if ( GUILayout.Button( clip.name ) )
    118.                     {
    119.                         _currentAnimClipInfo = _animClipDictionary[ clip ];
    120.                         Selection.activeObject = clip;
    121.                     }
    122.                 }
    123.                 GUILayout.EndScrollView();
    124.                 GUILayout.Space( 10 );
    125.  
    126.                 if ( _currentAnimClipInfo != null )
    127.                 {
    128.                     _scrollPosAnimClipInfo = GUILayout.BeginScrollView( _scrollPosAnimClipInfo, GUILayout.MinHeight( 250 ), GUILayout.MaxWidth( 700.0f ) );
    129.                     EditorGUILayout.LabelField( _currentAnimClipInfo, EditorStyles.wordWrappedLabel );
    130.                     GUILayout.EndScrollView();
    131.                 }
    132.             }
    133.         }
    134.     }
    135.  
    136.     // ------------------------------------------------------------------------
    137.  
    138.     void Refresh()
    139.     {
    140.         _layers = null;
    141.         _parameterNames = null;
    142.         _currentParameterInfo = null;
    143.         _stateNames = null;
    144.         _currentStateInfo = null;
    145.         _stateInfoList = null;
    146.         _currentAnimClipInfo = null;
    147.         _animClipDictionary = null;
    148.  
    149.         if ( _selectedAnimatorController != null )
    150.         {
    151.             FindLayers();
    152.             FindParameters();
    153.             FindStates();
    154.             FindAnimationClips();
    155.         }
    156.     }
    157.  
    158.     // ------------------------------------------------------------------------
    159.  
    160.     void FindLayers()
    161.     {
    162.         AnimatorController ac = _selectedAnimatorController;
    163.         _layers = new List<string>();
    164.         foreach ( AnimatorControllerLayer layer in ac.layers )
    165.         {
    166.             _layers.Add( layer.name );
    167.         }
    168.     }
    169.  
    170.     // ------------------------------------------------------------------------
    171.  
    172.     void FindParameters()
    173.     {      
    174.         AnimatorController ac = _selectedAnimatorController;
    175.  
    176.         _parameterNames = new List<string>();
    177.         foreach ( AnimatorControllerParameter parameter in ac.parameters )
    178.         {
    179.             _parameterNames.Add( parameter.name );
    180.         }
    181.     }
    182.  
    183.     // ------------------------------------------------------------------------
    184.  
    185.     void SetParameterInfo( string paramName )
    186.     {    
    187.         AnimatorController ac = _selectedAnimatorController;
    188.  
    189.         _currentParameterInfo = paramName + "\n\n";
    190.  
    191.         int layerCount = ac.layers.Length;
    192.         for ( int layer = 0; layer < layerCount; layer++ )
    193.         {
    194.             AddParameterInfoForStateMachine( paramName, ac.layers[ layer ].stateMachine, layer, "" );
    195.         }
    196.     }
    197.  
    198.     // ------------------------------------------------------------------------
    199.  
    200.     void AddParameterInfoForStateMachine( string paramName, AnimatorStateMachine stateMachine, int layer, string parentName )
    201.     {
    202.         for ( int i = 0; i < stateMachine.states.Length; i++ )
    203.         {
    204.             AnimatorState state = stateMachine.states[ i ].state;
    205.  
    206.             if ( state.motion != null )
    207.             {
    208.                 AddParameterInfoForBlendTree( paramName, state.motion, parentName + state.name + '\\' );
    209.             }
    210.  
    211.             if ( state.timeParameterActive && state.timeParameter == paramName )
    212.             {
    213.                 _currentParameterInfo += string.Format( "Time parameter in state {0} \n", parentName + state.name );
    214.             }
    215.             if ( state.mirrorParameterActive && state.mirrorParameter == paramName )
    216.             {
    217.                 _currentParameterInfo += string.Format( "Mirror parameter in state {0} \n", parentName + state.name );
    218.             }
    219.             if ( state.cycleOffsetParameterActive && state.cycleOffsetParameter == paramName )
    220.             {
    221.                 _currentParameterInfo += string.Format( "Cycle parameter in state {0} \n", parentName + state.name );
    222.             }
    223.             if ( state.speedParameterActive && state.speedParameter == paramName )
    224.             {
    225.                 _currentParameterInfo += string.Format( "Speed parameter in state {0} \n", parentName + state.name );
    226.             }
    227.  
    228.             foreach ( AnimatorStateTransition trans in state.transitions )
    229.             {
    230.                 AddParameterInfoForTransition( paramName, trans, parentName + state.name );
    231.             }
    232.         }
    233.  
    234.         foreach ( AnimatorStateTransition trans in stateMachine.anyStateTransitions )
    235.         {
    236.             AddParameterInfoForTransition( paramName, trans, parentName + stateMachine.name );
    237.         }
    238.  
    239.         foreach ( AnimatorTransition trans in stateMachine.entryTransitions )
    240.         {
    241.             AddParameterInfoForTransition( paramName, trans, parentName + stateMachine.name );
    242.         }
    243.  
    244.         for ( int i = 0; i < stateMachine.stateMachines.Length; i++ )
    245.         {
    246.             AddParameterInfoForStateMachine( paramName, stateMachine.stateMachines[ i ].stateMachine, layer, parentName + stateMachine.name + '\\' );
    247.         }
    248.     }
    249.  
    250.     // ------------------------------------------------------------------------
    251.  
    252.     void AddParameterInfoForBlendTree( string paramName, Motion motion, string parentName )
    253.     {
    254.         BlendTree blendTree = motion as BlendTree;
    255.         if ( blendTree != null )
    256.         {
    257.             if ( blendTree.blendParameter == paramName || blendTree.blendParameterY == paramName )
    258.             {
    259.                 _currentParameterInfo += string.Format( "BlendTree in {0}\n", parentName + motion.name );
    260.             }
    261.             foreach ( ChildMotion childMotion in blendTree.children )
    262.             {
    263.                 if ( childMotion.motion != null )
    264.                 {
    265.                     AddParameterInfoForBlendTree( paramName, childMotion.motion, parentName + motion.name + '\\' );
    266.                 }
    267.             }
    268.         }
    269.     }
    270.  
    271.     // ------------------------------------------------------------------------
    272.  
    273.     void AddParameterInfoForTransition( string paramName, AnimatorTransitionBase transition, string parentName )
    274.     {
    275.         foreach ( AnimatorCondition cond in transition.conditions )
    276.         {
    277.             if ( cond.parameter == paramName )
    278.             {
    279.                 string destinationName = transition.destinationState != null ? " to " + transition.destinationState.name :
    280.                     ( transition.destinationStateMachine != null ? " to " + transition.destinationStateMachine.name : "" );
    281.                 _currentParameterInfo += string.Format( "Transition at {0}\n", parentName + destinationName );
    282.             }
    283.         }
    284.     }
    285.  
    286.     // ------------------------------------------------------------------------
    287.  
    288.     void FindStates()
    289.     {
    290.         _stateNames = new List<string>();
    291.         _stateInfoList = new List<string>();
    292.  
    293.         AnimatorController ac = _selectedAnimatorController;
    294.  
    295.         int layerCount = ac.layers.Length;
    296.         for ( int layer = 0; layer < layerCount; layer++ )
    297.         {
    298.             FindStatesWithinStateMachine( ac.layers[ layer ].stateMachine, layer, "" );
    299.         }
    300.     }
    301.  
    302.     // ------------------------------------------------------------------------
    303.  
    304.     void FindStatesWithinStateMachine( AnimatorStateMachine stateMachine, int layer, string parentName )
    305.     {
    306.         for ( int i = 0; i < stateMachine.states.Length; i++ )
    307.         {
    308.             AnimatorState state = stateMachine.states[ i ].state;
    309.             _stateNames.Add( state.name );
    310.             _stateInfoList.Add( parentName + state.name + "\n" );
    311.         }
    312.         for ( int i = 0; i < stateMachine.stateMachines.Length; i++ )
    313.         {
    314.             FindStatesWithinStateMachine( stateMachine.stateMachines[ i ].stateMachine, layer, parentName + stateMachine.name + '\\' );
    315.         }
    316.     }
    317.  
    318.     // ------------------------------------------------------------------------
    319.  
    320.     void FindAnimationClips()
    321.     {
    322.         _animClipDictionary = new Dictionary<AnimationClip, string>();
    323.  
    324.         AnimatorController ac = _selectedAnimatorController;
    325.  
    326.         int layerCount = ac.layers.Length;
    327.         for ( int layer = 0; layer < layerCount; layer++ )
    328.         {
    329.             FindAnimationClipsWithinStateMachine( ac.layers[ layer ].stateMachine, layer, "" );
    330.         }
    331.     }
    332.  
    333.     // ------------------------------------------------------------------------
    334.  
    335.     void FindAnimationClipsWithinStateMachine( AnimatorStateMachine stateMachine, int layer, string parentName )
    336.     {
    337.         for ( int i = 0; i < stateMachine.states.Length; i++ )
    338.         {
    339.             AnimatorState state = stateMachine.states[ i ].state;
    340.             FindAnimationClipsInMotion( state.motion, parentName + state.name + '\\' );
    341.         }
    342.         for ( int i = 0; i < stateMachine.stateMachines.Length; i++ )
    343.         {
    344.             FindAnimationClipsWithinStateMachine( stateMachine.stateMachines[ i ].stateMachine, layer, parentName + stateMachine.name + '\\' );
    345.         }
    346.     }
    347.  
    348.     // ------------------------------------------------------------------------
    349.  
    350.     void FindAnimationClipsInMotion( Motion motion, string parentName )
    351.     {
    352.         BlendTree blendTree = motion as BlendTree;
    353.         if ( blendTree != null )
    354.         {
    355.             foreach ( ChildMotion childMotion in blendTree.children )
    356.             {
    357.                 if ( childMotion.motion != null )
    358.                 {
    359.                     FindAnimationClipsInMotion( childMotion.motion, parentName + motion.name + '\\' );
    360.                 }
    361.             }
    362.         }
    363.         AnimationClip animationClip = motion as AnimationClip;
    364.         if ( animationClip != null )
    365.         {
    366.             string animClipInfo;
    367.             if ( !_animClipDictionary.TryGetValue( animationClip, out animClipInfo ) )
    368.             {
    369.                 animClipInfo = AssetDatabase.GetAssetPath( animationClip ) + "\n\n";
    370.                 _animClipDictionary.Add( animationClip, animClipInfo );
    371.             }
    372.             animClipInfo += "Used in " + parentName + "\n";
    373.             _animClipDictionary[ animationClip ] = animClipInfo;
    374.         }
    375.     }
    376.  
    377.     // ------------------------------------------------------------------------
    378. }
    379.  
    380.  
    381.