Search Unity

[SOLVED] Mechanim AnimatorOverrideController Layer Access

Discussion in 'Animation' started by ArborealGames, Sep 16, 2016.

  1. ArborealGames

    ArborealGames

    Joined:
    Aug 8, 2012
    Posts:
    6
    Hi, in my 2D game I have an animator controller, and an override controller, the latter being assigned to my character like so:
    [AnimatorController (3 layers) ]
    >[AnimatorOverrideController] ( assigned to character )

    • The animator controller has 3 layers.
    • I intend to append animations via the 'sync' functionality of mechanim.
    • I aim to swap the animations in these 3 layers at runtime.

    I can use the AnimationOverrideController to override the 'Base Layer' animations like this:
    Code (CSharp):
    1. //( grab reference to component )
    2. Animator animRef= GetComponent<Animator>();
    3.  
    4. //( replace with a shiny new one so we dont adjust the prefab )
    5. AnimatorOverrideController newOne= new AnimatorOverrideController();
    6. newOne.runtimeAnimatorController= animRef.runtimeAnimatorController;
    7. animRef.runtimeAnimatorController= newOne;
    8.  
    9. //( Replace the animation for 'idle' )
    10. ((AnimatorOverrideController)animRef.runtimeAnimatorController)["idle"]= replacementAnimTest;
    ...but I cannot find a way to access the other layers to override those as well, or to swap their animation clips.

    Is there a way to do this or do I need to start from scratch and use the legacy animation scripting just so that I can set like:
    Code (CSharp):
    1. Animator["idleAnimation"].layer= 1;
    ...or some other similar approach? If you even can do that in legacy?
    Otherwise I'll end up spawning gameobjects on the fly and trying to match them up all because I can't access the other layers to assign clips.

    Advice is appreciated!


    SOLUTION

    1)
    animation 'layers' in mechanim are NOT aimed at overlapping sprites, but are aimed at layering bone weights in animations, and so were not fit for my purpose to begin with.

    2)
    When you set an override controller's clip in the way mentioned above, you set it via it's clip name not it's state name. As mentioned below you could create dummy animations with funky names and replace those to potentially modify animations in other layers, though due to point 1), I won't be doing this for my project as it won't achieve the desired effect.

    3) As a point of interest, my final solution was simply to create my own framework for overlaying gameobjects with sprite renderers and animators attached.
    I created one animator to act as the base/pattern for all characters, and derived override controllers for all overlays and the parent overlay, e.g. one override for the body, one for the main hand weapons, one for offhand.
    I then at runtime replace these overrides with an 'instantiated clone' of the override so that they may be tweaked independantly at runtime without affecting one another (by reference).
    These clone overrides on child objects then act as the other overlapping 'layers' in a conventional, photoshop-like sense.
    These layers are synchroinsed by setting the animator's parameters to all children overrides in unison, if they have been created through the framework.
    It's worth noting that you must also set their state speeds to have the same duration overall for all clips of the same name/state upon being assigned. This seems to be because upon import, a clip's sprites-per-second are sometimes interpreted differently based on things like the number of sprites overall.
     
    Last edited: Sep 21, 2016
  2. Ideka

    Ideka

    Joined:
    Feb 23, 2015
    Posts:
    9
    This:
    Changes all occurences of the clip named "idle" in the animator, regardless of layer.
     
  3. ArborealGames

    ArborealGames

    Joined:
    Aug 8, 2012
    Posts:
    6
    Hello, thank you for trying, but this does not appear to be the case.
    after calling that, only the base layer's idle animation is changed, and the other layers remain unaffected.
    I wish to adjust the other layer's animations.
    And yes I have tried the usual "idle", "Base Layer.idle", "OtherLayer.idle"...

    Hmm... seems like you can't simply overlap 2d animations in the layers anyway, like for example, if I wanted a character to have a hat overlap their sprite, layers don't seem to achieve this. they use weights and switch between one or the other whereas I require multiple simultaneously, I suppose I will have to create a hackish workaround and just dump multiple animators on top of one another... just seems so... unintuitive? Am I missing something obvious?
     
    Last edited: Sep 16, 2016
  4. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    @fvfwvwv Hi, Ideka is right, chaging the clip idle will change all occurence of the clip idle in your controller independantly of the layer.
    If this is not the case then there is bug and you should log it.

    Can you give us more detail on what you would like to achieve exactly? My guess is that you are trying to do a equipment system for your character
    There is a few thread on this currently
    http://forum.unity3d.com/threads/creating-an-equipment-system-on-a-2d-pixel-game.315600/
    http://forum.unity3d.com/threads/2d-puppet-rigging-tips-tricks.245564/
    as pointed by @dustinandrew one of the approach taken by a lot of user is to use transform and animator layers to draw a complete character with equipement.
     
  5. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Also I forgot to tell you, you should setup your clip before assign the overricontroller on your animator.
    There is a bug, when you set a clip the controller get reseted to the default state, we are working on a fix but it not yet available

    Code (CSharp):
    1.  
    2. //( grab reference to component )
    3. Animator animRef= GetComponent<Animator>();
    4. //( replace with a shiny new one so we dont adjust the prefab )
    5. AnimatorOverrideController newOne= new AnimatorOverrideController();
    6. newOne.runtimeAnimatorController= animRef.runtimeAnimatorController;
    7. //( Replace the animation for 'idle' )
    8. newOne["idle"]= replacementAnimTest;
    9. animRef.runtimeAnimatorController= newOne;
    10.  
     
  6. ArborealGames

    ArborealGames

    Joined:
    Aug 8, 2012
    Posts:
    6
    OK thanks for that,

    I have tinkered hither and tither and decided that trying to combine 'animation layers' and 'override controllers' with 2D animations (that don't utilise kinematics) is a bit like trying to use a hammer to drill a hole. It seems like that combination of technologies is meant mostly for 3D, rigged-model animations, and for layering node positions, not for layering sprites. Silly me.

    I have now gone down the path of having code create child GameObjects with SpriteRenderers and Animators on them, each with 1 layer and their own animatorControllerOverride, then simply parenting them with different z indices so that they overlap, which I guess is a bit like using a hand-drill to drill a hole, but I got there. It will become an elegant solution one way or another, I just have grown quite attached to mecanim's interface, it has great potential and you should be proud.

    I really appreciate your advice about the bug by the way Mechanim-Dev. I will encounter that a little further down the road when dynamically loading these animations, and the heads up is much appreciated. So that I get this straight, I assume you're saying that if I assign the clip to an active runtimeAnimatorController, it resets it's state/parameters, but if I create a clone and then assign the clip to that, and THEN assign the clone as a new override controller, the state/parameters are retained... interesting, a bit long-winded but perhaps I'll keep an eye on that bug-fix and try your workaround. Thankyou. Any idea what patch that might be in perchance? I don't think that for this project it will be much of an issue though, now that I'm aware of it.

    Additionally, regarding Ideka's hint, I was looking in the animator UI (the animator window) whilst calling that code to assign the animation clip, and the base layer changed, whilst the others didnt, but I imagine that perhaps the override controller was changing it for all layers but the UI simply wasn't reflecting this? I'm not too worried either way I was just frustrated and as I say, trying to use the wrong tools for the job.

    Thanks for your time you pair.


    Update

    I have come to a realisation that my fundamental understanding of what the override does was wrong to begin with. The override overrides by animation clip name, not by the animation state name. So with empty states they don't exist as far as the override is converned, and with the same clip name they become the same clip as far as the override is concerned and in a sense, invisible in the inspector UI.

    It still isn't adequate in this circumstance though because even by replacing uniquely named animations I cannot overlap them anyway visually, its more for weighted bones but at least I ...understand it more now, thank you.
     
    Last edited: Sep 18, 2016
  7. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Exactly, like i said this is a know issue which is not wanted and we are working on a fix for this.

    Yes exactly the override is by clip name and not by state name. The way many have worked around this issue is to add a distinct empty clip in each empty state to make sure that you can override the whole animation state set.
     
  8. ArborealGames

    ArborealGames

    Joined:
    Aug 8, 2012
    Posts:
    6
    OK nice one, thanks for the help!
    I'll mark it as resolved.

    If nothing else my understanding of the various mecanim-related systems is much better after this.
    As you say, due to 'layers' being aimed at 3D bone weights and not aimed at overlapping sprites, for this case I have simply overlapped animators on separate objects, works well. :)
    I just wanted to exhaust the other natively-handled-by-unity options first because I love understanding the tools I'm using if that makes sense, for the sake of being aware of more options for future projects.

    Thanks again, swift responses from a unity dev, very appreciated I know how hard it is to find the time these days, you're awesome.