Interaction Controller
InteractionController is a component in OctoXR that is used for driving hovering and interactions between Interactors and Interactables. It is associated with one or more Interactables and is responsible for object behavior when the Interactables is associated with are hovered or interacting with one or more Interactors.
InteractionController is an abstract class and it can't be derived from a user defined class directly. Instead, users must derive from generic version of InteractionController -InteractionController<TInteractor, TInteractable> in order to implement their own custom InteractionControllers. InteractionController is meant to manage interaction behavior between specific types of Interactors and Interactables, although it can be as general as the user wants it to be - e.g. deriving from InteractionController<Interactor, Interactable> would define an InteractionController capable of driving the interactions between any types of Interactors and Interactables. Users are required to implement the following abstract methods of InteractionController<TInteractor, TInteractable> class:
protected abstract bool TryStartInteractionWithInteractableByInteractor(TInteractor interactor, TInteractable interactable) - As the name suggests, this method is called when interaction between the specified Interactor and Interactable (associated with InteractionController the method is called on) should start, after all other conditions for starting the interaction between the specified Interactor and Interactable have been satisfied. This is the opportunity to initialize the state the InteractionController uses for further driving the interaction. Return value indicates whether the interaction can actually start, it is the last opportunity for cancelling the interaction between Interactor and Interactable.
protected abstract void HandleInteractionWithInteractableByInteractorStopped(TInteractor interactor, TInteractable interactable) - similar to previously described method, this is called when interaction between the specified Interactor and Interactable has been stopped, either explicitly by user request (e.g. by calling one of the Stop methods defined on Interactor/Interactable for stopping interactions) or when the interaction system has determined that the interaction should be stopped for any other reason.
protected abstract void HandleInteractionsStoppedAllAtOnce() - this is called when interactions between all Interactables associated with the InteractionController and all Interactors currently interacting with them have been stopped all at once (e.g. when InteractionController has been disabled). Important thing to note is that the previous method HandleInteractionWithInteractableByInteractorStopped is not called in the circumstances when this method is called, so both are required to be implemented.
As mentioned, besides driving the behavior of interactions between Interactables and Interactors, InteractionController can drive the behavior of hovering between them as well. There are 3 methods that can be overridden to facilitate this:
protected virtual bool TryStartHoveringInteractableByInteractor(TInteractor interactor, TInteractable interactable)
protected virtual void HandleHoveringInteractableByInteractorStopped(TInteractor interactor, TInteractable interactable)
protected virtual void HandleHoveringStoppedAllAtOnce()
They are completely equivalent to the previously stated abstract methods for handling interactions starting/stopping, only used in the context of hovering between Interactors and Interactables associated with the InteractionController. They are not required to be implemented as driving the hovering behavior is completely optional and left to OctoXR user to handle it, if so desired. Default implementations of these methods are empty or, in the case of the first one, returning true to indicate that hovering can always start when interaction system has determined that it can start.
As far as the logic for interaction/hovering behavior goes, there is no dedicated method that gets called - this is left up to the user to decide where and if it should be implemented, e.g. whether via defining Update or FixedUpdate methods and using those to update the state of the objects affected by interaction and/or hovering. If at any point interaction/hovering needs to be stopped from within the InteractionController's behavior updating logic, user can simply call any of the Stop methods offered by InteractionController that function much the same as Stop methods on Interactor/Interactable dedicated for stopping interactions/hovering. There are methods for stopping interaction, hovering or both simultaneously between specific pair of Interactor-Interactable as well as for stopping all interactions/hovering performed by a specific Interactor or performed on a specific Interactable, etc. InteractionController maintains lists of all currently hovering and interacting pairs of Interactors and Interactables internally, freeing the user from needing to implement it. InteractionController offers several methods for obtaining the Interactors and Interactables that are currently interacting/hovering as well, so they can also be utilized by the user.
Grab Interaction Controller
GrabInteractionController is InteractionController that serves as a base class for InteractionControllers that drive the behavior of grab type of interactions. It is an abstract class and, like InteractionController class, has no exposed properties in the Unity editor. It is associated with GrabInteractables. It's defined mostly for convenience - to encapsulate logic for finding the GrabInteractables it should automatically associate with itself when it is reset or initially attached to a GameObject. It searches the object it is attached to and child objects for GrabInteractables to associate with.
Rigid Body Grab Controller
RigidBodyGrabController is a GrabInteractionController in OctoXR that drives the grab interaction by manipulating rigid body on the same GameObject the RigidBodyGrabController is attached to (it requires the rigid body component is attached).
Usual setup is having a RigidBodyGrabController attached to a GameObject with rigid body, with GrabInteractable attached to the same object or a child object that has a collider on it or on one of its own child objects. Then, make sure the Interactor that should initiate and manage grab interactions has one of spatial query types of Hover Tracker and/or Interaction Start Indicator set. In the same manner, you can attach more than one GrabInteractable under the same RigidBodyGrabController object if you want - each with its own subset of colliders that should participate in starting hovers/interactions. This way, you can have any type of configuration for a grab interactable object, from fairly simple to as complex as needed.
How exactly the RigidBodyGrabController drives the object when interaction with it is in progress is configured via several properties:
Linear Move - Property of enumeration type PhysicsBodyDirectMoveOption. It specifies the exact way the RigidBodyBrabController should update position of the rigid body:
None - No movement is performed at all.
SetVelocity - Position is changed by setting the velocity of the body to a value that will cause it to move the exact target amount that is needed.
SetPosition - Position is changed by setting position directly on the rigid body, using Rigidbody.MovePosition method.
Angular Move - The same type and role as the Linear Move property, only this is used for updating rotation of the rigid body.
Set Kinematic On Interaction Start - If enabled, rigid body will be set to kinematic when interaction starts. When kinematic, body is moved to target position/rotation by setting position/rotation directly on the body, regardless if Linear/Angular Move is set to SetVelocity option. If Linear/Angular Move is set to None, no linear/angular movement is performed on the rigid body. When interaction with the body ends, rigid body is restored back to non-kinematic, unless it was already kinematic when the interaction started.
Disable Collisions On Interaction Start - If enabled, collisions with the rigid body will be disabled for the duration of the interaction with it. Again, relevant state of the body will be restored when interaction ends.
Set Velocity On Interaction End - If enabled, RigidBodyGrabController will set the linear velocity of the rigid body to a value that is based on the last movement performed by the interacting object (this object's position and rotation is specified via RigidBodyGrabController's InteractorSpecification) before interaction with the rigid body ended. This can be especially useful when used in tandem with Set Kinematic On Interaction Start.
Set Angular Velocity On Interaction End - Has the same role as the previous property, only this is used for setting the angular velocity of the rigid body.
When interaction with a GrabInteractable that is associated with the RigidBodyGrabController starts, RigidBodyGrabController takes a reference to a Transform component that acts as an anchor to which its rigid body is attached. During the interaction, RigidBodyGrabController maintains certain offset between its rigid body and this anchor Transform, both linear and angular, depending on the RigidBodyGrabController's properties. That anchor Transform is specified via RigidBodyGrabController's InteractorSpecification:
RigidBodyGrabControllerInteractorSpecification
InteractorSpecification used by RigidBodyGrabController, it should be added to the Specifications list of an Interactor in order to make it possible to initiate and drive the interactions between the Interactor and a GrabInteractable associated with the RigidBodyGrabController. This specification is listed as Rigid Body Grab in the drop-down that appears when selecting a type of InteractorSpecification after adding the specification to the Interactor's list of specifications in Unity editor.
It has a single property exposed:
Grabbed Object Follow Target - Reference to a Transform component instance that is used as an anchor to which the RigidBodyGrabController's rigid body is attached when interacting with it. This is usually set to interacting hand object's wrist Transform.
RigidBodyGrabController currently only allows one Interactor to interact with the GrabInteractables associated with it and only with a single Interactable at the same time, it is meant to be used for simple and most common types of grab interactions.
Last updated