Skip to content

Commit 2fe201d

Browse files
committed
fix(Interaction): ensure controllers preserve the correct visibility
The Interact Object Appearance script was incorrectly hiding controller visibility when both controllers would touch the object. This was because the cached object state was only for the last object that interacted, however an existing interacting controller could be overridden by a new interacting controller which would then prevent the previous controller from regaining the correct visibility state. The fix is to ensure the object state is cached accordingly. Another issue was how it was storing the coroutines for each interaction event as it was storing them per interaction not per object that was interacting. This would mean that if both controllers touched the same object at the same time, then one would cancel the coroutine of the other. This has been fixed by grouping the coroutines with the object they are to affect.
1 parent 321ee82 commit 2fe201d

File tree

1 file changed

+62
-66
lines changed

1 file changed

+62
-66
lines changed

Assets/VRTK/Scripts/Interactions/VRTK_InteractObjectAppearance.cs

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ namespace VRTK
33
{
44
using UnityEngine;
55
using System.Collections;
6+
using System.Collections.Generic;
67

78
/// <summary>
89
/// Event Payload
@@ -146,15 +147,10 @@ public enum ValidInteractingObject
146147
/// </summary>
147148
public event InteractObjectAppearanceEventHandler RenderersDisabled;
148149

149-
protected GameObject touchAffectedObject;
150-
protected GameObject grabAffectedObject;
151-
protected GameObject useAffectedObject;
152-
protected Coroutine touchRoutine;
153-
protected Coroutine grabRoutine;
154-
protected Coroutine useRoutine;
155-
protected bool currentRenderState;
156-
protected bool currentGameObjectState;
157-
protected bool currentStatesSet;
150+
protected Dictionary<GameObject, bool> currentRenderStates = new Dictionary<GameObject, bool>();
151+
protected Dictionary<GameObject, bool> currentGameObjectStates = new Dictionary<GameObject, bool>();
152+
protected Dictionary<GameObject, Coroutine> affectingRoutines = new Dictionary<GameObject, Coroutine>();
153+
protected List<GameObject> touchingObjects = new List<GameObject>();
158154

159155
public virtual void OnGameObjectEnabled(InteractObjectAppearanceEventArgs e)
160156
{
@@ -190,7 +186,10 @@ public virtual void OnRenderersDisabled(InteractObjectAppearanceEventArgs e)
190186

191187
protected virtual void OnEnable()
192188
{
193-
currentStatesSet = false;
189+
currentRenderStates.Clear();
190+
currentGameObjectStates.Clear();
191+
affectingRoutines.Clear();
192+
touchingObjects.Clear();
194193
objectToMonitor = (objectToMonitor == null ? GetComponentInParent<VRTK_InteractableObject>() : objectToMonitor);
195194

196195
if (objectToMonitor != null)
@@ -227,7 +226,7 @@ protected virtual void OnDisable()
227226
objectToMonitor.InteractableObjectUsed -= InteractableObjectUsed;
228227
objectToMonitor.InteractableObjectUnused -= InteractableObjectUnused;
229228
}
230-
CancelAllRoutines();
229+
CancelRoutines();
231230
}
232231

233232
protected virtual InteractObjectAppearanceEventArgs SetPayload(GameObject affectingObject, InteractionType interactionType)
@@ -244,7 +243,10 @@ protected virtual void RestoreDefaults()
244243
{
245244
if (objectToMonitor != null && objectToMonitor.IsTouched())
246245
{
247-
ToggleState(touchAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, InteractionType.None);
246+
for (int i = 0; i < touchingObjects.Count; i++)
247+
{
248+
ToggleState(touchingObjects[i], gameObjectActiveByDefault, rendererVisibleByDefault, InteractionType.None);
249+
}
248250
}
249251
}
250252

@@ -281,21 +283,20 @@ protected virtual void ToggleState(GameObject objectToToggle, bool gameObjectSho
281283
{
282284
if (objectToToggle != null)
283285
{
284-
if (!currentStatesSet || currentRenderState != rendererShow)
286+
if (!currentRenderStates.ContainsKey(objectToToggle) || currentRenderStates[objectToToggle] != rendererShow)
285287
{
286288
VRTK_ObjectAppearance.ToggleRenderer(rendererShow, objectToToggle, ObjectToIgnore());
287289
EmitRenderEvent(objectToToggle, rendererShow, interactionType);
288290
}
289291

290-
if (!currentStatesSet || currentGameObjectState != gameObjectShow)
292+
if (!currentGameObjectStates.ContainsKey(objectToToggle) || currentGameObjectStates[objectToToggle] != gameObjectShow)
291293
{
292294
objectToToggle.SetActive(gameObjectShow);
293295
EmitGameObjectEvent(objectToToggle, gameObjectShow, interactionType);
294296
}
295297

296-
currentRenderState = rendererShow;
297-
currentGameObjectState = gameObjectShow;
298-
currentStatesSet = true;
298+
currentRenderStates[objectToToggle] = rendererShow;
299+
currentGameObjectStates[objectToToggle] = gameObjectShow;
299300
}
300301
}
301302

@@ -305,37 +306,24 @@ protected virtual IEnumerator ToggleStateAfterTime(GameObject objectToToggle, bo
305306
ToggleState(objectToToggle, gameObjectShow, rendererShow, interactionType);
306307
}
307308

308-
protected virtual void CancelAllRoutines()
309-
{
310-
CancelTouchRoutine();
311-
CancelGrabRoutine();
312-
CancelUseRoutine();
313-
}
314-
315-
protected virtual void CancelTouchRoutine()
309+
protected virtual void CancelRoutines(GameObject currentAffectingObject = null)
316310
{
317-
if (touchRoutine != null)
311+
if (currentAffectingObject != null)
318312
{
319-
StopCoroutine(touchRoutine);
320-
touchRoutine = null;
321-
}
322-
}
323-
324-
protected virtual void CancelGrabRoutine()
325-
{
326-
if (grabRoutine != null)
327-
{
328-
StopCoroutine(grabRoutine);
329-
grabRoutine = null;
313+
if (affectingRoutines.ContainsKey(currentAffectingObject) && affectingRoutines[currentAffectingObject] != null)
314+
{
315+
StopCoroutine(affectingRoutines[currentAffectingObject]);
316+
}
330317
}
331-
}
332-
333-
protected virtual void CancelUseRoutine()
334-
{
335-
if (useRoutine != null)
318+
else
336319
{
337-
StopCoroutine(useRoutine);
338-
useRoutine = null;
320+
foreach (KeyValuePair<GameObject, Coroutine> affectingRouting in affectingRoutines)
321+
{
322+
if (currentAffectingObject == affectingRouting.Key && affectingRouting.Value != null)
323+
{
324+
StopCoroutine(affectingRouting.Value);
325+
}
326+
}
339327
}
340328
}
341329

@@ -386,81 +374,89 @@ protected virtual void InteractableObjectTouched(object sender, InteractableObje
386374
{
387375
if (IsValidInteractingObject(e.interactingObject, validTouchInteractingObject))
388376
{
389-
CancelAllRoutines();
390-
touchAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
391-
touchRoutine = StartCoroutine(ToggleStateAfterTime(touchAffectedObject, gameObjectActiveOnTouch, rendererVisibleOnTouch, touchAppearanceDelay, InteractionType.Touch));
377+
GameObject touchAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
378+
CancelRoutines(touchAffectedObject);
379+
if (!touchingObjects.Contains(touchAffectedObject))
380+
{
381+
touchingObjects.Add(touchAffectedObject);
382+
}
383+
affectingRoutines[touchAffectedObject] = StartCoroutine(ToggleStateAfterTime(touchAffectedObject, gameObjectActiveOnTouch, rendererVisibleOnTouch, touchAppearanceDelay, InteractionType.Touch));
392384
}
393385
}
394386

395387
protected virtual void InteractableObjectUntouched(object sender, InteractableObjectEventArgs e)
396388
{
397389
if (IsValidInteractingObject(e.interactingObject, validTouchInteractingObject))
398390
{
399-
CancelAllRoutines();
400-
touchRoutine = StartCoroutine(ToggleStateAfterTime(touchAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, untouchAppearanceDelay, InteractionType.Untouch));
401-
touchAffectedObject = null;
391+
GameObject touchAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
392+
CancelRoutines(touchAffectedObject);
393+
if (touchingObjects.Contains(touchAffectedObject))
394+
{
395+
touchingObjects.Remove(touchAffectedObject);
396+
}
397+
affectingRoutines[touchAffectedObject] = StartCoroutine(ToggleStateAfterTime(touchAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, untouchAppearanceDelay, InteractionType.Untouch));
402398
}
403399
}
404400

405401
protected virtual void InteractableObjectGrabbed(object sender, InteractableObjectEventArgs e)
406402
{
407403
if (IsValidInteractingObject(e.interactingObject, validGrabInteractingObject))
408404
{
409-
CancelAllRoutines();
410-
grabAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
411-
grabRoutine = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveOnGrab, rendererVisibleOnGrab, grabAppearanceDelay, InteractionType.Grab));
405+
GameObject grabAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
406+
CancelRoutines(grabAffectedObject);
407+
affectingRoutines[grabAffectedObject] = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveOnGrab, rendererVisibleOnGrab, grabAppearanceDelay, InteractionType.Grab));
412408
}
413409
}
414410

415411
protected virtual void InteractableObjectUngrabbed(object sender, InteractableObjectEventArgs e)
416412
{
417413
if (IsValidInteractingObject(e.interactingObject, validGrabInteractingObject))
418414
{
419-
CancelAllRoutines();
415+
GameObject grabAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
416+
CancelRoutines(grabAffectedObject);
420417
if (objectToMonitor.IsUsing())
421418
{
422-
grabRoutine = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveOnUse, rendererVisibleOnUse, ungrabAppearanceDelay, InteractionType.Ungrab));
419+
affectingRoutines[grabAffectedObject] = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveOnUse, rendererVisibleOnUse, ungrabAppearanceDelay, InteractionType.Ungrab));
423420
}
424421
else if (objectToMonitor.IsTouched())
425422
{
426-
grabRoutine = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveOnTouch, rendererVisibleOnTouch, ungrabAppearanceDelay, InteractionType.Ungrab));
423+
affectingRoutines[grabAffectedObject] = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveOnTouch, rendererVisibleOnTouch, ungrabAppearanceDelay, InteractionType.Ungrab));
427424
}
428425
else
429426
{
430-
grabRoutine = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, ungrabAppearanceDelay, InteractionType.Ungrab));
427+
affectingRoutines[grabAffectedObject] = StartCoroutine(ToggleStateAfterTime(grabAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, ungrabAppearanceDelay, InteractionType.Ungrab));
431428
}
432-
grabAffectedObject = null;
433429
}
434430
}
435431

436432
protected virtual void InteractableObjectUsed(object sender, InteractableObjectEventArgs e)
437433
{
438434
if (IsValidInteractingObject(e.interactingObject, validUseInteractingObject))
439435
{
440-
CancelAllRoutines();
441-
useAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
442-
useRoutine = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveOnUse, rendererVisibleOnUse, useAppearanceDelay, InteractionType.Use));
436+
GameObject useAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
437+
CancelRoutines(useAffectedObject);
438+
affectingRoutines[useAffectedObject] = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveOnUse, rendererVisibleOnUse, useAppearanceDelay, InteractionType.Use));
443439
}
444440
}
445441

446442
protected virtual void InteractableObjectUnused(object sender, InteractableObjectEventArgs e)
447443
{
448444
if (IsValidInteractingObject(e.interactingObject, validUseInteractingObject))
449445
{
450-
CancelAllRoutines();
446+
GameObject useAffectedObject = (objectToAffect == null ? GetActualController(e.interactingObject) : objectToAffect);
447+
CancelRoutines(useAffectedObject);
451448
if (objectToMonitor.IsGrabbed())
452449
{
453-
useRoutine = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveOnGrab, rendererVisibleOnGrab, unuseAppearanceDelay, InteractionType.Unuse));
450+
affectingRoutines[useAffectedObject] = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveOnGrab, rendererVisibleOnGrab, unuseAppearanceDelay, InteractionType.Unuse));
454451
}
455452
else if (objectToMonitor.IsTouched())
456453
{
457-
useRoutine = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveOnTouch, rendererVisibleOnTouch, unuseAppearanceDelay, InteractionType.Unuse));
454+
affectingRoutines[useAffectedObject] = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveOnTouch, rendererVisibleOnTouch, unuseAppearanceDelay, InteractionType.Unuse));
458455
}
459456
else
460457
{
461-
useRoutine = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, unuseAppearanceDelay, InteractionType.Unuse));
458+
affectingRoutines[useAffectedObject] = StartCoroutine(ToggleStateAfterTime(useAffectedObject, gameObjectActiveByDefault, rendererVisibleByDefault, unuseAppearanceDelay, InteractionType.Unuse));
462459
}
463-
useAffectedObject = null;
464460
}
465461
}
466462
}

0 commit comments

Comments
 (0)