|
// Interact Haptics|Interactables|35020
|
|
namespace VRTK
|
|
{
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Event Payload
|
|
/// </summary>
|
|
/// <param name="controllerReference">The reference to the controller to perform haptics on.</param>
|
|
public struct InteractHapticsEventArgs
|
|
{
|
|
public VRTK_ControllerReference controllerReference;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event Payload
|
|
/// </summary>
|
|
/// <param name="sender">this object</param>
|
|
/// <param name="e"><see cref="InteractHapticsEventArgs"/></param>
|
|
public delegate void InteractHapticsEventHandler(object sender, InteractHapticsEventArgs e);
|
|
|
|
/// <summary>
|
|
/// Provides controller haptics upon interaction with the specified Interactable Object.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// **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.
|
|
/// </remarks>
|
|
[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;
|
|
|
|
/// <summary>
|
|
/// Emitted when the haptics are from a near touch.
|
|
/// </summary>
|
|
public event InteractHapticsEventHandler InteractHapticsNearTouched;
|
|
/// <summary>
|
|
/// Emitted when the haptics are from a touch.
|
|
/// </summary>
|
|
public event InteractHapticsEventHandler InteractHapticsTouched;
|
|
/// <summary>
|
|
/// Emitted when the haptics are from a grab.
|
|
/// </summary>
|
|
public event InteractHapticsEventHandler InteractHapticsGrabbed;
|
|
/// <summary>
|
|
/// Emitted when the haptics are from a use.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The CancelHaptics method cancels any existing haptic feedback on the given controller.
|
|
/// </summary>
|
|
/// <param name="controllerReference"></param>
|
|
public virtual void CancelHaptics(VRTK_ControllerReference controllerReference)
|
|
{
|
|
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The HapticsOnNearTouch method triggers the haptic feedback on the given controller for the settings associated with near touch.
|
|
/// </summary>
|
|
/// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
|
|
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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The HapticsOnTouch method triggers the haptic feedback on the given controller for the settings associated with touch.
|
|
/// </summary>
|
|
/// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
|
|
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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The HapticsOnGrab method triggers the haptic feedback on the given controller for the settings associated with grab.
|
|
/// </summary>
|
|
/// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
|
|
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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The HapticsOnUse method triggers the haptic feedback on the given controller for the settings associated with use.
|
|
/// </summary>
|
|
/// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
|
|
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<VRTK_InteractableObject>());
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|