Search Unity

Mecanim - Change animation speed of specific animation or layers

Discussion in 'Animation' started by Rico21745, Nov 27, 2012.

  1. Ferb

    Ferb

    Joined:
    Jan 4, 2014
    Posts:
    20
    That's what I came here looking to find out how to do, and Arnleif's solution worked for me. If what you want to change the speed of is more complicated than a simple animation clip, you can make a blendtree (call it 'SpeedBlend') that blends between two identical blendtrees (call them BasicBlendA and BasicBlendB), but with the speed of everything in BasicBlendA set to 0 and the speed of everything in BasicBlendB set to 1, then having SpeedBlend blend between the two by some float parameter. If necessary, you could do this with everything on an animation layer, all using the same parameter - then that parameter will effectively control the speed of that layer.

    I agree such a hacky solution shouldn't be necessary though, and Mecanim is quite lacking in features. (Basic copy and paste functionality in the state machine for instance - while implementing the above solution, you will, as far as I know, have to make two copies of the BasicBlend blendtree manually; I can copy and paste single animation clips, but not a blendtree or a group of clips with transitions.)
     
    bluescrn likes this.
  2. japoilski

    japoilski

    Joined:
    Feb 23, 2015
    Posts:
    6
    Solution!
    Change clip speed of any layer.

    UnityEditorInternal.AnimatorController ac = animator.runtimeAnimatorController as UnityEditorInternal.AnimatorController;

    UnityEditorInternal.StateMachine sm = ac.GetLayer(1).stateMachine;
    for (int i = 0; i < sm.stateCount; i++)
    {
    UnityEditorInternal.State state = sm.GetState(i);
    state.speed = 2;
    Debug.Log(state.uniqueName + " " + state.speed);
    }

    This is just an example. Modify it to make it work with your code.
     
  3. japoilski

    japoilski

    Joined:
    Feb 23, 2015
    Posts:
    6
    Here are some functions that you guys can you use. (NOT TESTED)

    void SetAnimSpeedWithClipTag(int layer, string tag, float speed)
    {
    UnityEditorInternal.AnimatorController ac = animator.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
    UnityEditorInternal.StateMachine sm = ac.GetLayer(layer).stateMachine;
    for (int i = 0; i < sm.stateCount; i++)
    {
    UnityEditorInternal.State state = sm.GetState(i);
    if (state.tag == tag) //Change speed for all clip with the tag specified
    state.speed = speed;
    }
    }

    void SetAnimSpeedWithClipName(int layer, string name, float speed)
    {
    UnityEditorInternal.AnimatorController ac = animator.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
    UnityEditorInternal.StateMachine sm = ac.GetLayer(layer).stateMachine;
    for (int i = 0; i < sm.stateCount; i++)
    {
    UnityEditorInternal.State state = sm.GetState(i);
    if (state.uniqueName == name) //Change speed for only the clip name specified
    state.speed = speed;
    }
    }

    void SetAnimSpeedOfLayer(int layer, float speed)
    {
    UnityEditorInternal.AnimatorController ac = animator.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
    UnityEditorInternal.StateMachine sm = ac.GetLayer(layer).stateMachine;
    for (int i = 0; i < sm.stateCount; i++)
    {
    //Change speed for all animation state in the layer
    UnityEditorInternal.State state = sm.GetState(i);
    state.speed = speed;
    }
    }
     
  4. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    491
    UnityEditorInternal?

    I wouldn't expect that to work outside of the editor...
     
  5. japoilski

    japoilski

    Joined:
    Feb 23, 2015
    Posts:
    6
    Good point! It will only work in the editor -_-
     
  6. gsus725

    gsus725

    Joined:
    Aug 23, 2010
    Posts:
    250
  7. gsus725

    gsus725

    Joined:
    Aug 23, 2010
    Posts:
    250
    Guys nevermind Mecanim.Dev messaged me back and says this is being worked on already
     
  8. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,663
    This is a new feature in 5.1

    Take a look a the documentation

    Runtime Animator State Properties

    Overview
    This feature, introduced in Unity 5.1, allows users to attach any of their Animator State properties( speed, mirror, cycle offset) as a controller’s parameter to change their value at runtime.

    Properties can either be exposed by using the Animator State Inspector or by script.


    Editor
    The Animator State Inspector has been improved to let you build your own properties setup.





    For each property you can choose to either:

    1. Set a constant value like before.

    2. Check the new checkbox ‘Parameter’ which should change the numeric field to a popup list containing all your controller’s parameters of the same type as the property. Choosing one parameter to drive your property will complete the setup.




    Scripting
    We have also added new properties to allow you to build your setup from script.

    The 3 following new members are used to define which of the controller’s parameters should control this property.

    string AnimatorState.speedParameter;
    string AnimatorState.mirrorParameter;
    string AnimatorState.cycleOffsetParameter;

    The following members are used to define if the controller should use the parameter to animate that property or not.

    bool AnimatorState.speedParameterActive;
    bool AnimatorState.mirrorParameterActive;
    bool AnimatorState.cycleOffsetParameterActive;

    Error Handling
    If the parameter cannot be found in the controller’s parameters list or if the parameter type doesn’t match the type of the property, a console warning should be thrown and the property would fallback to the old behaviour, which is to read the value from the constant.
     
  9. danielshae

    danielshae

    Joined:
    Mar 4, 2015
    Posts:
    1
    And all the people said, "Thanks, Unity. We take the mean stuff back now."
     
    Jroel and daterre like this.
  10. japoilski

    japoilski

    Joined:
    Feb 23, 2015
    Posts:
    6
    Nice!! I'll be waiting for this feature.
     
  11. MidgardDev

    MidgardDev

    Joined:
    Dec 11, 2012
    Posts:
    46
    I will be too. Happy to see that you guys actually got a solution for us :)

    Better late than never.
     
  12. eyalfx

    eyalfx

    Joined:
    Oct 8, 2010
    Posts:
    98
    Great. looking forward to the next release.
    And hacking it in the meantime :)
     
  13. chichom27

    chichom27

    Joined:
    Jun 18, 2013
    Posts:
    3
    So, did this change make it ti 5.1?
     
  14. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,393
    It's in, yes, and seems to be working. I thought it wasn't working, but the animator only shows one decimal for it's float parameters, which makes it hard to tell that a script has updated the "AnimSpeed" variable from 1 to 1.02.
     
  15. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,663
    Yes it's in but we did fix a few bug so you may want to update to 5.1.1 or any most recent released version
     
  16. Wurghi

    Wurghi

    Joined:
    Apr 11, 2013
    Posts:
    39
    the first 3d engine i used, about 12 years ago had an easy script-way to handle the animationspeed in percent. like 0 means start of walk cycle and 100 the end and everything inbetween is interpolated. It was incredible handy and easy... now i have this. How would i get something like that? Get the state, get the animation from the state, read the length of the animation(is this even possible???), set the parameter of the animation to a calculated percentage?... And what if i want to jump from 20% of the animation to 70% ? Does it mean i have to increase the speed alot for a very short time to get a fast forward?
     
  17. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,544
    Ha, well, after all this, does anyone have a simple code snippet for changing an individual States speed?

    Thanks
     
  18. Alima-Studios

    Alima-Studios

    Joined:
    Nov 12, 2014
    Posts:
    47
    In unity 5.0.3f2, animator.layers[intex] or Getlayer(index) seems to be missing

    is there any way to chage the motion clip of the state at runtime by code ¿?
     
  19. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,663
  20. jrDev

    jrDev

    Joined:
    Nov 5, 2008
    Posts:
    1,677
    So how do I go about scripting this? How do I add a parameter and set through script?

    Thanks,
    jrDev
     
  21. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,663
    If you mean have a script that automate this in the editor,

    you need first to add a parameter in your controller
    http://docs.unity3d.com/ScriptReference/Animations.AnimatorController.AddParameter.html

    then on the AnimatorState that you would like to change the speed at runtime you need to set both
    http://docs.unity3d.com/ScriptReference/Animations.AnimatorState-speedParameter.html
    http://docs.unity3d.com/ScriptReference/Animations.AnimatorState-speedParameterActive.html
    Code (CSharp):
    1.  
    2. // Creates the controller
    3. var controller = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath("Assets/mycontroller.controller");
    4.  
    5. // Add parameters
    6. controller.AddParameter("stateSpeed", AnimatorControllerParameterType.Float);
    7.  
    8. var rootStateMachine = controller.layers[0].stateMachine;
    9.  
    10. var myState = rootStateMachine.AddState("myState");
    11.  
    12. myState.speedParameter = "stateSpeed";
    13. myState.speedParameterActive = true;
    14.  
     
  22. jrDev

    jrDev

    Joined:
    Nov 5, 2008
    Posts:
    1,677
    This is what I was looking for. I'll try this out.

    Thanks,
    jrDev
     
  23. jrDev

    jrDev

    Joined:
    Nov 5, 2008
    Posts:
    1,677
    Hey again Mecanim.Dev,

    So I've been trying to change the value of the parameter in editor script but it won't update it until I am in play mode. Is this a bug? I mean, if I use GetFloat() it gives the correct value I set previously. Also changing the parameter value doesn't change the state speed that I linked it to...any help?

    Edit: Nevermind, I just realized the parameter is just a multiplier of the state speed and it is not just copying the value, its doing parametervalue*stateSpeed...so to get 3 times the speed per the parameter value, each state must have its default set to 1. If the state speed is set to 2, that would mean a speed of 6 for the state.

    Edit2: I still need to know why the parameter value doesn't update in edit mode.

    Thanks,
    jrDev
     
    Last edited: Feb 24, 2016
  24. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,663
  25. jrDev

    jrDev

    Joined:
    Nov 5, 2008
    Posts:
    1,677
    Ok, is there any plans to add this? Currently it is slightly off-putting with my editor script set to adjust the parameter values but they don't update of course until the game starts. I can clearly do it manually in edit mode, so it's not like it is completely restricted, why not allow scripting it too in edit mode?

    Also, I am trying to change the name of a parameter through script, this doesn't seem to work though for some reason?

    Code (CSharp):
    1. animatorController.parameters[0].name = "New Name";
    Thanks for the responses,
    jrDev
     
  26. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,663
    I'm not sure I understand what you are actually trying to achieve? can you give us more detail on what you would like to do while in edit mode?

    yes this is expected as seen in the doc
    http://docs.unity3d.com/ScriptReference/Animations.AnimatorController-parameters.html
     
  27. jrDev

    jrDev

    Joined:
    Nov 5, 2008
    Posts:
    1,677
    Hey,

    I just want to be able to modify the Parameter values and see the change with having to be in play mode. Just for visual readability sake. I have an editor changing the parameter values but you can only see the speed parameter change when in play mode.

    Thanks,
    jrDev
     
  28. gevarre

    gevarre

    Joined:
    Jan 19, 2009
    Posts:
    132
    For those of you (like me) that are (A) still reading this very old thread, and (B) still confused with all the different bits and pieces of info given here, here's an example:

    Goal: Change the playback speed of a particular Mechanim animation state in script at runtime.
    1. Set up the states in an Animation Controller. (We'll call the animation state we want to change "VariableAnimState".)
    2. In the Animator Controller editor window, select the "Parameters" tab.
    3. Click the "+" sign and create a float parameter.
    4. Name this new float parameter "VariableAnimSpeed".
    5. By default, the value of the float will be 0, so change it to 1 (If you want the animation to start at normal speed...)
    6. Now select the animation state that you want to change so you can see it in the inspector. (In our case, it's VariableAnimState)
    7. In the inspector, notice there is a field labeled "Speed". Leave this at default, which will normally be 1.
    8. Below the Speed field, there is a blank field labeled "Multiplier". Click the checkbox to the right of it labeled "Parameter".
    9. Now back in the Multiplier field, click the dropdown arrow and select the parameter you want to control it. (In our case it's "VariableAnimSpeed")

    Note: if you don't create the float parameter first, you will get an error.
    You have now finished setup.

    10. In script, here are the relevant bits. Change as needed:

    Code (CSharp):
    1. public Animator animator;
    2.  
    3. void ChangeStateSpeed()
    4. {
    5.     animator.SetFloat("VariableAnimSpeed", 2.0f);
    6. }
    Now when you change the value of the float variable in the animator, the speed multiplier for that particular state will also change.

    Hope this helps.
     
  29. ciapoide121

    ciapoide121

    Joined:
    Aug 30, 2014
    Posts:
    10
    This is how documentation should be written.

    Thank you gevarre!
     
    Pharaoh_ likes this.
  30. coldshower

    coldshower

    Joined:
    Dec 27, 2016
    Posts:
    1
    good solution.I often use the blend tree to resolve the problem .
     
  31. indieDoroid

    indieDoroid

    Joined:
    Jan 25, 2016
    Posts:
    226
    You sir are a god!

    Thanks for this explanation :)

    sharing is caring

    https://twitter.com/IndieNendoroid
     
  32. lucipir

    lucipir

    Joined:
    Aug 28, 2013
    Posts:
    1
    gevarre, for the first time I write in the forum and I am doing it just to say THANK YOU!!!
     
  33. fbarboza

    fbarboza

    Joined:
    Jun 5, 2017
    Posts:
    8
    Thank you very much my friend!
    I was totally lost "Googleling around" the solution, read a lot of old stuff and finally have found your post.
    Thank you!
     
  34. MartinGebske

    MartinGebske

    Joined:
    Jun 18, 2013
    Posts:
    13
    Is it possible to use the same animation controller for different models? i.e. two People who both are in idle... but one should idle a bit faster?
     
    arkogelul likes this.
  35. arkogelul

    arkogelul

    Joined:
    Nov 14, 2016
    Posts:
    101
    I'm looking for the exact same thing.
    I thought something like would exist:

    Code (CSharp):
    1. Animator.Play("animation",speed);
    But I can't seem to find a way of doing it.

    The only solutions I have found are global.
     
  36. ivitz

    ivitz

    Joined:
    May 1, 2017
    Posts:
    2
    not only that. I need to get animation duration via script but it doesn't count the speed multiplier! So the duration is for speed 1, but if I have speed 2 the duration is not half, it is the same! this is insane...
     
  37. stevesan

    stevesan

    Joined:
    Aug 14, 2011
    Posts:
    65
  38. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    659
    It still amazes me how badly Mecanim over-complicates even the simplest of tasks.

    That 10 step process posted by @gevarre would take 2 steps with my Animancer plugin (link in my signature):

    1. Write the script:
    Code (CSharp):
    1. public AnimancerController animancer;
    2. public AnimationClip clip;
    3.  
    4. public void SetAnimationSpeed(float speed)
    5. {
    6.     animancer.GetState(clip).Speed = speed;
    7. }
    2. Assign the references in the inspector.

    That's it. No messing around with the clunky UI. No magic strings. Just simple code that tells it exactly what you want to do.

    Of course it's much more common to set the speed when you play the animation rather than adjusting an already playing animation so the method would likely look more like this:
    Code (CSharp):
    1. public void Play(float speed)
    2. {
    3.     animancer.Play(clip).Speed = speed;
    4.  
    5.     // Or:
    6.  
    7.     var state = animancer.Play(clip);
    8.     state.Speed = speed;
    9.     state.Time = ...
    10.     state.OnEnd = ...
    11.     // etc.
    12. }
     
    mr_blahblah likes this.