Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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:
    25
    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.)
     
    Ultroman and bluescrn like 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.
     
    Ultroman and PrimalCoder like this.
  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:
    641
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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.
     
    Ultroman, fherbst, GrayedFox and 7 others like this.
  9. danielshae

    danielshae

    Joined:
    Mar 4, 2015
    Posts:
    1
    And all the people said, "Thanks, Unity. We take the mean stuff back now."
     
    Alic, 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:
    47
    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:
    108
    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:
    6,292
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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. OlliQueck

    OlliQueck

    Joined:
    Apr 11, 2013
    Posts:
    49
    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,552
    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:
    78
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
  20. crafTDev

    crafTDev

    Joined:
    Nov 5, 2008
    Posts:
    1,820
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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. crafTDev

    crafTDev

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

    Thanks,
    jrDev
     
  23. crafTDev

    crafTDev

    Joined:
    Nov 5, 2008
    Posts:
    1,820
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
  25. crafTDev

    crafTDev

    Joined:
    Nov 5, 2008
    Posts:
    1,820
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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. crafTDev

    crafTDev

    Joined:
    Nov 5, 2008
    Posts:
    1,820
    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.
     
    Fera_KM, Phasmatodea, xpath and 26 others like this.
  29. ciapoide121

    ciapoide121

    Joined:
    Aug 30, 2014
    Posts:
    12
    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. KarlKarl2000

    KarlKarl2000

    Joined:
    Jan 25, 2016
    Posts:
    604
    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:
    105
    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:
    2,551
    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. }
     
    ciapoide121 and mr_blahblah like this.
  39. Ultroman

    Ultroman

    Joined:
    Mar 10, 2014
    Posts:
    110
    Yes, I'm necro'ing. Sue me. (But please don't.) The same problems persist and this is a great thread.

    The new parameter-system is neat, but the Speed variable is right there on the State / Blend Tree...I can see it...I can change it...why can I not just set it from code? It is incredibly inconvenient to use the parameter-system for many things. For example, all my weapons have different speeds I want to play their animations at, because the same attacks can get quicker with stats and thus their animations (simple States) need to be played faster. In order to achieve this, I have to have a separate parameter for each of my weapon animations, just to be able to set their speed individually. I have to do this, because if they shared one animation-speed variable it would lerp their playback speeds (which could be very different) when transitioning between weapon animations, even if they only overlap slightly. I don't want that. I want it to transition between two weapon states, each continuing to play at the exact speed I set them to when I fired them, and just transition between those. In order to do that, I need to triple my number of Animator parameters in order to simply set the speed of my animations at runtime when I Play() them, just to avoid speed-lerping. Alternatively, I could set speed on the State to a default value and scale the speed based on a multiplier, but I'd still need a multiplier-parameter for each weapon animation. That's about 16 parameters I'll need just for that.

    Why? Why doesn't Play() have an optional "speed" parameter that sets the speed? When I can set the Speed variable in the inspector and I can even change it there at runtime, why can I not just set the speed of the State from code? It's so weird. Please, for the love of anything you personally find holy, find a way to allow us to do this. It would simplify a lot of use-cases.
    Is it because it takes less processing power to set a parameter than looking up States in Animation Layers all the time to set their speeds? If so, I'd rather be able to just create a reference to the State when I need one and set the speed on that, kind of like the old system. Or, as I said, at least be able to set it when I Play() the animation.

    Other requests:
    It would also be incredibly useful if you could make a checkbox on Blend Tree Motion Fields (next to the Mirror-checkbox) to play the given Motion / Blend Tree in reverse at whatever positive speed it has. Perhaps have that on simple States, as well, so we don't have to use a negative speed variable just for those.

    It would also be fantastic to be able to set speed to 0 on Blend Tree Motion Fields, instead of it being clamped at 0.01 (as others have noted earlier in this thread). If I were to make it 0 for some reason, it'd be my own fault that the whole thing stops. It's the expected behavior for me, compared to it continuing to play. It would be even nicer to be able to set the speed to negative values in order to make it play in reverse (also fixes the same issue as the previous point).

    And you have to overhaul the Blend Tree editor. We need the ability to drag the connections around, so we don't have to remake everything just because we want to make a change at the root of the tree. They are incredibly cumbersome to work with.

    Most importantly, though, we need to be able to reuse the same child Motion Field / Blend Tree several times in the list of Motions in a Blend Tree, so we can use the same child-subtree but at different speeds. Otherwise, I have to manually duplicate child blend trees for each speed I want it to be played at, which means at least +1 blend tree per directional animation just to automate its speed with a custom minimum speed (4 extra points near the middle). This is in order to blend AND automatically scale the speed of movement animations using just one 2D Directional Blend Tree, which I assume was the idea behind it. With this change and at least some of the ones above, your system would be much more flexible and easy to work with.

    I may have to try Animancer, but it seems a bit bloated for what I need. I just need to set my animation speeds :D
     
    Last edited: Feb 9, 2021
    Fera_KM, PrimalCoder and KarlKarl2000 like this.
  40. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    453
    Hey! I got the multiplier parameter working. I might just add my two cents here that solved an almost two-day fight for me, in case anybody else would find it helpful.

    My issue was that in Editor, the animator controller is an asset, but this asset was referred to by my two Animator components (I have two animators that act in sync using a shared controller, one for first person, one for third person). So, the parameter and configuration needs to be added to the shared animator controller asset, but in runtime, the animatorInstance.setFloat() needs to be called for each Animator component.
     
  41. mat108

    mat108

    Joined:
    Aug 24, 2018
    Posts:
    130
    LOL it's ben 8 years and Unity still doesn't allow for more than one multiplier parameter per clip.

     
  42. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,551
    Why would you need more than one multiplier parameter? Just multiply the value yourself before you set the parameter.

    I'd be the last person to defend Mecanim, but I honestly doubt that any animation system in any engine would have multiple speed multipliers for a single animation within the animation system rather than just expecting you to do it yourself. It wouldn't make sense for them to waste performance for everyone else just to cover an obscure edge case with an easy workaround.
     
  43. mat108

    mat108

    Joined:
    Aug 24, 2018
    Posts:
    130
    Yeah I mean I did that now. And it works but it absolutely 'feels' un-elegant and error prone. Functionality to add several parameters seems like an absolute no-brainer to add to a system like this.
     
  44. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,551
    1. Make a float parameter.
    2. Set that parameter as the animation's speed multiplier.
    3. Multiply your values.
    4. Set the parameter
    Or
    1. Make a float parameter.
    2. Make another float parameter.
    3. Set both parameters as the animation's speed multipliers.
    4. Set the first parameter.
    5. Set the second parameter.
    The most un-elegant and error-prone part is the code to set a parameter since its based on a magic string. So the second approach doubles up on the worst part of the process and anyone who only uses one multiplier would pay a small performance cost to support this feature. From where I'm standing, that means not having that feature is a no-brainer and it explains why no animation system I know of has such a feature.
     
  45. Lyraedan

    Lyraedan

    Joined:
    Jun 25, 2019
    Posts:
    8
    Bump 10 years later and we still can't do this :/

    What I found from trying to tackle this issue
    The animation state layers speed / speed multiplier values are only getters so you can't set them in code.

    The Animator only has 1 singular speed variable. That yes you can change. But, if you have 2 animations playing lets say you have legs walking for the lower body and arms holding a gun for the upper body. Changing this speed value changes the speed for both.

    (This applies even with Sync set to false in the layer settings - thought I should mention that)

    My solution to this ridiculous issue: Set the speed to whatever it needs to be when you need it-> Wait for the animation to finish -> set the animation speed back to 1
     
    Last edited: Jun 10, 2022