/// <summary> /// Local method to move to the target position/rotation at the move speed. The onComplete action will be called after the character has arrived. /// </summary> /// <param name="targetPosition">The target position.</param> /// <param name="targetRotation">The target rotation.</param> /// <param name="minMoveSpeed">The minimum speed to move positions.</param> /// <param name="onComplete">The action to call after the character has arrived.</param> private IEnumerator MoveToTargetLocal(Vector3 targetPosition, Quaternion targetRotation, float minMoveSpeed, Action onComplete) { if (s_EndOfFrame == null) { s_EndOfFrame = new WaitForFixedUpdate(); } // Use the existing speed if it is greater then the minimum so the character will smoothly move to the target. var moveSpeed = m_Controller.InputVector.magnitude > minMoveSpeed ? m_Controller.InputVector.magnitude : minMoveSpeed; // Stop any existing velocities. m_Controller.StopMovement(); // Gradually move towards the target position/rotation. var prevPosition = m_Transform.position; var startOffset = m_Transform.InverseTransformPoint(targetPosition); while (true) { // Rotate towards the target rotation. m_Controller.SetRotation(Quaternion.Slerp(m_Transform.rotation, targetRotation, m_Controller.RotationSpeed * Time.deltaTime)); // Use Root Motion to determine how far to move. var position = m_Transform.position; position.x = Mathf.MoveTowards(position.x, targetPosition.x, m_Controller.RootMotionForce.x > 0.05f ? m_Controller.RootMotionForce.x : 0.05f); position.z = Mathf.MoveTowards(position.z, targetPosition.z, m_Controller.RootMotionForce.z > 0.05f ? m_Controller.RootMotionForce.z : 0.05f); m_Controller.SetPosition(position); // Keep walking towards the target position. Slow down as the character gets closer. var offset = m_Transform.InverseTransformPoint(targetPosition); var strength = (startOffset.x < 0.001f ? 0 : offset.x / startOffset.x); m_AnimatorMonitor.SetHorizontalInputValue(moveSpeed * strength); strength = (startOffset.z < 0.001f ? 0 : offset.z / startOffset.z); m_AnimatorMonitor.SetForwardInputValue(moveSpeed * strength); // Break if the character has arrived at the destination. Perform the check after the movements so it doesn't have to wait for a frame to pass before checking again. if (Mathf.Abs(m_Transform.position.x - targetPosition.x) < 0.1f && Mathf.Abs(m_Transform.position.z - targetPosition.z) < 0.1f && Quaternion.Angle(m_Transform.rotation, targetRotation) < 0.1f) { break; } // If the character is stuck then stop trying to move. if ((position - prevPosition).sqrMagnitude < 0.00001f) { break; } prevPosition = position; yield return(s_EndOfFrame); } // The character has arrived. Set the position and rotation to its final position. m_Controller.SetPosition(targetPosition); m_Controller.SetRotation(targetRotation); // The character is no longer moving. m_Controller.StopMovement(); // The coroutine has ended. m_MoveToTargetRoutine = null; // Let the calling ability know that the character has arrived. onComplete(); }