/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.Objects.CharacterAssist { using Opsive.UltimateCharacterController.Utility; using UnityEngine; /// /// Specifies the location that the character should move to when the Move Towards ability is started. /// public class MoveTowardsLocation : MonoBehaviour { [Tooltip("The offset relative to the transform that the character should move towards.")] [SerializeField] protected Vector3 m_Offset = new Vector3(0, 0, 1); [Tooltip("The yaw offset relative to the transform that the character should rotate towards.")] [SerializeField] protected float m_YawOffset = 180; [Tooltip("The size of the area that the character can start the ability at. A zero value indicates that the character must land on the exact offset.")] [SerializeField] protected Vector3 m_Size; [Tooltip("The ability can start when the distance between the start location and character is less than the specified value.")] [Range(0.0001f, 100)] [SerializeField] protected float m_Distance = 0.01f; [Tooltip("The ability can start when the angle threshold between the start location and character is less than the specified value.")] [Range(0, 360)] [SerializeField] protected float m_Angle = 0.5f; [Tooltip("Is the character required to be on the ground?")] [SerializeField] protected bool m_RequireGrounded = true; [Tooltip("Should the ability wait to start until all transitions are complete?")] [SerializeField] protected bool m_PrecisionStart = true; [Tooltip("The multiplier to apply to the character's speed when moving to the start location.")] [SerializeField] protected float m_MovementMultiplier = 1; public Vector3 Offset { get { return m_Offset; } set { m_Offset = value; } } public float YawOffset { get { return m_YawOffset; } set { m_YawOffset = value; } } public Vector3 Size { get { return m_Size; } set { m_Size = value; } } public float Distance { get { return m_Distance; } set { m_Distance = value; } } public float Angle { get { return m_Angle; } set { m_Angle = value; } } public bool RequireGrounded { get { return m_RequireGrounded; } set { m_RequireGrounded = value; } } public bool PrecisionStart { get { return m_PrecisionStart; } set { m_PrecisionStart = value; } } public float MovementMultiplier { get { return m_MovementMultiplier; } set { m_MovementMultiplier = value; } } private Transform m_Transform; private float m_StartYawOffset; private Vector3 m_StartOffset; public Vector3 TargetPosition { get { return m_Transform.TransformPoint(m_Offset); } } public Quaternion TargetRotation { get { return m_Transform.rotation * Quaternion.Euler(0, m_YawOffset, 0); } } public float StartYawOffset { get { return m_StartYawOffset; } } public Vector3 StartOffset { get { return m_StartOffset; } } /// /// Initialize the default values. /// private void Awake() { m_Transform = transform; m_StartYawOffset = m_YawOffset; m_StartOffset = m_Offset; } /// /// Returns the direction that the character should move towards. /// /// The position of the character. /// The rotation of the character. /// The direction that the character should move towards. public Vector3 GetTargetDirection(Vector3 position, Quaternion rotation) { var direction = m_Transform.TransformPoint(m_Offset) - position; if (m_Size.sqrMagnitude == 0) { return MathUtility.InverseTransformDirection(direction, rotation); } var size = m_Transform.TransformDirection(m_Size); if (Mathf.Abs(direction.x) < Mathf.Abs(size.x / 2)) { direction.x = 0; } if (Mathf.Abs(direction.y) < Mathf.Abs(size.y / 2)) { direction.y = 0; } if (Mathf.Abs(direction.z) < Mathf.Abs(size.z / 2)) { direction.z = 0; } return MathUtility.InverseTransformDirection(direction, rotation); } /// /// Is the character in a valid position? /// /// The position of the character. /// The rotation of the character. /// Is the character grounded? /// True if the position is valid. public bool IsPositionValid(Vector3 position, Quaternion rotation, bool grounded) { var direction = GetTargetDirection(position, rotation); if (Mathf.Abs(direction.x) <= m_Distance && ((m_RequireGrounded && grounded) || (!m_RequireGrounded && (Mathf.Abs(direction.y) <= m_Distance))) && Mathf.Abs(direction.z) <= m_Distance) { return true; } return false; } /// /// Is the character in a valid rotation? /// /// The rotation of the character. /// True if the rotation is valid. public bool IsRotationValid(Quaternion rotation) { Vector3 forwardDirection; if (m_RequireGrounded) { forwardDirection = Vector3.ProjectOnPlane(m_Transform.forward, rotation * Vector3.up); } else { forwardDirection = m_Transform.forward; } return Vector3.Angle(Quaternion.Euler(0, m_YawOffset, 0) * forwardDirection, rotation * Vector3.forward) <= m_Angle / 2 + 0.001f; } } }