Search Unity

Swapping Override Clips at Runtime

Discussion in 'Animation' started by Alismuffin, Feb 16, 2015.

  1. Alismuffin

    Alismuffin

    Joined:
    Oct 3, 2011
    Posts:
    100
    Hey guys!

    I have a base AnimatorController and an AnimatorOverrideController.

    Things work well except for when I swap out the override AnimationClip from the list of AnimationClipPairs at runtime! It resets the animator controller

    overrideController[originalClipName] = attackClip;

    That is all I have written for the swap and it results in the entire animator being reset. It goes back to its default state and all parameters are reset.

    Is there a way that I can somehow safely swap the clip and keep the current state I am in as well as the parameters? (The state I am in is not the state that I want to swap the clip for)
     
  2. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Hi Alismuffin,

    It's expected that the animator is resetted when you change a clip. This is something we would like to change in the future.

    In the meantime you need to save the Animator State before changing the clip, change the clip and then push back the saved state.

    Code (CSharp):
    1.        
    2.         Animator animator = GetComponent<Animator>();
    3.  
    4.         AnimatorStateInfo[] layerInfo = new AnimatorStateInfo[animator.layerCount];
    5.         for (int i = 0; i < animator.layerCount; i++)
    6.         {
    7.             layerInfo[i] = animator.GetCurrentAnimatorStateInfo(i);
    8.         }
    9.  
    10.         // Do swap clip in override controller here
    11.  
    12.         // Push back state
    13.         for (int i = 0; i < animator.layerCount; i++)
    14.         {
    15.             animator.Play(layerInfo[i].nameHash, i, layerInfo[i].normalizedTime);
    16.         }
    17.        
    18.         // Force an update
    19.         animator.Update(0.0f);
    20.  
     
  3. Alismuffin

    Alismuffin

    Joined:
    Oct 3, 2011
    Posts:
    100
    Hey thanks that helps a lot!

    However that still doesn't solve my issue with the actual parameters changing. I have a float value that I need to stay the same during the clip change. Is there any similar solution to this?
     
  4. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    yes you will need to save the parameter value too.
     
  5. Alismuffin

    Alismuffin

    Joined:
    Oct 3, 2011
    Posts:
    100
    As far as I can see there is no way of getting a list of these parameters which makes that solution not entirely ideal. I can't rely on knowing the names of the parameters that I want to save because this is a very generic operation I am doing.

    Thanks to your initial post and some reworking of my controller I was able to get what I wanted without making use of parameters so thanks for that!
     
  6. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    In 5.0 we did add Animator.parameters which return the parameter list.
     
  7. Alismuffin

    Alismuffin

    Joined:
    Oct 3, 2011
    Posts:
    100
    Ah! That's great. Unfortunately I cannot use 5.0 at this point but that is great to know! Thanks for your help.
     
  8. theANMATOR2b

    theANMATOR2b

    Joined:
    Jul 12, 2014
    Posts:
    7,790
    How were you able to overcome the problem without the solutions mecanim.dev suggested?
     
  9. jctz

    jctz

    Joined:
    Aug 14, 2013
    Posts:
    47
    I'm using Mechanim.Dev's solution ( as well as manually resetting some of my basic controller bools) but I'm now getting this error in the console:

    Calling Animator.GotoState on Synchronize layer

    This appears to be happening when I call animator.Play() in the 'push back state' block in the example code, and the effect is that my replacement clips don't play.

    Could this be due to the fact that I'm calling this inside a coroutine?
     
  10. jctz

    jctz

    Joined:
    Aug 14, 2013
    Posts:
    47
    Also, I just wanted to clarify how Unity 5 will improve this. Will Unity 5 eliminate the need for us to manually save/restore the state, or will it only make it easier for us to save/restore the state ourselves?
     
  11. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    We didn't change anything regarding this in 5.0, you still need to save/restore everything manually
     
  12. nonehill

    nonehill

    Joined:
    Oct 29, 2014
    Posts:
    7
  13. Ben_SEM

    Ben_SEM

    Joined:
    Jan 12, 2015
    Posts:
    3
    Hi,
    I've been trying this on a simple test in 5.1.1 and it doesn't seem to work anymore (or I'm doing something wrong). After saving the states and changing the clips through the override controller, the original Animator becomes corrupt it seems, reporting 0 layers and 0 parameters. No error is raised and the clip replacement works, but the states are not restored correctly and so the FSM resets.

    Any idea what's going on?
     
    agentHein likes this.
  14. riccardotognin

    riccardotognin

    Joined:
    Nov 12, 2012
    Posts:
    4
    Hi Ben_SEM,
    i think i found the solution to your problem with the resetting FSM:

    Code (CSharp):
    1. Animator animator = GetComponent<Animator>();
    2. AnimatorStateInfo[] layerInfo = new AnimatorStateInfo[animator.layerCount];
    3. for (int i = 0; i < animator.layerCount; i++)
    4. {
    5.     layerInfo[i] = animator.GetCurrentAnimatorStateInfo(i);
    6. }
    7. // Do swap clip in override controller here
    8.  
    9. // Force an update
    10. animator.Update(0.0f);
    11.  
    12. // Push back state
    13. for (int i = 0; i < animator.layerCount; i++)
    14. {
    15.     animator.Play(layerInfo[i].nameHash, i, layerInfo[i].normalizedTime);
    16. }      
    17.  
    As you can see, i moved the animator.Update(0.0f) line right before the // Push back state and it seems to work just fine for me.
     
    theANMATOR2b likes this.
  15. Ben_SEM

    Ben_SEM

    Joined:
    Jan 12, 2015
    Posts:
    3
    It works for me as well! Thanks a lot riccardo :)
     
  16. riccardotognin

    riccardotognin

    Joined:
    Nov 12, 2012
    Posts:
    4
    I'm glad it worked for you too! You're welcome ;)
     
  17. Ben_SEM

    Ben_SEM

    Joined:
    Jan 12, 2015
    Posts:
    3
    Two more things to know if you're trying to pull this one:
    1- spinning the animator *again* (though animator.Update(0f)) after restoring the animator state prevents some cases of one-frame undetermined state
    2 - backing up and restoring the animator parameters as well is a good idea. See http://answers.unity3d.com/questions/919995/parameters-and-states-of-animator-reset-on-objects.html. Note that I don't know of any way to save and restore the *trigger* parameters, which due to the way we build our animators is not an issue for us; but that may be a blocking point for others.
    [Edit: more points!]
    3 - restoring the state of the animator does not restore transitions (blends) that were in progress. Haven't found a way to do that properly, though maybe using CrossFade could help.
     
    Last edited: Aug 11, 2015
  18. aaronmichaelfrost

    aaronmichaelfrost

    Joined:
    Feb 4, 2021
    Posts:
    39
    Animator.layercount returns 0 for me when I use an animator controller override in 2020.2.2f1, and it also says animator doesnt have an animator controller when it clearly does
     
    Last edited: Jun 25, 2021
  19. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    Either post a thread about it and give some actual details or report a bug in Unity via the Help menu. Don't necro a 6 year old thread just because it's tangentially related.