Skip to content

Commit 48ed905

Browse files
committed
feat(Interaction): add near touch to interact haptics
The Interact Haptics script now has an option for initiating haptics on a near touch interaction event. The Interact Haptics script has also been refactored to use the Interactable Object events rather than having hard coded method calls from the interaction scripts (Touch/Grab/Use) to the Interact Haptics script. The Interactable Object script has a new method to help subscribe and unsubscribe from these interaction events and the Interact Object Highlighter has also been refactored to use these new event subscription helpers.
1 parent c24633e commit 48ed905

File tree

9 files changed

+391
-123
lines changed

9 files changed

+391
-123
lines changed

Assets/VRTK/Documentation/API.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4200,6 +4200,30 @@ The PerformSecondaryAction method returns whether the object has a secondary act
42004200

42014201
The ResetIgnoredColliders method is used to clear any stored ignored colliders in case the `Ignored Colliders` array parameter is changed at runtime. This needs to be called manually if changes are made at runtime.
42024202

4203+
#### SubscribeToInteractionEvent/2
4204+
4205+
> `public virtual void SubscribeToInteractionEvent(InteractionType givenType, InteractableObjectEventHandler methodCallback)`
4206+
4207+
* Parameters
4208+
* `InteractionType givenType` - The Interaction Type to register the events for.
4209+
* `InteractableObjectEventHandler methodCallback` - The method to execute when the Interaction Type is initiated.
4210+
* Returns
4211+
* _none_
4212+
4213+
The SubscribeToInteractionEvent method subscribes a given method callback for the given Interaction Type.
4214+
4215+
#### UnsubscribeFromInteractionEvent/2
4216+
4217+
> `public virtual void UnsubscribeFromInteractionEvent(InteractionType givenType, InteractableObjectEventHandler methodCallback)`
4218+
4219+
* Parameters
4220+
* `InteractionType givenType` - The Interaction Type that the previous event subscription was under.
4221+
* `InteractableObjectEventHandler methodCallback` - The method that was being executed when the Interaction Type was initiated.
4222+
* Returns
4223+
* _none_
4224+
4225+
The UnsubscribeFromInteractionEvent method unsubscribes a previous event subscription for the given Interaction Type.
4226+
42034227
### Example
42044228

42054229
`VRTK/Examples/005_Controller_BasicObjectGrabbing` uses the `VRTK_InteractTouch` and `VRTK_InteractGrab` scripts on the controllers to show how an interactable object can be grabbed and snapped to the controller and thrown around the game world.
@@ -4314,6 +4338,10 @@ The Interact Haptics script is attached on the same GameObject as an Interactabl
43144338

43154339
### Inspector Parameters
43164340

4341+
* **Clip On Near Touch:** Denotes the audio clip to use to rumble the controller on near touch.
4342+
* **Strength On Near Touch:** Denotes how strong the rumble in the controller will be on near touch.
4343+
* **Duration On Near Touch:** Denotes how long the rumble in the controller will last on near touch.
4344+
* **Interval On Near Touch:** Denotes interval betweens rumble in the controller on near touch.
43174345
* **Clip On Touch:** Denotes the audio clip to use to rumble the controller on touch.
43184346
* **Strength On Touch:** Denotes how strong the rumble in the controller will be on touch.
43194347
* **Duration On Touch:** Denotes how long the rumble in the controller will last on touch.
@@ -4326,9 +4354,11 @@ The Interact Haptics script is attached on the same GameObject as an Interactabl
43264354
* **Strength On Use:** Denotes how strong the rumble in the controller will be on use.
43274355
* **Duration On Use:** Denotes how long the rumble in the controller will last on use.
43284356
* **Interval On Use:** Denotes interval betweens rumble in the controller on use.
4357+
* **Object To Affect:** 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.
43294358

43304359
### Class Events
43314360

4361+
* `InteractHapticsNearTouched` - Emitted when the haptics are from a near touch.
43324362
* `InteractHapticsTouched` - Emitted when the haptics are from a touch.
43334363
* `InteractHapticsGrabbed` - Emitted when the haptics are from a grab.
43344364
* `InteractHapticsUsed` - Emitted when the haptics are from a use.
@@ -4345,6 +4375,28 @@ Adding the `VRTK_InteractHaptics_UnityEvents` component to `VRTK_InteractHaptics
43454375

43464376
### Class Methods
43474377

4378+
#### CancelHaptics/1
4379+
4380+
> `public virtual void CancelHaptics(VRTK_ControllerReference controllerReference)`
4381+
4382+
* Parameters
4383+
* `VRTK_ControllerReference controllerReference` -
4384+
* Returns
4385+
* _none_
4386+
4387+
The CancelHaptics method cancels any existing haptic feedback on the given controller.
4388+
4389+
#### HapticsOnNearTouch/1
4390+
4391+
> `public virtual void HapticsOnNearTouch(VRTK_ControllerReference controllerReference)`
4392+
4393+
* Parameters
4394+
* `VRTK_ControllerReference controllerReference` - The reference to the controller to activate the haptic feedback on.
4395+
* Returns
4396+
* _none_
4397+
4398+
The HapticsOnNearTouch method triggers the haptic feedback on the given controller for the settings associated with near touch.
4399+
43484400
#### HapticsOnTouch/1
43494401

43504402
> `public virtual void HapticsOnTouch(VRTK_ControllerReference controllerReference)`

Assets/VRTK/Source/Editor/VRTK_InteractHapticsEditor.cs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
[CustomEditor(typeof(VRTK_InteractHaptics))]
77
public class VRTK_InteractHapticsEditor : Editor
88
{
9+
SerializedProperty clipOnNearTouch;
10+
SerializedProperty strengthOnNearTouch;
11+
SerializedProperty durationOnNearTouch;
12+
SerializedProperty intervalOnNearTouch;
13+
914
SerializedProperty clipOnTouch;
1015
SerializedProperty strengthOnTouch;
1116
SerializedProperty durationOnTouch;
@@ -21,8 +26,15 @@ public class VRTK_InteractHapticsEditor : Editor
2126
SerializedProperty durationOnUse;
2227
SerializedProperty intervalOnUse;
2328

29+
SerializedProperty objectToAffect;
30+
2431
private void OnEnable()
2532
{
33+
clipOnNearTouch = serializedObject.FindProperty("clipOnNearTouch");
34+
strengthOnNearTouch = serializedObject.FindProperty("strengthOnNearTouch");
35+
durationOnNearTouch = serializedObject.FindProperty("durationOnNearTouch");
36+
intervalOnNearTouch = serializedObject.FindProperty("intervalOnNearTouch");
37+
2638
clipOnTouch = serializedObject.FindProperty("clipOnTouch");
2739
strengthOnTouch = serializedObject.FindProperty("strengthOnTouch");
2840
durationOnTouch = serializedObject.FindProperty("durationOnTouch");
@@ -37,14 +49,27 @@ private void OnEnable()
3749
strengthOnUse = serializedObject.FindProperty("strengthOnUse");
3850
durationOnUse = serializedObject.FindProperty("durationOnUse");
3951
intervalOnUse = serializedObject.FindProperty("intervalOnUse");
52+
53+
objectToAffect = serializedObject.FindProperty("objectToAffect");
4054
}
4155

4256
public override void OnInspectorGUI()
4357
{
4458
serializedObject.Update();
4559

4660
EditorGUILayout.Space();
47-
EditorGUILayout.LabelField("Haptics On Touch", EditorStyles.boldLabel);
61+
EditorGUILayout.LabelField("Haptics On Near Touch Settings", EditorStyles.boldLabel);
62+
63+
EditorGUILayout.ObjectField(clipOnNearTouch, typeof(AudioClip));
64+
if (clipOnNearTouch.objectReferenceValue == null)
65+
{
66+
EditorGUILayout.PropertyField(strengthOnNearTouch);
67+
EditorGUILayout.PropertyField(durationOnNearTouch);
68+
EditorGUILayout.PropertyField(intervalOnNearTouch);
69+
}
70+
71+
EditorGUILayout.Space();
72+
EditorGUILayout.LabelField("Haptics On Touch Settings", EditorStyles.boldLabel);
4873

4974
EditorGUILayout.ObjectField(clipOnTouch, typeof(AudioClip));
5075
if (clipOnTouch.objectReferenceValue == null)
@@ -55,7 +80,7 @@ public override void OnInspectorGUI()
5580
}
5681

5782
EditorGUILayout.Space();
58-
EditorGUILayout.LabelField("Haptics On Grab", EditorStyles.boldLabel);
83+
EditorGUILayout.LabelField("Haptics On Grab Settings", EditorStyles.boldLabel);
5984

6085
EditorGUILayout.ObjectField(clipOnGrab, typeof(AudioClip));
6186
if (clipOnGrab.objectReferenceValue == null)
@@ -66,7 +91,7 @@ public override void OnInspectorGUI()
6691
}
6792

6893
EditorGUILayout.Space();
69-
EditorGUILayout.LabelField("Haptics On Use", EditorStyles.boldLabel);
94+
EditorGUILayout.LabelField("Haptics On Use Settings", EditorStyles.boldLabel);
7095

7196
EditorGUILayout.ObjectField(clipOnUse, typeof(AudioClip));
7297
if (clipOnUse.objectReferenceValue == null)
@@ -76,6 +101,9 @@ public override void OnInspectorGUI()
76101
EditorGUILayout.PropertyField(intervalOnUse);
77102
}
78103

104+
EditorGUILayout.Space();
105+
EditorGUILayout.PropertyField(objectToAffect);
106+
79107
serializedObject.ApplyModifiedProperties();
80108
}
81109
}

Assets/VRTK/Source/Scripts/Interactions/VRTK_InteractGrab.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -499,18 +499,6 @@ protected virtual GameObject GetUndroppableObject()
499499
return null;
500500
}
501501

502-
protected virtual void AttemptHaptics(bool initialGrabAttempt)
503-
{
504-
if (grabbedObject != null && initialGrabAttempt)
505-
{
506-
VRTK_InteractHaptics doHaptics = grabbedObject.GetComponentInParent<VRTK_InteractHaptics>();
507-
if (doHaptics != null)
508-
{
509-
doHaptics.HapticsOnGrab(controllerReference);
510-
}
511-
}
512-
}
513-
514502
protected virtual void AttemptGrabObject()
515503
{
516504
GameObject objectToGrab = GetGrabbableObject();
@@ -529,7 +517,6 @@ protected virtual void PerformGrabAttempt(GameObject objectToGrab)
529517
IncrementGrabState();
530518
bool initialGrabAttempt = IsValidGrabAttempt(objectToGrab);
531519
undroppableGrabbedObject = GetUndroppableObject();
532-
AttemptHaptics(initialGrabAttempt);
533520
}
534521

535522
protected virtual bool ScriptValidGrab(VRTK_InteractableObject objectToGrabScript)

Assets/VRTK/Source/Scripts/Interactions/VRTK_InteractHaptics.cs

Lines changed: 116 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,19 @@ public struct InteractHapticsEventArgs
2525
[AddComponentMenu("VRTK/Scripts/Interactions/VRTK_InteractHaptics")]
2626
public class VRTK_InteractHaptics : MonoBehaviour
2727
{
28-
[Header("Haptics On Touch")]
28+
[Header("Haptics On Near Touch Settings")]
29+
30+
[Tooltip("Denotes the audio clip to use to rumble the controller on near touch.")]
31+
public AudioClip clipOnNearTouch;
32+
[Tooltip("Denotes how strong the rumble in the controller will be on near touch.")]
33+
[Range(0, 1)]
34+
public float strengthOnNearTouch = 0;
35+
[Tooltip("Denotes how long the rumble in the controller will last on near touch.")]
36+
public float durationOnNearTouch = 0f;
37+
[Tooltip("Denotes interval betweens rumble in the controller on near touch.")]
38+
public float intervalOnNearTouch = minInterval;
39+
40+
[Header("Haptics On Touch Settings")]
2941

3042
[Tooltip("Denotes the audio clip to use to rumble the controller on touch.")]
3143
public AudioClip clipOnTouch;
@@ -37,7 +49,7 @@ public class VRTK_InteractHaptics : MonoBehaviour
3749
[Tooltip("Denotes interval betweens rumble in the controller on touch.")]
3850
public float intervalOnTouch = minInterval;
3951

40-
[Header("Haptics On Grab")]
52+
[Header("Haptics On Grab Settings")]
4153

4254
[Tooltip("Denotes the audio clip to use to rumble the controller on grab.")]
4355
public AudioClip clipOnGrab;
@@ -49,7 +61,7 @@ public class VRTK_InteractHaptics : MonoBehaviour
4961
[Tooltip("Denotes interval betweens rumble in the controller on grab.")]
5062
public float intervalOnGrab = minInterval;
5163

52-
[Header("Haptics On Use")]
64+
[Header("Haptics On Use Settings")]
5365

5466
[Tooltip("Denotes the audio clip to use to rumble the controller on use.")]
5567
public AudioClip clipOnUse;
@@ -61,6 +73,15 @@ public class VRTK_InteractHaptics : MonoBehaviour
6173
[Tooltip("Denotes interval betweens rumble in the controller on use.")]
6274
public float intervalOnUse = minInterval;
6375

76+
[Header("Custom Settings")]
77+
78+
[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.")]
79+
public VRTK_InteractableObject objectToAffect;
80+
81+
/// <summary>
82+
/// Emitted when the haptics are from a near touch.
83+
/// </summary>
84+
public event InteractHapticsEventHandler InteractHapticsNearTouched;
6485
/// <summary>
6586
/// Emitted when the haptics are from a touch.
6687
/// </summary>
@@ -76,6 +97,14 @@ public class VRTK_InteractHaptics : MonoBehaviour
7697

7798
protected const float minInterval = 0.05f;
7899

100+
public virtual void OnInteractHapticsNearTouched(InteractHapticsEventArgs e)
101+
{
102+
if (InteractHapticsNearTouched != null)
103+
{
104+
InteractHapticsNearTouched(this, e);
105+
}
106+
}
107+
79108
public virtual void OnInteractHapticsTouched(InteractHapticsEventArgs e)
80109
{
81110
if (InteractHapticsTouched != null)
@@ -100,6 +129,32 @@ public virtual void OnInteractHapticsUsed(InteractHapticsEventArgs e)
100129
}
101130
}
102131

132+
/// <summary>
133+
/// The CancelHaptics method cancels any existing haptic feedback on the given controller.
134+
/// </summary>
135+
/// <param name="controllerReference"></param>
136+
public virtual void CancelHaptics(VRTK_ControllerReference controllerReference)
137+
{
138+
VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
139+
}
140+
141+
/// <summary>
142+
/// The HapticsOnNearTouch method triggers the haptic feedback on the given controller for the settings associated with near touch.
143+
/// </summary>
144+
/// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
145+
public virtual void HapticsOnNearTouch(VRTK_ControllerReference controllerReference)
146+
{
147+
if (clipOnNearTouch != null)
148+
{
149+
VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnNearTouch);
150+
}
151+
else if (strengthOnNearTouch > 0 && durationOnNearTouch > 0f)
152+
{
153+
TriggerHapticPulse(controllerReference, strengthOnNearTouch, durationOnNearTouch, intervalOnNearTouch);
154+
}
155+
OnInteractHapticsNearTouched(SetEventPayload(controllerReference));
156+
}
157+
103158
/// <summary>
104159
/// The HapticsOnTouch method triggers the haptic feedback on the given controller for the settings associated with touch.
105160
/// </summary>
@@ -153,9 +208,29 @@ public virtual void HapticsOnUse(VRTK_ControllerReference controllerReference)
153208

154209
protected virtual void OnEnable()
155210
{
156-
if (!GetComponent<VRTK_InteractableObject>())
211+
objectToAffect = (objectToAffect != null ? objectToAffect : GetComponentInParent<VRTK_InteractableObject>());
212+
213+
if (objectToAffect != null)
157214
{
158-
VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_InteractHaptics", "VRTK_InteractableObject", "the same"));
215+
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.NearTouch, NearTouchHaptics);
216+
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Touch, TouchHaptics);
217+
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Grab, GrabHaptics);
218+
objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Use, UseHaptics);
219+
}
220+
else
221+
{
222+
VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_InteractHaptics", "VRTK_InteractableObject", "the same or parent"));
223+
}
224+
}
225+
226+
protected virtual void OnDisable()
227+
{
228+
if (objectToAffect != null)
229+
{
230+
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.NearTouch, NearTouchHaptics);
231+
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Touch, TouchHaptics);
232+
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Grab, GrabHaptics);
233+
objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Use, UseHaptics);
159234
}
160235
}
161236

@@ -170,5 +245,41 @@ protected virtual InteractHapticsEventArgs SetEventPayload(VRTK_ControllerRefere
170245
e.controllerReference = givenControllerReference;
171246
return e;
172247
}
248+
249+
protected virtual void NearTouchHaptics(object sender, InteractableObjectEventArgs e)
250+
{
251+
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
252+
if (VRTK_ControllerReference.IsValid(controllerReference))
253+
{
254+
HapticsOnNearTouch(controllerReference);
255+
}
256+
}
257+
258+
protected virtual void TouchHaptics(object sender, InteractableObjectEventArgs e)
259+
{
260+
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
261+
if (VRTK_ControllerReference.IsValid(controllerReference))
262+
{
263+
HapticsOnTouch(controllerReference);
264+
}
265+
}
266+
267+
protected virtual void GrabHaptics(object sender, InteractableObjectEventArgs e)
268+
{
269+
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
270+
if (VRTK_ControllerReference.IsValid(controllerReference))
271+
{
272+
HapticsOnGrab(controllerReference);
273+
}
274+
}
275+
276+
protected virtual void UseHaptics(object sender, InteractableObjectEventArgs e)
277+
{
278+
VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
279+
if (VRTK_ControllerReference.IsValid(controllerReference))
280+
{
281+
HapticsOnUse(controllerReference);
282+
}
283+
}
173284
}
174285
}

0 commit comments

Comments
 (0)