Search Unity

animation skips ahead as it reaches its destination

Discussion in 'Animation' started by uberalles, Jan 27, 2014.

  1. uberalles

    uberalles

    Joined:
    Jun 29, 2013
    Posts:
    46
    I have a blend tree animation for walking/running/turning a human character. I'm using a right-click to determine the destination and simply setting that to the navagent component. The problem is that when the character is about to reach its destination it doesn't simply walk to the spot then stop, it quickly does this 'skip' to the spot, where the speed goes from a constant 1.75f to as high as 5.1f.

    A lot of this code is from the Stealth project with a few added touches.

    Code (csharp):
    1.  
    2.  
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6. public class CharacterMovement: MonoBehaviour {
    7.  
    8. #region public variables
    9.     public float deadZone = 10f;
    10.     public float spd;
    11.     public const float deadZR = 5f;
    12.     public float deadZoneRotate;
    13.    
    14.  
    15.  
    16.  
    17. #endregion
    18.  
    19.  
    20.  
    21. #region private variables
    22.     private Animator anim;
    23.     private NavMeshAgent nav;
    24.     private AnimStarter animSetup;
    25.  
    26.  
    27. #endregion
    28.  
    29. #region event functions
    30.     // Use this for initialization
    31.     void Awake ()
    32.     {
    33.         nav = GetComponent<NavMeshAgent>();
    34.         anim = GetComponent<Animator>();
    35.         nav.updateRotation = false;
    36.         deadZone *= Mathf.Deg2Rad;
    37.         animSetup = new AnimStarter(anim);
    38.         deadZoneRotate = deadZR;
    39.        
    40.     }
    41.    
    42.     // Update is called once per frame
    43.     void Update ()
    44.     {
    45.         NavAnimMoving();
    46.     }
    47.  
    48.     void OnAnimatorMove()
    49.     {
    50.  
    51.        
    52.            
    53.             nav.velocity = anim.deltaPosition / Time.deltaTime;
    54.             transform.rotation = anim.rootRotation;
    55.             if(anim.GetFloat("Speed") > 1.75f)
    56.                 Debug.Log("Anim Speed: " + anim.GetFloat("Speed"));
    57.        
    58.     }
    59.    
    60. #endregion
    61.  
    62. #region class methods
    63.  
    64.     void NavAnimMoving()
    65.     {
    66.  
    67.         // Create the parameters to pass to the helper function.
    68.         float speed = 0;
    69.         float angle;
    70.         float dist;
    71.         //find the distance between the two points
    72.         dist = Vector3.Distance(transform.position,nav.destination);
    73.  
    74.         if(dist <= nav.stoppingDistance)
    75.         {
    76.             transform.position = Vector3.Lerp(transform.position,nav.destination,Time.deltaTime * 3.5f);
    77.         }
    78.  
    79.        
    80.  
    81.         speed = Vector3.Project(nav.desiredVelocity, transform.forward).magnitude;
    82.         // ... and the angle is the angle between forward and the desired velocity.
    83.         angle = FindAngle(transform.forward, nav.desiredVelocity, transform.up);
    84.         // If the angle is within the deadZone...
    85.         if(Mathf.Abs(angle) < deadZone)
    86.         {
    87.             // ... set the direction to be along the desired direction and set the angle to be zero.
    88.             transform.LookAt(transform.position + nav.desiredVelocity);
    89.             angle = 0f;
    90.         }
    91.  
    92.         // Call the Setup function of the helper class with the given parameters.
    93.         animSetup.Setup(speed, angle);
    94.  
    95.     }
    96.  
    97.     float FindAngle(Vector3 fromVector, Vector3 toVector, Vector3 upVector)
    98.     {
    99.         // If the vector the angle is being calculated to is 0...
    100.         if(toVector == Vector3.zero)
    101.             // ... the angle between them is 0.
    102.             return 0f;
    103.        
    104.         // Create a float to store the angle between the facing of the enemy and the direction it's travelling.
    105.         float angle = Vector3.Angle(fromVector, toVector);
    106.        
    107.         // Find the cross product of the two vectors (this will point up if the velocity is to the right of forward).
    108.         Vector3 normal = Vector3.Cross(fromVector, toVector);
    109.        
    110.         // The dot product of the normal with the upVector will be positive if they point in the same direction.
    111.         angle *= Mathf.Sign(Vector3.Dot(normal, upVector));
    112.        
    113.         // We need to convert the angle we've found from degrees to radians.
    114.         angle *= Mathf.Deg2Rad;
    115.        
    116.         return angle;
    117.     }
    118. #endregion
    119. }
    120.  
    To try and compensate for this I added a check to see if the remaining distance was within the navAgent's stopping zone and if it is then I just Lerp the character over (looks awful of course!). I have a feeling the problem is with the OnAnimatorMove method, when the velocity is set by the change in delta position:
    Code (csharp):
    1. nav.velocity = anim.deltaPosition / Time.deltaTime;
    Here's the code for the AnimStarter that sends the parameters to the Animator Controller (I doubt there's any problem here):

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class AnimStarter
    5. {
    6.     public float spdDmpTime = 0.1f;              
    7.     public float angleSpdDmpTime = 0.7f;      
    8.     public float angleRespTime = 0.6f;          
    9.     #region hashIDs
    10.     public static int dyingState;
    11.     public static int locomotionState;
    12.     public static int shoutState;
    13.     public static int deadBool;
    14.     public static int speedFloat;
    15.     public static int sneakingBool;
    16.     public static int shoutingBool;
    17.     public static int playerInSightBool;
    18.     public static int shotFloat;
    19.     public static int aimWeightFloat;
    20.     public static int angularSpeedFloat;
    21.     public static int openBool;
    22.     #endregion
    23.    
    24.     private Animator anim;                                                    
    25.    
    26.    
    27.     // Constructor
    28.     public AnimStarter(Animator animator)
    29.     {
    30.         anim = animator;
    31.         dyingState = Animator.StringToHash("Base Layer.Dying");
    32.         locomotionState = Animator.StringToHash("Base Layer.Locomotion");
    33.         shoutState = Animator.StringToHash("Shouting.Shout");
    34.         deadBool = Animator.StringToHash("Dead");
    35.         speedFloat = Animator.StringToHash("Speed");
    36.         sneakingBool = Animator.StringToHash("Sneaking");
    37.         shoutingBool = Animator.StringToHash("Shouting");
    38.         playerInSightBool = Animator.StringToHash("PlayerInSight");
    39.         shotFloat = Animator.StringToHash("Shot");
    40.         aimWeightFloat = Animator.StringToHash("AimWeight");
    41.         angularSpeedFloat = Animator.StringToHash("AngularSpeed");
    42.         openBool = Animator.StringToHash("Open");
    43.     }
    44.    
    45.    
    46.     public void Setup(float speed, float angle)
    47.     {
    48.         // Angular speed is the number of degrees per second.
    49.         float angularSpeed = angle / angleRespTime;
    50.         // Set the mecanim parameters and apply the appropriate damping to them.
    51.         anim.SetFloat(speedFloat, speed, spdDmpTime, Time.deltaTime);
    52.         anim.SetFloat(angularSpeedFloat, angularSpeed, angleSpdDmpTime, Time.deltaTime);
    53.     }  
    54.  
    55. }
    The debug in the OnAnimatorMove shows a velocity of over 5f even though I set the speed the MouseMovement script to 1.75f:
    Code (csharp):
    1.  
    2.  
    3.             if(Input.GetMouseButtonUp(1)  !rightClickOnce)
    4.             {
    5.                 rightClickOnce = true;
    6.                 nav.speed = 1.75f;
    7.                 nav.destination = hit.point;
    8.             }
    I'm really stuck on this one, any help would be greatly appreciated. Thanks.