using System; using UnityEngine; using Cinemachine.Utility; namespace Cinemachine { /// /// Alternative to AxisState - a simplified structure to hold the definition of an input axis /// [Serializable] public struct AxisBase { /// The current value of the axis [NoSaveDuringPlay] [Tooltip("The current value of the axis.")] public float m_Value; /// The minimum value for the axis [Tooltip("The minimum value for the axis")] public float m_MinValue; /// The maximum value for the axis [Tooltip("The maximum value for the axis")] public float m_MaxValue; /// If checked, then the axis will wrap around at the min/max values, forming a loop [Tooltip("If checked, then the axis will wrap around at the min/max values, forming a loop")] public bool m_Wrap; /// /// Call this from OnValidate() to validate the fields of this structure (applies clamps, etc). /// public void Validate() { m_MaxValue = Mathf.Clamp(m_MaxValue, m_MinValue, m_MaxValue); } } /// /// A helper class to drive an input axis, as an alternative to the standard Cinemachine.AxisState. /// Behaviour is a simple direct scaling of the input channel, with no max speed. /// [Serializable] public struct CinemachineInputAxisDriver { /// Multiply the input by this amount prior to processing. Controls the input power [Tooltip("Multiply the input by this amount prior to processing. Controls the input power.")] public float multiplier; /// The amount of time in seconds it takes to accelerate to a higher speed [Tooltip("The amount of time in seconds it takes to accelerate to a higher speed")] public float accelTime; /// The amount of time in seconds it takes to decelerate to a lower speed [Tooltip("The amount of time in seconds it takes to decelerate to a lower speed")] public float decelTime; /// The name of this axis as specified in Unity Input manager. /// Setting to an empty string will disable the automatic updating of this axis [Tooltip("The name of this axis as specified in Unity Input manager. " + "Setting to an empty string will disable the automatic updating of this axis")] public string name; /// The value of the input axis. A value of 0 means no input. You can drive /// "this directly from a custom input system, or you can set the Axis Name and /// have the value driven by the internal Input Manager [NoSaveDuringPlay] [Tooltip("The value of the input axis. A value of 0 means no input. You can drive " + "this directly from a custom input system, or you can set the Axis Name and " + "have the value driven by the internal Input Manager")] public float inputValue; /// Internal state private float mCurrentSpeed; const float Epsilon = UnityVectorExtensions.Epsilon; /// Call from OnValidate: Make sure the fields are sensible public void Validate() { accelTime = Mathf.Max(0, accelTime); decelTime = Mathf.Max(0, decelTime); } /// Update the axis /// current deltaTime /// The AxisState to update /// True if the axis value changed due to user input, false otherwise public bool Update(float deltaTime, ref AxisBase axis) { if (!string.IsNullOrEmpty(name)) { try { inputValue = CinemachineCore.GetInputAxis(name); } catch (ArgumentException) {} //catch (ArgumentException e) { Debug.LogError(e.ToString()); } } float input = inputValue * multiplier; if (deltaTime < Epsilon) mCurrentSpeed = 0; else { float speed = input / deltaTime; float dampTime = Mathf.Abs(speed) < Mathf.Abs(mCurrentSpeed) ? decelTime : accelTime; speed = mCurrentSpeed + Damper.Damp(speed - mCurrentSpeed, dampTime, deltaTime); mCurrentSpeed = speed; // Decelerate to the end points of the range if not wrapping float range = axis.m_MaxValue - axis.m_MinValue; if (!axis.m_Wrap && decelTime > Epsilon && range > Epsilon) { float v0 = ClampValue(ref axis, axis.m_Value); float v = ClampValue(ref axis, v0 + speed * deltaTime); float d = (speed > 0) ? axis.m_MaxValue - v : v - axis.m_MinValue; if (d < (0.1f * range) && Mathf.Abs(speed) > Epsilon) speed = Damper.Damp(v - v0, decelTime, deltaTime) / deltaTime; } input = speed * deltaTime; } axis.m_Value = ClampValue(ref axis, axis.m_Value + input); return Mathf.Abs(inputValue) > Epsilon; } /// Support for legacy AxisState struct: update the axis /// current deltaTime /// The AxisState to update /// True if the axis value changed due to user input, false otherwise public bool Update(float deltaTime, ref AxisState axis) { var a = new AxisBase { m_Value = axis.Value, m_MinValue = axis.m_MinValue, m_MaxValue = axis.m_MaxValue, m_Wrap = axis.m_Wrap }; bool changed = Update(deltaTime, ref a); axis.Value = a.m_Value; return changed; } float ClampValue(ref AxisBase axis, float v) { float r = axis.m_MaxValue - axis.m_MinValue; if (axis.m_Wrap && r > Epsilon) { v = (v - axis.m_MinValue) % r; v += axis.m_MinValue + ((v < 0) ? r : 0); } return Mathf.Clamp(v, axis.m_MinValue, axis.m_MaxValue); } } }