Search Unity

Mecanim + Root Motion + Move from point A to point B

Discussion in 'Animation' started by shopguy, Apr 30, 2015.

  1. shopguy

    shopguy

    Joined:
    Jan 12, 2013
    Posts:
    282
    I hope I'm missing something obvious, but after an hour of searching and scrolling through several pages of posts in this forum, I can't find what should be easy.

    I'm not looking for a script calculate waypoints or path-finding, or how to move a transform between 2 points. I've done all of that before. Just trying to figure out how to make an NPC, that is walking via a Mecanim style animation with root motion, move between waypoints.

    It seems like a real pain, compared to manually moving with script. Trying to get a "turn" animation, for example, to turn my NPC the exact amount needed (say 27.54545 degrees), then walk exactly to another point, and turn the exact amount needed again, and so on and so on.

    I understand (maybe incorrectly) the point of Mecanim is that animation is realistic, which maybe means you can't "stop at an exact point and turn" because your pivot foot hasn't touched the ground yet, so it wouldn't look real/smooth unless you move a little more in your current direction first. Okay.. if that's the case, not a huge issue, but then instead of turning 27.54545 degrees, maybe I need to turn 28.121212 degrees instead, to "correct" for this.

    Are there any tutorials that cover this type of thing? I've found plenty for player controlled characters, but none for moving NPCs between 2 points, or even something I'd think would be very common.. making NPCs/enemies follow or move towards the player.

    Lastly, my case might be a little more complex, because I think some/all of the walk animations I'm using, the root motion doesn't move in a straight line. These are zombie animations, so not sure I'd want them to, zombies don't really walk in a straight line (not the ones I've seen in real-life anyway ;).
     
    filod likes this.
  2. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    We do have a function to cover exactly this case.
    http://docs.unity3d.com/ScriptReference/Animator.MatchTarget.html

    Basically this function allow you to perfectly reach a position and a rotation. You can set a match target for either Root, left foot, right foot, left hand and right hand.
    This function will blend the current root motion of your controller with the matched position and rotation over the range of time specified by the function.

    Match target doesn't work while a statemachine is in transition to another state
     
  3. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,702
    For longer-ranged motion, such as patrolling waypoints, what about a different approach than MatchTarget?

    I recommend a higher-level motor control script.

    The more things change, the more they loop around back to earlier work. Back in the early days of robotics research, getting a robot from point A to point B was a big research topic. Roboticists weren't magicians who could break the laws of physics and teleport matter from one position to another in the physical world (i.e., directly modify transforms). They could only tell wheels to start rolling, which is the exact same thing as root motion. The robot's higher-level motor control script monitored the robot's position in relation to the destination and sent signals to the wheels to start or stop. The wheels (which is the root motion animator in this analogy) would do the actual work of moving the robot, but without any knowledge of where it was moving to, since this is handled by the higher level motor control script.

    So your higher level motor control script can just send "signals" (animator parameters) like "set forward speed to X" or "set turning speed to Y" to accomplish its goal of getting from A to B. Use blend trees and state transitions in your animator controller to comply with these signals.
     
    chelnok likes this.
  4. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    It really hard to be precise with this approach, even if you know that your clip 'walkleft' is doing a 45 degree rotation when you blend this clip with another clip the final rotation may not be exactly 45 but maybe 42~43 because you are not playing only one clip but the result of two clip blended together.

    Also Transition that are not instantenous break this method because of clip blending
     
  5. shopguy

    shopguy

    Joined:
    Jan 12, 2013
    Posts:
    282
    Thanks for the info, both of you. I haven't really read up on NavMesh because it seemed like overkill for my needs (don't really need obstacle avoidance -- path finding). I'm going to go ahead and read that section of the manual now, because I'm still struggling with the "go from point A to point B" part, and thinking NavMeshAgent.SetDestination might be what I need?

    It seems like MatchTarget is what I need to make it precise, but more of something I'll use "when I'm almost to point B", but not really for the overall traveling.

    I'm surprised with all of the 100+ mecanim videos on YouTube, none I could find are moving NPCs, just the player. I usually like start with a tutorial or walk-through before hitting the reference manuals, just to make sure I'm not doing something totally wrong or making life difficult. Not finding that for this.

    TonyLi's post over here http://forum.unity3d.com/threads/mecanim-control-by-mouse-click.283264/ -- made me think I need to give NavMesh a closer look. If it can be used to move the player to a mouse click location, seems like it should work for my needs, except the destination will be a series of fixed points, not mouse clicks. Then when I'm almost to the destination, and want to turn to face the next destination, sounds like I'll need MatchTarget to make that precise.
     
  6. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,702
    You could always use a bit of each for maximum accuracy.

    The code in my other post lets the NavMeshAgent handle rotation rather than letting the Animator animate it. As long as the character is moving, I think it looks fine. A lot of AAA games still do it this way.

    BTW, the NavMesh example in the Mecanim Example Scenes project works very much like an NPC. You set a destination, and the "NPC" makes it way there. In the example scene, you set it using a mouse click. But it's no different from setting the destination using an AI script instead.
     
  7. shopguy

    shopguy

    Joined:
    Jan 12, 2013
    Posts:
    282
    http://docs.unity3d.com/Manual/nav-CouplingAnimationAndNavigation.html

    I downloaded the sample on that page, which is probably similar to the asset store link you gave, but just the part I'm interested in. After seeing how much is required to get that level of quality, I think I will try the simple route first, the one you mention. Especially since I don't have the "strafe-set", and have never seen one for zombie style motion.

    Sounds like either way, the path is the same. I need to get the simple part working, then decide if I want to create the strafe-set and blending/variables, and/or add MatchTarget for precision.
     
    TonyLi likes this.
  8. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,702
    Good plan. I think it's best to implement the simplest solution that gives you the result you want.

    Thanks for posting that link, by the way. I wasn't aware that Unity had added that to the manual. Nice to know!
     
    shopguy likes this.
  9. shopguy

    shopguy

    Joined:
    Jan 12, 2013
    Posts:
    282
    Just wanted to say thanks again. Looks like this was exactly what I needed for this part of my project. Once I actually figured out how to use it with the animations I have.

    The results are looking great so far!

    Pretty project specific, but in case it helps future readers...

    I'm using 2 Mixamo animations here. The free "Zombie Walk" and another "Zombie Turns 90 degrees". I think this is pretty typical from what I've seen, one walking animation, and one turning (or sometimes multiple of each). This script is far from done, mostly just for testing, but I setup an animator with a default animation of walking, and it switches to the turning animation on a "Turn" trigger. Then attached this script to my NPC/zombie. I added lots of comments so hopefully someone can follow it, and maybe learn something -- or let me know if I'm doing things all wrong :)

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. // Ugly script, just used for demo/testing purposes!
    4. public class test5 : MonoBehaviour
    5. {
    6.     // Set this to your player transform (or any transform you want your Zombie to turn towards).
    7.     public Transform Player;
    8.  
    9.     // You can uncheck this in the inspector, to see how things fall apart without the awesomeness of MatchTarget.
    10.     public bool UseTargetMatch = true;
    11.  
    12.     int State;
    13.  
    14.     void Update()
    15.     {
    16.         Animator animator = GetComponent<Animator>();
    17.  
    18.         // This part just waits for the walk animation to loop two full times (4 steps), then triggers a turn.
    19.         //  In my real project I'll trigger the turns using a series of way points, not a fixed number of steps.
    20.         if (State == 0)
    21.         {
    22.             if (animator.GetCurrentAnimatorStateInfo(0).normalizedTime > 2)
    23.             {
    24.                 State = 1;
    25.                 animator.SetTrigger("Turn");
    26.             }
    27.         }
    28.  
    29.         // We are turning...
    30.         else if (State == 1)
    31.         {
    32.             // Wait for our turn state to begin (there is a delay because I'm using blending to make things look nice)...
    33.             if (animator.GetCurrentAnimatorStateInfo(0).IsName("zombie_turn_2"))
    34.             {
    35.                 // Change to next state
    36.                 State = 2;
    37.  
    38.                 // The magic happens here, unless disabled...
    39.                 if (UseTargetMatch)
    40.                 {
    41.                     // Calculate the correct rotation needed for us to face the player/target
    42.                     Quaternion correctRot = Quaternion.LookRotation(Player.position - transform.position);
    43.  
    44.                     animator.MatchTarget(
    45.  
    46.                         // position not used, we only modify rotation
    47.                         Vector3.zero,
    48.  
    49.                         // make target rotation the rotation needed to face player/target
    50.                         correctRot,
    51.  
    52.                         // adjust the root
    53.                         AvatarTarget.Root,
    54.  
    55.                         // zero weight for the position, so it doesn't get adjusted at all.  one for rotation = 100% adjustment
    56.                         new MatchTargetWeightMask(new Vector3(0, 0, 0), 1),
    57.  
    58.                         // we start adjustments at the current time, "right now"
    59.                         animator.GetCurrentAnimatorStateInfo(0).normalizedTime,
    60.                        
    61.                         // for my animation, this is when both feet hit the ground, so at that point it shouldn't continue to rotate
    62.                         //  so I want the rotation adjustments to complete at this point in the animation (50% point).
    63.                         0.5f);
    64.                 }
    65.             }
    66.         }
    67.  
    68.         // Waiting for turn to complete...
    69.         else if (State == 2)
    70.         {
    71.             // Wait for walk state to begin...
    72.             if (animator.GetCurrentAnimatorStateInfo(0).IsName("walking_3"))
    73.             {
    74.                 // Change to next state -- for this test, we are done.
    75.                 State = 3;
    76.  
    77.                 // Pretty much the same thing we did for our turn.  Due to blending between our turn state and walk state, the first walk loop needs
    78.                 //  to be adjusted also, otherwise we'll no longer be facing the target.
    79.                 if (UseTargetMatch)
    80.                 {
    81.                     Quaternion correctRot = Quaternion.LookRotation(Player.position - transform.position);
    82.  
    83.                     // For this one we use 1 as the end point.  At the very end of the first walk loop, we want to be facing the target.
    84.                     //  This works correctly because our walk cycle starts and ends at the same rotation point (none, or whichever direction we were facing when it
    85.                     //   started, which is typical of a good walk animation designed for mecanim).
    86.                     animator.MatchTarget(animator.targetPosition, correctRot, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(0, 0, 0), 1), animator.GetCurrentAnimatorStateInfo(0).normalizedTime, 1);
    87.                 }
    88.             }
    89.         }
    90.     }
    91. }
    92.  
     
    deuxieme, chelnok, Noisecrime and 2 others like this.
  10. shopguy

    shopguy

    Joined:
    Jan 12, 2013
    Posts:
    282
    ..and because a video is worth a million words, here is what I accomplished with the test script above:



    The male zombie is using MatchTarget, the female isn't.

    Granted, for this simple example it would work without MatchTarget, if I just position my zombies at the correct angle/location from the start. All of this MatchTarget stuff will be crucial though, once I start adding in animations like "zombie gets knocked back by gun fire" and other things that will no doubt not leave my zombies facing the correct direction all the time (not if I continue using blending), not without MatchTarget.
     
    deuxieme, chelnok, Noisecrime and 3 others like this.
  11. sskenth

    sskenth

    Joined:
    Sep 23, 2016
    Posts:
    54
    Oh wow! Thanks so much for breaking down the code line by line and showing a video, I'm just about to use this now in a project and really needed these comments!

    Thanks again!
     
    MaxFortarezza and shopguy like this.