// Interact Haptics|Interactables|35020
namespace VRTK
{
using UnityEngine;
///
/// Event Payload
///
/// The reference to the controller to perform haptics on.
public struct InteractHapticsEventArgs
{
public VRTK_ControllerReference controllerReference;
}
///
/// Event Payload
///
/// this object
///
public delegate void InteractHapticsEventHandler(object sender, InteractHapticsEventArgs e);
///
/// Provides controller haptics upon interaction with the specified Interactable Object.
///
///
/// **Required Components:**
/// * `VRTK_InteractableObject` - The Interactable Object component to detect interactions on. This must be applied on the same GameObject as this script if one is not provided via the `Object To Affect` parameter.
///
/// **Script Usage:**
/// * Place the `VRTK_InteractHaptics` script on either:
/// * The GameObject of the Interactable Object to detect interactions on.
/// * Any other scene GameObject and provide a valid `VRTK_InteractableObject` component to the `Object To Affect` parameter of this script.
///
[AddComponentMenu("VRTK/Scripts/Interactions/Interactables/VRTK_InteractHaptics")]
public class VRTK_InteractHaptics : VRTK_InteractableListener
{
[Header("Haptics On Near Touch Settings")]
[Tooltip("Denotes the audio clip to use to rumble the controller on near touch.")]
public AudioClip clipOnNearTouch;
[Tooltip("Denotes how strong the rumble in the controller will be on near touch.")]
[Range(0, 1)]
public float strengthOnNearTouch = 0;
[Tooltip("Denotes how long the rumble in the controller will last on near touch.")]
public float durationOnNearTouch = 0f;
[Tooltip("Denotes interval betweens rumble in the controller on near touch.")]
public float intervalOnNearTouch = minInterval;
[Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer near touching.")]
public bool cancelOnNearUntouch = true;
[Header("Haptics On Touch Settings")]
[Tooltip("Denotes the audio clip to use to rumble the controller on touch.")]
public AudioClip clipOnTouch;
[Tooltip("Denotes how strong the rumble in the controller will be on touch.")]
[Range(0, 1)]
public float strengthOnTouch = 0;
[Tooltip("Denotes how long the rumble in the controller will last on touch.")]
public float durationOnTouch = 0f;
[Tooltip("Denotes interval betweens rumble in the controller on touch.")]
public float intervalOnTouch = minInterval;
[Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer touching.")]
public bool cancelOnUntouch = true;
[Header("Haptics On Grab Settings")]
[Tooltip("Denotes the audio clip to use to rumble the controller on grab.")]
public AudioClip clipOnGrab;
[Tooltip("Denotes how strong the rumble in the controller will be on grab.")]
[Range(0, 1)]
public float strengthOnGrab = 0;
[Tooltip("Denotes how long the rumble in the controller will last on grab.")]
public float durationOnGrab = 0f;
[Tooltip("Denotes interval betweens rumble in the controller on grab.")]
public float intervalOnGrab = minInterval;
[Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer grabbing.")]
public bool cancelOnUngrab = true;
[Header("Haptics On Use Settings")]
[Tooltip("Denotes the audio clip to use to rumble the controller on use.")]
public AudioClip clipOnUse;
[Tooltip("Denotes how strong the rumble in the controller will be on use.")]
[Range(0, 1)]
public float strengthOnUse = 0;
[Tooltip("Denotes how long the rumble in the controller will last on use.")]
public float durationOnUse = 0f;
[Tooltip("Denotes interval betweens rumble in the controller on use.")]
public float intervalOnUse = minInterval;
[Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer using.")]
public bool cancelOnUnuse = true;
[Header("Custom Settings")]
[Tooltip("The Interactable Object to initiate the haptics from. If this is left blank, then the Interactable Object will need to be on the current or a parent GameObject.")]
public VRTK_InteractableObject objectToAffect;
///
/// Emitted when the haptics are from a near touch.
///
public event InteractHapticsEventHandler InteractHapticsNearTouched;
///
/// Emitted when the haptics are from a touch.
///
public event InteractHapticsEventHandler InteractHapticsTouched;
///
/// Emitted when the haptics are from a grab.
///
public event InteractHapticsEventHandler InteractHapticsGrabbed;
///
/// Emitted when the haptics are from a use.
///
public event InteractHapticsEventHandler InteractHapticsUsed;
protected const float minInterval = 0.05f;
public virtual void OnInteractHapticsNearTouched(InteractHapticsEventArgs e)
{
if (InteractHapticsNearTouched != null)
{
InteractHapticsNearTouched(this, e);
}
}
public virtual void OnInteractHapticsTouched(InteractHapticsEventArgs e)
{
if (InteractHapticsTouched != null)
{
InteractHapticsTouched(this, e);
}
}
public virtual void OnInteractHapticsGrabbed(InteractHapticsEventArgs e)
{
if (InteractHapticsGrabbed != null)
{
InteractHapticsGrabbed(this, e);
}
}
public virtual void OnInteractHapticsUsed(InteractHapticsEventArgs e)
{
if (InteractHapticsUsed != null)
{
InteractHapticsUsed(this, e);
}
}
///
/// The CancelHaptics method cancels any existing haptic feedback on the given controller.
///
///
public virtual void CancelHaptics(VRTK_ControllerReference controllerReference)
{
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
}
///
/// The HapticsOnNearTouch method triggers the haptic feedback on the given controller for the settings associated with near touch.
///
/// The reference to the controller to activate the haptic feedback on.
public virtual void HapticsOnNearTouch(VRTK_ControllerReference controllerReference)
{
if (clipOnNearTouch != null)
{
VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnNearTouch);
}
else if (strengthOnNearTouch > 0 && durationOnNearTouch > 0f)
{
TriggerHapticPulse(controllerReference, strengthOnNearTouch, durationOnNearTouch, intervalOnNearTouch);
}
else
{
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
}
OnInteractHapticsNearTouched(SetEventPayload(controllerReference));
}
///
/// The HapticsOnTouch method triggers the haptic feedback on the given controller for the settings associated with touch.
///
/// The reference to the controller to activate the haptic feedback on.
public virtual void HapticsOnTouch(VRTK_ControllerReference controllerReference)
{
if (clipOnTouch != null)
{
VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnTouch);
}
else if (strengthOnTouch > 0 && durationOnTouch > 0f)
{
TriggerHapticPulse(controllerReference, strengthOnTouch, durationOnTouch, intervalOnTouch);
}
else
{
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
}
OnInteractHapticsTouched(SetEventPayload(controllerReference));
}
///
/// The HapticsOnGrab method triggers the haptic feedback on the given controller for the settings associated with grab.
///
/// The reference to the controller to activate the haptic feedback on.
public virtual void HapticsOnGrab(VRTK_ControllerReference controllerReference)
{
if (clipOnGrab != null)
{
VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnGrab);
}
else if (strengthOnGrab > 0 && durationOnGrab > 0f)
{
TriggerHapticPulse(controllerReference, strengthOnGrab, durationOnGrab, intervalOnGrab);
}
else
{
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
}
OnInteractHapticsGrabbed(SetEventPayload(controllerReference));
}
///
/// The HapticsOnUse method triggers the haptic feedback on the given controller for the settings associated with use.
///
/// The reference to the controller to activate the haptic feedback on.
public virtual void HapticsOnUse(VRTK_ControllerReference controllerReference)
{
if (clipOnUse != null)
{
VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnUse);
}
else if (strengthOnUse > 0 && durationOnUse > 0f)
{
TriggerHapticPulse(controllerReference, strengthOnUse, durationOnUse, intervalOnUse);
}
else
{
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
}
OnInteractHapticsUsed(SetEventPayload(controllerReference));
}
protected virtual void OnEnable()
{
EnableListeners();
}
protected virtual void OnDisable()
{
DisableListeners();
}
protected override bool SetupListeners(bool throwError)
{
objectToAffect = (objectToAffect != null ? objectToAffect : GetComponentInParent());
if (objectToAffect != null)
{
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.NearUntouch, CancelNearTouchHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Untouch, CancelTouchHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Ungrab, CancelGrabHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Unuse, CancelUseHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.NearTouch, NearTouchHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Touch, TouchHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Grab, GrabHaptics);
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Use, UseHaptics);
return true;
}
else if (throwError)
{
VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_InteractHaptics", "VRTK_InteractableObject", "the same or parent"));
}
return false;
}
protected override void TearDownListeners()
{
if (objectToAffect != null)
{
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.NearUntouch, CancelNearTouchHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Untouch, CancelTouchHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Ungrab, CancelGrabHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Unuse, CancelUseHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.NearTouch, NearTouchHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Touch, TouchHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Grab, GrabHaptics);
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Use, UseHaptics);
}
}
protected virtual void TriggerHapticPulse(VRTK_ControllerReference controllerReference, float strength, float duration, float interval)
{
VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, strength, duration, (interval >= minInterval ? interval : minInterval));
}
protected virtual InteractHapticsEventArgs SetEventPayload(VRTK_ControllerReference givenControllerReference)
{
InteractHapticsEventArgs e;
e.controllerReference = givenControllerReference;
return e;
}
protected virtual void NearTouchHaptics(object sender, InteractableObjectEventArgs e)
{
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
if (VRTK_ControllerReference.IsValid(controllerReference))
{
HapticsOnNearTouch(controllerReference);
}
}
protected virtual void TouchHaptics(object sender, InteractableObjectEventArgs e)
{
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
if (VRTK_ControllerReference.IsValid(controllerReference))
{
HapticsOnTouch(controllerReference);
}
}
protected virtual void GrabHaptics(object sender, InteractableObjectEventArgs e)
{
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
if (VRTK_ControllerReference.IsValid(controllerReference))
{
HapticsOnGrab(controllerReference);
}
}
protected virtual void UseHaptics(object sender, InteractableObjectEventArgs e)
{
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
if (VRTK_ControllerReference.IsValid(controllerReference))
{
HapticsOnUse(controllerReference);
}
}
protected virtual void CancelOn(GameObject givenObject)
{
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(givenObject);
if (VRTK_ControllerReference.IsValid(controllerReference))
{
CancelHaptics(controllerReference);
}
}
protected virtual void CancelNearTouchHaptics(object sender, InteractableObjectEventArgs e)
{
if (cancelOnNearUntouch)
{
CancelOn(e.interactingObject);
}
}
protected virtual void CancelTouchHaptics(object sender, InteractableObjectEventArgs e)
{
if (cancelOnUntouch)
{
CancelOn(e.interactingObject);
}
}
protected virtual void CancelGrabHaptics(object sender, InteractableObjectEventArgs e)
{
if (cancelOnUngrab)
{
CancelOn(e.interactingObject);
}
}
protected virtual void CancelUseHaptics(object sender, InteractableObjectEventArgs e)
{
if (cancelOnUnuse)
{
CancelOn(e.interactingObject);
}
}
}
}