Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question How to handle complex Unity animator controller

Discussion in 'Animation' started by heinrichs81, May 16, 2021.

  1. heinrichs81

    heinrichs81

    Joined:
    Sep 8, 2020
    Posts:
    4
    Hello Forum,

    last months I've broken my head on strategies how to handle my Animations for characters in Unity with the Unity-AnimatorController. For an overview I categorize this post text in three parts.
    0. What I want to do
    1. What I know
    2. Problems and how I try to solve

    My aim is not to get the one and only perfect solution, it's more about the discussion about different ways and opinions to handle specific problems. Also about the way to get to different solutions and to talk about the advantages and disadvantages. I hope you're all can be part of this discussion and feel free to solve this problems for further newcomers.
    For the ones who did not know about some special topics. I've marked the technical terms with [ ] and at the End of this article you will find the links to specific descriptions.

    0. What I want to do
    I want to realize a relative complex AnimatorController [1] for an humanoid Character [2] with root motion [3].
    For the first step I want to realize the mobility or. locomotion of this character. All the animations I want to use right now are already done and imported as FBX [4] to Unity, and prepared for my use case.
    I try to categorize all my motions in a superficial level:
    a) walk -> forward, forward right, right, backward right, backward, backward left, left, forward left
    same for -> b) jog c) run and d) crouch
    e) start -> walk, jog, run, crouch forward
    f) same for start from rest position to -> 45°, 90°, 135°, 180°
    g) stop -> walk, jog, run, crouch
    h) same for stop from rest position to -> 45°, 90°, 135°, 180°

    So in a nutshell the starts, does and stops of different kinds of motion in several directions.

    There also planned several steps to equip my Charterer with standard animations.
    Planned are i) Start Jumps, j) Landings and k) Dodges -> in 8 directions of current look direction and
    different kind of l) attacks.

    So a really great part of the considerations is the extensibility of the system.
    But first I want to came to a solution for a smooth and enjoyable movement for my character.

    1. What I know
    Basics about Animator Controller -> States, Blend Trees, Sub State Machines, Transitions and Transitions Settings, Behaviors, parameters, layers [5]
    Basics about state machines [6]
    Basics about Unity-FBX-Settings-> Model, Rig, Animation, Materials [7]
    Basic basics of design patterns. [8]
    And also Basics about Scripting and the standard Unity features.
    Basic organization of animations [9]

    So my first tries had been the standard learn phase of a creating a simple state machine in the Unity-Animator by using normal states and transitions like to find in every standard tutorial on YouTube or other sources. Of course, this ended very soon in a confusing network of states, transitions and parameters.

    Next I experimented with blend trees [10]. At first this concept determined a lot of my problems, but at the end some issues came with this solution. Blend trees are a great solution to capsule similar animations like walk, jog and run forward, but on the other hand a state in a blend tree is not defined as well, because it is a mixture of different states... in my opinion

    2. Problems and how I try to solve

    2.1 State definition of in between values:
    Imagine I want to have a smooth transition from a locomotion animation (i.e. jog) to a stop animation (i.e. stop jog).
    Lets say walk is from >0.2 m/s to <2 m/s -> jog is from >2m/s to <5m/s and run from >5m/s. I can define this states by speed, okay... but for me it not seems a good way. Because this values are also are possible in start and stop animations.
    So, how to define which states currently present without self query of the state in animator?

    2.2 Blend trees with similar non similar states
    So I came to the idea to handle all start and stop -> walk, jog, run, crouch animations in a blend tree.
    upload_2021-5-16_0-35-1.png
    (Fig. 1)

    Very soon I recognized that blend trees only works with floats in an "in between way". This principal don't work with non-similar animations. And believe or not: start -> walk, jog, run and crouch motions are not-similar to each other. Same for stop animations.
    upload_2021-5-16_0-36-27.png
    (Fig. 2)

    I had the idea to force set this animations in a blend tree by define natural numbers for the different animations (i.e. stop walk -> 1; stop jog -> 2; stop run -> 3 (see Fig. 2 Threshold)), and force set them in script. This felt also like cheating, and of course this caused other issues. If in some case the stop state is not well defined and switches, weird (in between) animations are the consequence.
    Is there a way to use blend trees on a safe and "non cheating" way to separate animations that have similar transition conditions, but different kind of motions?

    2.3 Default of a Sub-state machine [11]
    Meant are the Sub-states machines of the Unity-AnimatorController.
    My next idea where to separate animations with similiar transitions, but different motions in a sub-state. Of course. This seems to be really a right way. But the great problem is the "default state" of the Unity-AnimationController, or rather the "default state" of the sub-state machine (see Fig. 3).
    upload_2021-5-16_0-38-23.png
    (Fig. 3)

    Imagine currently the Character is something in between jog and running in this animation is well played in an blend tree... but now the character should stop. So if I make a transition from run/jog blend tree to stop-Sub-state machine, I've got a big problem. Unity demands a default state. But there is no default state. If the Character Runs before, the animation is "stop run", if its jog, it's "stop jog", and so on (See Fig. 4 blue arrow).
    upload_2021-5-16_0-40-25.png
    (Fig. 4)

    So I played with the thoughts to put a placeholder animation with little frames as default (See Fig. 4, Motion field), but I cannot define that placeholder as well. What it should be? jog, run, walk, stop walk, stop run...depends on the animation before and after.
    Is there a good way to handle the default state of sub-state machines which are in close relationship to motion of the further and following steps?

    I hope you all can understand my "problems". How to handle complex multiple to multiple states conditions?!
    I also like to discuss of different aspects and solutions and I am grateful and glad for every solution, contribution and thought process you you share with us.


    Sources:
    [1] Animator Controller (https://docs.unity3d.com/Manual/class-AnimatorController.html)
    [2] humanoid Character (https://docs.unity3d.com/560/Documentation/Manual/UsingHumanoidChars.html)
    [3] root motion (https://docs.unity3d.com/Manual/RootMotion.html)
    [4] FBX, filmbox format (https://en.wikipedia.org/wiki/FBX & https://docs.huihoo.com/unity/5.4/Documentation/en/Manual/HOWTO-exportFBX.html)
    [5] Animation Controller, context (https://learn.unity.com/tutorial/controlling-animation)
    [6] Finite State Machine (https://en.wikipedia.org/wiki/Finite-state_machine)
    [7] Humanoid animations (https://docs.unity3d.com/Manual/ConfiguringtheAvatar.html)
    [8] Design Patterns (https://en.wikipedia.org/wiki/Software_design_pattern)
    [9] Animations Organization Concepts (https://unity3d.com/de/how-to/build-animator-controllers)
    [10] Blend Trees (https://docs.unity3d.com/Manual/class-BlendTree.html)
    [11] Sub-State machine (https://docs.unity3d.com/Manual/NestedStateMachines.html)
     

    Attached Files:

  2. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    685
    2.1. you can convert the movement speed (rigidbody velocity or animator velocity) to the blend value of the locomotion blend tree. for start/stop use separate state / substate-machine.

    2.2. stops (and starts) can be synchronized to a degree. for more advanced stuff you will have to track foot positions (and crossfade to a point in animation)

    if you don't want to synchronize them for some reason, use separate state for each (stop jog, stop run etc), not a substate machine
     
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,580
    I don't know how to effectively solve your problems using Animator Controllers, but Animancer (link in my signature) would likely make your job a lot easier because it lets you play and control all your animations directly in scripts (no Animator Controllers).
    1. Animancer's Mixers serve the same purpose as Blend Trees, but you have full access to their states and thresholds.
    2. You can just give your script an array of AnimationClips (or Transitions) and play whichever one you want.
    3. This one should actually be easy to solve with either system by just having two Blend Trees (or Mixers): one for the looping walk/jog/run which transitions into the other for the stopping walk/jog/run. That way if you're halfway between walking and jogging and you stop, it will also blend halfway between the stop walking and stop jogging animations. Or if you don't want to blend the stopping animations like that, Animancer would let you use an array just like question 2 so you can just pick whichever is most appropriate for your current speed.
     
  4. heinrichs81

    heinrichs81

    Joined:
    Sep 8, 2020
    Posts:
    4
    Hello Forum,

    first thank you bobadi for your interesting suggestions.
    And also thanks to Kybernetik for your short introduction to Animancer.

    For my first solution I tried out some attempts that I want to share with the forum and maybe discuss advantages and disadvantages.

    upload_2021-7-9_11-29-49.png
    (Fig. 1)

    In Figure 1 you can see I made three Sup-State Machines for "Turn To Locomotion", "Locomotions" and "Turn Locomotion Direction". For the "Idle" state I currently have a single State, but I think I will change it later to a Sub-State Machine. Each of this upper States/Sub-State Machines have a Behaviour Script on it. In This Script to things where done
    1.1. To leave: Figure out if a change to another State/Sub-State Machine should be made and to which one it should be made
    1.2. By entering: Check which inner States/Blend Trees should be played now.

    There is also the possibility to implement most of the logic directly with the Transitions and the Transition Conditions, but I decided to do the logic in the Behaviour Script, because for me it`s easier to read, to understand and to debug.

    upload_2021-7-9_11-48-44.png
    (Fig. 2)

    In Figure 2 is shown how I managed how the logic should decide between several states that are similar, but not blendable, because their blended motions look weird. For this example in the Animator Parameters there is a Float Parameter called "STATES Locomotion To Turn". This parameter is set by the Behaviour Script from the "Turn Locomotion Direction" Sub-State Machine, as mentioned in 1.2. For a better overview, I've made an Enum to with the different "Turn Locomotion Direction"-States. In the Blend Tree the single state is played by this set parameter.
    I. e.
    Code (CSharp):
    1. turnDirectionStateEnum = TurnDirectionStates.TURN_JOG_LEFT_180;
    Code (CSharp):
    1. statesTurnToLocomotion.SetValueInAnimator(animator, (float)turnDirectionStateEnum);
    To handle my Parameters I've done two things.
    2.1 I made a Classes for my Parameters for the game-play, like inputs or velocity of the character.
    2.2 I made Classes for my Animator Parameters that allows me more control. The main reason is to be able to change the easily the rename the parameters in the inspector without changing them directly in the script.

    upload_2021-7-9_12-10-40.png
    (Fig. 3)

    In Figure 3 you can see the current game-play parameters their added to a GameObject "Being Parameters" which is a child of the character.

    Current issues are
    3.1. the motions is not precise enough
    3.1.1 stop motions are not fast enough, so I deleted that states (increase animation speed looks weird)
    3.1.2 the turn motions i.e. 180 degree turns are not played yet as a 180 degree turn, because of the blending to the next state. I currently don't know how to solve this.
    3.1.3 The locomotion is to sluggish. The turning circle is to big.

    The next steps are:
    4.1 fix some of the upper issues.
    4.2 extend the controller with new motions
    4.2.1 linear straight locomotion (left, right, backward, ...) for combat mode
    4.2.2 crouch locomotion
    4.2.3 jumps
    4.2.4 raise and fall
    4.2.5 else... roll, dodge, attacks, block, interactions

    Please feel welcome to critic and discuss and to give everybody the chance to learn and grow in experience. :)
     
  5. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,580
  6. heinrichs81

    heinrichs81

    Joined:
    Sep 8, 2020
    Posts:
    4
    Thanks for this Information. I already tried to disable root motion while turning. May I should read more into the details you posted. In my opinion Blend Trees works very well in Unity's Animator, but the rest is full of stupid weaknesses that slowly starts to robbing my patience. :(