Search Unity

Animation Track and Animator Override Controllers

Discussion in 'Timeline' started by TheLadyApollo, Jan 3, 2018.

  1. TheLadyApollo

    TheLadyApollo

    Joined:
    Nov 27, 2017
    Posts:
    4
    Hi! I'm creating an turn based RPG where every action (attack, generic actions, death) is based on a timeline animation, the problem is that when attacking, I want the defender to be basically any character, since every character will share an 'hurt' state, I've created a generic animator with every state and each character has it own Animator Override Controller.

    The problem is that the Animation Track works only by setting the animation clip directly and it ignores completely the overrides on it controller. Is there a way to workaround this problem?
     
  2. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Sounds to me like you need to actually let the Animator play the animation, instead of using the timeline to override the animator.

    I'm not sure if its possible to make the timeline use the animator instead (which is what you want, right? so the animator plays the right animation).

    Other than that I guess you would have to use a script to change the animation clip that should be played.
    Once you know what character the timeline should be applied to, you can get the characters animator, then from there the override controller.

    But maybe there is a cleaner way possible that I'm not aware of, or maybe the timeline guys are working on something to make this more straightforward (which would be nice!) But then again consider having a animation that is pretty short and then overriding it with an animation that takes 5x longer... would the timeline have to scale the animation down (so it plays faster)?
     
  3. TheLadyApollo

    TheLadyApollo

    Joined:
    Nov 27, 2017
    Posts:
    4
    Oh, I guess I never realized that the problem is that the timeline overrides the animator, instead of working with it. So that's the "problem".

    I guess that I could create an custom track that works with the animator, playing the animation when the clip start, the problem is that it would damage our animator's workflow, not letting them seamlessly work with the timeline in the editor, previewing the animations...

    I really hope that the unity team is working on a more straightforward approach to everything related to the timeline, as it is, in my opinion, the strongest feature of unity.

    And for that case with animations with different length, I don't think the timeline should scale at all, if the overriding animation is shorter than the original, it should just repeat itself (if Loop Time is true), or, if is longer, just cut it.
     
    dadude123 likes this.
  4. TheLadyApollo

    TheLadyApollo

    Joined:
    Nov 27, 2017
    Posts:
    4
    Just an update on the matter
    I've created an AnimatorTrack and it working greatly, there is definitely room for improvements and I'm not totally satisfied with it but I wanted to share with you guys:

    Code (csharp):
    1.  
    2. public class AnimatorMixerBehaviour : PlayableBehaviour
    3. {
    4.     public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    5.     {
    6.         Animator animator = playerData as Animator;
    7.  
    8.         if (!animator)
    9.             return;
    10.  
    11.         int inputCount = playable.GetInputCount ();
    12.  
    13.         string strongestName = "";
    14.         float strongestInputWeight = 0;
    15.         float strongestClipStart = 0;
    16.         float time = (float)playable.GetGraph().GetRootPlayable(0).GetTime();
    17.        
    18.  
    19.         for (int i = 0; i < inputCount; i++)
    20.         {
    21.             float inputWeight = playable.GetInputWeight(i);
    22.             ScriptPlayable<AnimatorBehaviour> inputPlayable = (ScriptPlayable<AnimatorBehaviour>)playable.GetInput(i);
    23.             AnimatorBehaviour input = inputPlayable.GetBehaviour ();
    24.  
    25.             if (inputWeight > strongestInputWeight)
    26.             {
    27.                 strongestInputWeight = inputWeight;
    28.                 strongestName = input.animationName;
    29.                 strongestClipStart = input.ClipStartTime;
    30.             }
    31.         }
    32.  
    33.         if(strongestInputWeight != 0)
    34.         {
    35.             AnimationClip animation;
    36.  
    37.             try
    38.             {
    39.                 animation = animator.runtimeAnimatorController.animationClips.Where(anim => anim.name == strongestName).First();
    40.             }
    41.             catch
    42.             {
    43.                 throw new Exception($"Animator does not have an animation called {strongestName}");
    44.             }
    45.  
    46.             float normalizedTime = (time - strongestClipStart) / animation.length;
    47.  
    48.             animator.Play(animation.name, 0, normalizedTime);
    49.  
    50.             if (Application.isEditor)
    51.                 animator.Update(Time.deltaTime);
    52.         }
    53.     }
    54. }
     
    seant_unity, zIyaGtVm and Charlesmxy like this.
  5. Charlesmxy

    Charlesmxy

    Joined:
    Jan 16, 2015
    Posts:
    2
    That's pretty awesome! Could you share the AnimatorBehaviour.cs?
     
  6. zIyaGtVm

    zIyaGtVm

    Joined:
    Dec 27, 2017
    Posts:
    131
    Thanks for sharing this script. This help me a lot
    Instead of putting animationclips on a animation track.
    I also try to use a custom timeline track which only controlls an animators current state.
     
  7. huulong

    huulong

    Joined:
    Jul 1, 2013
    Posts:
    224
    I'm exactly in the same case as the OP, with a bunch of generic animations reused across my characters, but each with their override.

    So, what was it doing exactly? I thought it would find the override animation associated to some base animation set on the AnimatorMixerBehaviour track, but I don't see references to AnimatorOverrideController. Maybe that part of the logic is in the AnimatorBehaviour class?

    A custom track where you can set animator states would be great too! Although that seems harder to pass a reference to an animator state.

    Personally I'm using a custom integer parameter for my animations, so I would only need to pass an integer. Either:
    a. defining a custom track and placing custom clips with an int parameter
    b. using Signal Track with Signal Receiver and placing custom Signal Emitters (markers) that can take an integer (in this case I need one marker to start the animation and one to stop it (revert to default animation)