namespace VRTK.Prefabs.Interactions.Controllables { using System; using UnityEngine; using UnityEngine.Events; using Malimbe.MemberChangeMethod; using Malimbe.XmlDocumentationAttribute; using Malimbe.PropertySerializationAttribute; using Zinnia.Data.Type; using Zinnia.Data.Attribute; /// /// Defines the event with the drive value. /// [Serializable] public class DriveUnityEvent : UnityEvent { } /// /// The basis of the public interface that will drive a control in relation to a specified world axis. /// /// The to operate with the facade. /// The actual concrete implementation of the drive facade being used. public abstract class DriveFacade : MonoBehaviour where TDrive : Drive where TSelf : DriveFacade { #region Reference Settings /// /// The linked /// [Serialized] [field: Header("Reference Settings"), DocumentedByXml, Restricted] public TDrive Drive { get; protected set; } #endregion #region Events /// /// Emitted when the raw value changes with the raw value data. /// [Header("Events"), DocumentedByXml] public DriveUnityEvent ValueChanged = new DriveUnityEvent(); /// /// Emitted when the step value changes with the step value data. /// [DocumentedByXml] public DriveUnityEvent StepValueChanged = new DriveUnityEvent(); /// /// Emitted when the normalized value changes with the normalized value data. /// [DocumentedByXml] public DriveUnityEvent NormalizedValueChanged = new DriveUnityEvent(); /// /// Emitted when has been reached by the control. /// [DocumentedByXml] public DriveUnityEvent TargetValueReached = new DriveUnityEvent(); /// /// Emitted when the drive starts moving the control. /// [DocumentedByXml] public DriveUnityEvent StartedMoving = new DriveUnityEvent(); /// /// Emitted when the drive is no longer moving the control and it is stationary. /// [DocumentedByXml] public DriveUnityEvent StoppedMoving = new DriveUnityEvent(); #endregion #region Drive Settings /// /// The axis to operate the drive motion on. /// [Serialized] [field: Header("Drive Settings"), DocumentedByXml] public DriveAxis.Axis DriveAxis { get; set; } = Controllables.DriveAxis.Axis.XAxis; /// /// Determines if the drive should move the element to the set . /// [Serialized] [field: DocumentedByXml] public bool MoveToTargetValue { get; set; } = true; /// /// The normalized value to attempt to drive the control to if the is set to . /// [Serialized] [field: DocumentedByXml, Range(0f, 1f)] public float TargetValue { get; set; } = 0.5f; /// /// The speed in which the drive will attempt to move the control to the desired value. /// [Serialized] [field: DocumentedByXml] public float DriveSpeed { get; set; } = 10f; #endregion #region Step Settings /// /// The range of step values to use. /// [Serialized] [field: Header("Step Settings"), DocumentedByXml] public FloatRange StepRange { get; set; } = new FloatRange(0f, 10f); /// /// The increment to increase the steps in value by. /// [Serialized] [field: DocumentedByXml] public float StepIncrement { get; set; } = 1f; #endregion /// /// Sets the to the position that the current step value represents. /// public virtual void SetTargetValueByStepValue() { SetTargetValueByStepValue(Drive.StepValue); } /// /// Sets the to the position that the given step value represents. /// /// The step value that represents the new target value. public virtual void SetTargetValueByStepValue(float stepValue) { float normalizedStepValue = Mathf.InverseLerp(StepRange.minimum, StepRange.maximum, Mathf.Clamp(stepValue, StepRange.minimum, StepRange.maximum)); TargetValue = normalizedStepValue; } /// /// Forces the drive to move to the current step value at the given speed. /// /// The speed the drive will move the control at. public virtual void ForceSnapToStepValue(float driveSpeed) { MoveToTargetValue = true; DriveSpeed = driveSpeed; SetTargetValueByStepValue(); } /// /// Calculates the axis to use for the given . /// /// The new value. protected virtual void CalculateDriveAxis(DriveAxis.Axis driveAxis) { Drive.CalculateDriveAxis(driveAxis); } /// /// Processes the drive's ability to automatically drive the control. /// /// Whether the drive can automatically drive the control. protected virtual void ProcessAutoDrive(bool autoDrive) { Drive.ConfigureAutoDrive(autoDrive); } /// /// Sets the new . /// /// The new value. protected virtual void SetTargetValue(float targetValue) { Drive.SetTargetValue(targetValue); } /// /// Processes the changes to the . /// /// The new value. /// Whether the new value should be processed. protected virtual void ProcessDriveSpeed(float driveSpeed, bool moveToTargetValue) { Drive.ProcessDriveSpeed(driveSpeed, moveToTargetValue); } /// /// Called after has been changed. /// [CalledAfterChangeOf(nameof(DriveAxis))] protected virtual void OnAfterDriveAxisChange() { Drive.SetUp(); } /// /// Called after has been changed. /// [CalledAfterChangeOf(nameof(MoveToTargetValue))] protected virtual void OnAfterMoveToTargetValueChange() { Drive.SetUp(); } /// /// Called after has been changed. /// [CalledAfterChangeOf(nameof(TargetValue))] protected virtual void OnAfterTargetValueChange() { Drive.SetUp(); } /// /// Called after has been changed. /// [CalledAfterChangeOf(nameof(DriveSpeed))] protected virtual void OnAfterDriveSpeedChange() { Drive.SetUp(); } /// /// Called after has been changed. /// [CalledAfterChangeOf(nameof(StepRange))] protected virtual void OnAfterStepRangeChange() { Drive.SetUp(); } /// /// Called after has been changed. /// [CalledAfterChangeOf(nameof(StepIncrement))] protected virtual void OnAfterStepIncrementChange() { Drive.SetUp(); } } }