Search Unity

Implementing a Vaulting system using Target Matching

Discussion in 'Animation' started by daniel_lochner, Apr 16, 2020.

  1. daniel_lochner

    daniel_lochner

    Joined:
    Jun 9, 2016
    Posts:
    174
    Hi there,

    I've been trying to implement a more robust vaulting system into my game using Unity's Target Matching, however I have been experiencing a few issues.
    1. Remaining at a match position: While vaulting I would like the left hand to remain on the vaulting object until the player releases and jumps up on top of it. From the documentation, it seems you have to specify a start and end normalized time, where the avatar target moves towards a match position over that period of time. The following is an example snippet of code which I have tried that doesn't seem to work:
      Code (CSharp):
      1. if (normalizedTime < 0.1f)
      2. {
      3.     animator.MatchTarget(leftHandPosition, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0f, 0.1f);
      4. }
      5. else if (normalizedTime < 0.75f)
      6. {
      7.     animator.MatchTarget(leftHandPosition, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.1f, 0.75f);
      8. }
    2. Switching match targets during the animation: On to my next point. When I have finished targeting a match position for the left hand, I would like to switch over to the left foot. This would ensure the player lands on the vaulting object as expected. The following is a continuation of the first example snippet of code:
      Code (CSharp):
      1. else
      2. {
      3.     animator.MatchTarget(leftFootPosition, Quaternion.identity, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 0), 0.75f, 1f);
      4. }
    3. Inaccurate: I'm not sure if this point is just a by-product of the issues I've been experiencing above, but I've found that the match targets can be very inaccurate. When targeting a position, the selected body part moves around the targeted position as if it weren't even targeting it at all?
    Here are my different vaulting animations:
    Vaulting.gif

    If you can shed some light on any of these points, I would greatly appreciate it!

    Thanks,
    Daniel
     
  2. daniel_lochner

    daniel_lochner

    Joined:
    Jun 9, 2016
    Posts:
    174
    So I think I've figured out what has been causing all the problems! :)

    It seems Match Targeting doesn't function correctly during transitions! In my example listed above, you can see that my first stretch of matching starts at 0 and ends at 0.1 seconds into the animation. This is however is shorter than the initial transition duration, and so is completely ignored!

    When I set each of the transition durations to 0, everything works smoothly!

    Something else I needed to do differently, was use a SMB instead of simply putting it in the Update function inside of this if statement:
    if (animator.GetCurrentAnimatorStateInfo(0).IsName("Vaulting (Climb)"))
    {
    }


    This is because this also doesn't take into account the transition, and so would start at around 0.2 seconds into the animation!

    As for my points 2 and 3, they were by-products of this issue.


    Is there another way around this though than to just set the transition durations to 0? I would of course still like to fade between animations!
     
    Last edited: Apr 20, 2020
    merpheus likes this.
  3. daniel_lochner

    daniel_lochner

    Joined:
    Jun 9, 2016
    Posts:
    174
    Hooray! I've fixed all the issues! For those who are interested and see this thread in the future, here were my final changes.

    1. First of all, don't simply call the
    MatchTarget
    function. Instead call this wrapper function:
    Code (CSharp):
    1. public void MatchTarget(Vector3 matchPosition, Quaternion matchRotation, AvatarTarget target, MatchTargetWeightMask weightMask, float normalisedStartTime, float normalisedEndTime)
    2. {
    3.     if (animator.IsInTransition(0))
    4.     {
    5.         SetVaulting(false);
    6.         return;
    7.     }
    8.  
    9.     if (animator.isMatchingTarget)
    10.     {
    11.         return;
    12.     }
    13.  
    14.     float normalizeTime = Mathf.Repeat(animator.GetCurrentAnimatorStateInfo(0).normalizedTime, 1f);
    15.  
    16.     if (normalizeTime > normalisedEndTime)
    17.     {
    18.         return;
    19.     }
    20.  
    21.     animator.MatchTarget(matchPosition, matchRotation, target, weightMask, normalisedStartTime, normalisedEndTime);
    22. }

    2. Another key change was disabling collision detection for my player's rigidbody! (Disabling the collider is not enough!) I achieved that with the following code in my SetVaulting() function:
    Code (CSharp):
    1. public void SetVaulting(bool vaulting)
    2. {
    3.     Vaulting = animator.applyRootMotion = vaulting;
    4.     rigidbody.detectCollisions = collider.enabled = !vaulting;
    5. }

    3. In the Update loop (I switched back to using the update loop instead of State Machine Behaviours as indicated in the previous post), I then use something similar to the following code:
    Code (CSharp):
    1. if (Vaulting)
    2. {
    3.     if (animator.GetCurrentAnimatorStateInfo(0).IsName("Vault On Top (Climb)"))
    4.     {
    5.         MatchTarget(leftHandPosition, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0f), 0f, 0.2f);
    6.         MatchTarget(onTopRootPosition, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(Vector3.one, 0f), 0.55f, 0.65f);
    7.     }
    8. ...
    9. }