using UnityEngine.XR.Interaction.Toolkit.Inputs.Readers; namespace UnityEngine.XR.Interaction.Toolkit.Samples.Hands { /// /// An input button reader based on another and holds it true until falling below a lower release threshold. /// Useful with hand interaction because the bool select value can bounce when the hand is near the tight internal threshold, /// so using this will keep the pinch true until moving the fingers much further away than the pinch activation threshold. /// [DefaultExecutionOrder(XRInteractionUpdateOrder.k_XRInputDeviceButtonReader)] public class ReleaseThresholdButtonReader : MonoBehaviour, IXRInputButtonReader { [SerializeField] [Tooltip("The source input that this component reads to create a processed button value.")] XRInputButtonReader m_ValueInput = new XRInputButtonReader("Value"); /// /// The source input that this component reads to create a processed button value. /// public XRInputButtonReader valueInput { get => m_ValueInput; set => XRInputReaderUtility.SetInputProperty(ref m_ValueInput, value, this); } [SerializeField] [Tooltip("The threshold value to use to determine when the button is pressed. Considered pressed equal to or greater than this value.")] [Range(0f, 1f)] float m_PressThreshold = 0.8f; /// /// The threshold value to use to determine when the button is pressed. Considered pressed equal to or greater than this value. /// /// /// This reader will also be considered performed if the source input is performed. /// public float pressThreshold { get => m_PressThreshold; set => m_PressThreshold = value; } [SerializeField] [Tooltip("The threshold value to use to determine when the button is released when it was previously pressed. Keeps being pressed until falls back to a value of or below this value.")] [Range(0f, 1f)] float m_ReleaseThreshold = 0.25f; /// /// The threshold value to use to determine when the button is released when it was previously pressed. /// Keeps being pressed until falls back to a value of or below this value. /// /// /// This reader will still be considered performed if the source input is still performed /// when this threshold is reached. /// public float releaseThreshold { get => m_ReleaseThreshold; set => m_ReleaseThreshold = value; } bool m_IsPerformed; bool m_WasPerformedThisFrame; bool m_WasCompletedThisFrame; /// /// See . /// void OnEnable() { m_ValueInput?.EnableDirectActionIfModeUsed(); } /// /// See . /// void OnDisable() { m_ValueInput?.DisableDirectActionIfModeUsed(); } /// /// See . /// void Update() { // Go true when either the press threshold is reached or the bool is already performed. // Only drop back to false when the release threshold is reached and the bool is no longer performed. var prevPerformed = m_IsPerformed; var pressAmount = m_ValueInput.ReadValue(); bool newValue; if (prevPerformed) newValue = pressAmount > m_ReleaseThreshold || m_ValueInput.ReadIsPerformed(); else newValue = pressAmount >= m_PressThreshold || m_ValueInput.ReadIsPerformed(); m_IsPerformed = newValue; m_WasPerformedThisFrame = !prevPerformed && m_IsPerformed; m_WasCompletedThisFrame = prevPerformed && !m_IsPerformed; } /// public bool ReadIsPerformed() { return m_IsPerformed; } /// public bool ReadWasPerformedThisFrame() { return m_WasPerformedThisFrame; } /// public bool ReadWasCompletedThisFrame() { return m_WasCompletedThisFrame; } /// public float ReadValue() { return m_ValueInput.ReadValue(); } /// public bool TryReadValue(out float value) { return m_ValueInput.TryReadValue(out value); } } }