Skip to main content
Applies to: Molca VR SDK

Overview

This recipe shows you how to create custom VR interaction components by extending MolcaInteractionBase. You’ll implement specialized interaction logic that responds to XR Interaction Toolkit events, integrate with the reference system for step-based validation, and add custom per-frame behavior while users interact with objects. This approach is ideal for creating unique interactions beyond standard grab mechanics—like levers, switches, dials, or custom analog controls.

Prerequisites

Step-by-step

Step 1: Create a custom interaction class

Create a new C# script that extends MolcaInteractionBase and implements the UpdateInteraction() method for per-frame logic.
Why this works: MolcaInteractionBase automatically binds to the XRBaseInteractable on the same GameObject during Awake, tracks selectEntered/selectExited events, and calls UpdateInteraction() only while isInteracting is true. You focus on the interaction logic without managing XRI event wiring.

Step 2: Add XR Interactable component

Add an XRGrabInteractable (or XRSimpleInteractable) component to the same GameObject as your custom interaction script.
Why this works: MolcaInteractionBase.Awake() automatically discovers the XRBaseInteractable on the same GameObject via GetComponent<XRBaseInteractable>(). If you need to reference an interactable on a different GameObject, assign it manually to the interactable field in the Inspector.

Step 3: Add ReferenceableComponent for step integration

Add a ReferenceableComponent to enable reference-based lookups from VR steps.
Why this works: MolcaInteractionBase registers itself with ReferenceManager after RuntimeManager.WaitForInitialization() completes. This allows VR steps to find your interaction component by reference ID using ReferenceManager.GetReference<LeverInteraction>(refId).

Step 4: Implement interaction events

Add Unity events or C# events to expose interaction state changes to other systems.
Why this works: Unity events appear in the Inspector and can be wired to other components without code. C# events (using System.Action or custom delegates) provide type-safe callbacks for code-based integration. Both patterns work well with the step system for completion validation.

Step 5: Add optional distance-based force release

Configure maxInteractionDistance to automatically release the interaction when the hand moves too far away.
Why this works: MolcaInteractionBase checks distance every frame in Update() when maxInteractionDistance > 0. If the hand exceeds this distance, it calls ForceRelease() which triggers selectExited on the interactable, ending the interaction gracefully.

Step 6: Test in VR

Enter Play mode with VR active and test your custom interaction.
Why this works: MolcaInteractionBase handles all XRI event wiring automatically. Your UpdateInteraction() method only runs while the user is actively interacting, so you can safely assume currentInteractor is valid and isInteracting is true.

Complete example

Here’s a complete custom button interaction that requires the user to press and hold for a duration:
This button interaction provides visual feedback, tracks hold progress, and fires events at key moments. Wire onHoldComplete to a custom step’s Complete() method for step-based validation.

Troubleshooting

  • UpdateInteraction() never called: Verify the GameObject has an XRBaseInteractable component (XRGrabInteractable or XRSimpleInteractable). Check that the interactable is enabled and the XR rig is active. Ensure isInteracting is true by adding Debug.Log(isInteracting) in Update().
  • Interactable field is null: MolcaInteractionBase.Awake() only searches the same GameObject. If your interactable is on a child or parent, assign it manually in the Inspector to the interactable field.
  • Reference not found by steps: Ensure ReferenceableComponent is attached and has a stable ID (check Inspector). Verify RuntimeManager.WaitForInitialization() completes before steps try to resolve references. Check that ReferenceManager subsystem is active.
  • Interaction releases unexpectedly: Check maxInteractionDistance value. If set too low, the hand will exceed the distance and trigger ForceRelease(). Set to 0 to disable distance checks entirely.
  • Events don’t fire: Verify Unity events are wired in the Inspector (expand the event section and add listeners). For C# events, ensure subscribers are registered in OnEnable and unregistered in OnDisable to avoid memory leaks.
  • Hand position jitter: Use smoothing or damping on hand position calculations. Consider using Mathf.Lerp() or Vector3.Lerp() to smooth rotation/position updates. Check XR tracking quality in your headset settings.