Search Unity

Animator parameter to Custom Editor

Discussion in 'Animation' started by share_gamerz_ID, Mar 31, 2020.

  1. share_gamerz_ID

    share_gamerz_ID

    Joined:
    Mar 19, 2019
    Posts:
    12
    Hi guys. I am writing an editor script, I am getting value from animator and retrieve all parameters and convert them in enum. Everything is working fine except to one major bug.
    this code runs in OnEnable of my editor script
    Code (CSharp):
    1. AnimatorControllerParameter[] parameters = scriptTarget.Animations.animator.parameters;
    2.             animatorParameters = new string[scriptTarget.Animations.animator.parameterCount];
    3.             selectedParameter = new int[scriptTarget.Animations.animator.parameterCount];
    4.             for (int x = 0; x < parameters.Length; x++)
    5.             {
    6.                 animatorParameters[x] = parameters[x].name;
    7.             }
    this code gives me all parameters and cache in array. Looks Good.
    then I convert that in enum.
    Code (CSharp):
    1. string DrawParameter(string parameterName, string[] data, int index)
    2.         {
    3.             EditorGUILayout.BeginVertical();
    4.             GUILayout.Space(2);
    5.             EditorGUILayout.BeginHorizontal();
    6.             EditorGUILayout.LabelField(parameterName);
    7.             selectedParameter[index] = EditorGUILayout.Popup(selectedParameter[index], data);
    8.             EditorGUILayout.EndHorizontal();
    9.             EditorGUILayout.EndVertical();
    10.             return data[selectedParameter[index]];
    11.         }
    this return me string and I draw parameter.
    Code (CSharp):
    1. scriptTarget.Animations.ForwardParameter = DrawParameter("Forward", animatorParameters, 0);
    So as far as I works fine.

    The BUG came when I add new parameter in animator.
    Code (CSharp):
    1. scriptTarget.Animations.animator.parameters
    this parameter return me zero size.
    Why?
    No idea how!!!
    Anyone have any clue?
     
  2. share_gamerz_ID

    share_gamerz_ID

    Joined:
    Mar 19, 2019
    Posts:
    12
    Edit : When i recompile code then
    Code (CSharp):
    1. scriptTarget.Animations.animator.parameters
    this code return actual amount, otherwise 0.
    Seems like bug in animator component, or maybe bug in code.:(
     
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Animator Controllers aren't designed to be accessed in Edit Mode so there are some things you just won't be able to do. Try using
    animator.runtimeAnimatorController as UnityEditor.AnimatorController;
    which might give you access to what you need.
     
  4. share_gamerz_ID

    share_gamerz_ID

    Joined:
    Mar 19, 2019
    Posts:
    12
    Runtime animator controller doesn't give me parameters so i can't access parameters of animator. Documentation of Runtime animator while animator component have parameters array.

    As I need to populate animator parameters into drop down. So:(
     
    Last edited: Apr 2, 2020
  5. altan86

    altan86

    Joined:
    Feb 6, 2018
    Posts:
    10
    @Kybernetik seem to just point out a clue but not how to utilize UnityEditor.Animations.AnimatorController in any manner, so I will complete his answer. Besides its not really a bug since it can be resolved via UnityEditor.Animations.AnimatorController.

    Let me give a brief outlook of what the issue is:
    Reading UnityEngine.Animator.parameters after a parameter is added/removed via the Animator window will result in an empty array. The array will refresh after a scene is loaded or after scripts are compiled. I suspect this is due to how some UnityEngine scripts do not necessarily update in realtime in Editor Mode.

    Solution:
    In order to get the refreshed parameters in realtime and in Editor Mode after adding/removing a parameter via the Animator window, you will need to load the AnimatorController asset (asset with .controller extension) using AssetDatabase.LoadAssetAtPath().
    Since you have the controller reference from Animator.runtimeAnimatorController (type RuntimeAnimatorController), then it a matter of finding its path and loading it as a UnityEditor.Animations.AnimatorController using AssetDatabase.GetAssetPath().
    So it will look like this:
    Code (CSharp):
    1. AnimatorController editorController = (AnimatorController)AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath([your Animator reference].runtimeAnimatorController), typeof(AnimatorController));
    After that you can access the parameters using editorController.parameters and the array values in it will refresh each time there is a change in the Animator parameters.

    Hope this helps!

    Some references: https://docs.unity3d.com/ScriptReference/Animations.AnimatorController.html
     
    theStiggler, crafTDev, EZaca and 2 others like this.
  6. MartyMcFly

    MartyMcFly

    Joined:
    May 2, 2013
    Posts:
    17
    It helped ME. Thanks so much for this, altan86!
     
  7. theStiggler

    theStiggler

    Joined:
    Oct 21, 2013
    Posts:
    7
    Apologies for necro-ing the thread but just wanted to add some useful further info to @altan86 's answer. I was writing a script for a custom editor for setting any float parameter for an attached animator, but was having trouble getting changes to save - which led me here.
    Some of the game objects I am targeting with this script use Animator Override Controllers rather than Animator Controllers, which meant there were a few extra steps to getting altan's method to work.

    Code (CSharp):
    1. // get animator component
    2.         animatorComponent = script.gameObject.GetComponent<Animator>();
    3.  
    4.         // get the runtime animator controller
    5.         RuntimeAnimatorController runtimeController = animatorComponent.runtimeAnimatorController;
    6.  
    7.         // if it is an override controller we need to get the base controller
    8.         if (runtimeController.GetType() == typeof(AnimatorOverrideController))
    9.         {
    10.             AnimatorOverrideController overrideController = (AnimatorOverrideController)runtimeController;
    11.             // runtimeAnimatorController of an AnimatorOverrideController is the base controller
    12.             runtimeController = overrideController.runtimeAnimatorController;
    13.         }
    14.  
    15.         // load the .controller file as a UnityEditor.Animations.AnimatorController
    16.         // this allows for updating of floatParamNames in Edit Mode
    17.         AnimatorController editorController =
    18.             (AnimatorController)AssetDatabase.LoadAssetAtPath(AssetDatabase.GetAssetPath(runtimeController), typeof(AnimatorController));
    Basically it's just a check on the Type of the runtime animation controller once you get it from the Animator component. Not too complicated but took some searching to find the solution, may save someone some time!
     
    hamza_unity995 likes this.