/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.Character.Abilities { using Opsive.Shared.Events; using UnityEngine; /// /// The Quick Turn ability allows the character to play an explicit animation when the character turns. /// [DefaultStopType(AbilityStopType.Automatic)] [DefaultAbilityIndex(8)] public class QuickTurn : StoredInputAbilityBase { [Tooltip("The minimum value of the input vector required for the ability to start.")] [SerializeField] protected float m_MinInputSqrMagnitude = 0.1f; [Tooltip("The value which differentiates between a walk and a run.")] [SerializeField] protected float m_SpeedChangeThreshold = 1; public float SpeedChangeThreshold { get { return m_SpeedChangeThreshold; } set { m_SpeedChangeThreshold = value; } } public float MinInputSqrMagnitude { get { return m_MinInputSqrMagnitude; } set { m_MinInputSqrMagnitude = value; } } private Vector2 m_AverageInput; private float m_StateIndex; private bool m_EventStop; protected override bool UseRawInput { get { return true; } } protected override bool RequireInput { get { return true; } } public override float AbilityFloatData { get { return m_StateIndex; } } /// /// Initialize the default values. /// public override void Awake() { base.Awake(); EventHandler.RegisterEvent(m_GameObject, "OnAnimatorQuickTurnComplete", OnQuickTurnComplete); } /// /// Called when the ablity is tried to be started. If false is returned then the ability will not be started. /// /// True if the ability can be started. public override bool CanStartAbility() { if (!base.CanStartAbility()) { return false; } // Don't start the ability if the input magnitude is below the threshold. if (m_CharacterLocomotion.RawInputVector.sqrMagnitude < m_MinInputSqrMagnitude) { return false; } m_AverageInput = Vector2.zero; for (int i = 0; i < m_InputCount; ++i) { m_AverageInput += m_Inputs[i]; } m_AverageInput /= m_InputCount; // In order for turn to start the input vector has move in an opposite direction. if ((m_CharacterLocomotion.RawInputVector.x == 0 || m_AverageInput.x == 0 || Mathf.Sign(m_AverageInput.x) == Mathf.Sign(m_CharacterLocomotion.RawInputVector.x)) && (m_CharacterLocomotion.RawInputVector.y == 0 || m_AverageInput.y == 0 || Mathf.Sign(m_AverageInput.y) == Mathf.Sign(m_CharacterLocomotion.RawInputVector.y))) { return false; } // Diagonal turns are not accepted. if (Vector2.Dot(m_CharacterLocomotion.RawInputVector, m_AverageInput) > -0.5f) { return false; } return true; } /// /// The ability has started. /// protected override void AbilityStarted() { if (Mathf.Abs(m_AverageInput.x) > m_SpeedChangeThreshold || Mathf.Abs(m_AverageInput.y) > m_SpeedChangeThreshold) { m_StateIndex = 1; } else { m_StateIndex = 0; } m_EventStop = false; m_CharacterLocomotion.ForceRootMotionRotation = true; base.AbilityStarted(); } /// /// Animation event callback when the quick turn animation has completed. /// private void OnQuickTurnComplete() { m_EventStop = true; } /// /// Can the ability be stopped? /// /// True if the ability can be stopped. public override bool CanStopAbility() { return m_EventStop || !m_CharacterLocomotion.Moving; } /// /// The ability has stopped running. /// /// Was the ability force stopped? protected override void AbilityStopped(bool force) { base.AbilityStopped(force); m_CharacterLocomotion.ForceRootMotionRotation = false; } /// /// Called when the character is destroyed. /// public override void OnDestroy() { base.OnDestroy(); EventHandler.UnregisterEvent(m_GameObject, "OnAnimatorQuickTurnComplete", OnQuickTurnComplete); } } }