New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to manually release grabbed object? #29
Comments
I would like to know, too. |
Thirding this one |
Try this:
[2:37 PM] |
@PicoPlanetDev I've been trying to use what you described here to force a release but haven't been able to do it. Could you possibly clarify what you did a little more? I'd be very greatful! I'm making the void public in the grab intractable script. That's straight forward enough but when you say "on the interactor" i'm not sure if that is on a script on the object getting released and if it's supposed to be in the XRgrabinteractor class or monobehavior class. So far I've been messing with it for a while and can't seem to get it to work. |
Even with all this help above it took me a while to muddle through it. So for the benefit of anyone else coming here or maybe @PicoPlanetDev, this is my solution for dropping an item in code: In XRBaseInteractable I added this public method (just after OnSelectExit, if it matters): /// <summary>This method was added by ian to enable dropping of objects
/// when we need to do it in code (e.g. at level end or when exhausted)
/// </summary>
/// <param name="interactor">Usually the player's hand</param>
public void CustomForceDrop(XRBaseInteractor interactor)
{
OnSelectExit(interactor);
} Then in the code on the interactable item (in my case a knife) I added this: _xrGrabInteractable = GetComponent<XRGrabInteractable>();
XRBaseInteractor _beingHeldBy = _xrGrabInteractable.selectingInteractor;
Debug.Log($"{this} is being held by {_beingHeldBy}");
_xrGrabInteractable.CustomForceDrop(_beingHeldBy); Now for someone else's use case you may want to set the object inactive, or have a time to disable the XRGrabInteractable component to avoid the object automatically being picked back up by the Interactor (hand). In my case I want to remove the object - a powerup or food for example - from the player's hand, so I call gameObject.SetActive(false); immediately after the CustomForceDrop. Also note: If you update Unity XR Interactions on the next release, I think the CustomForceDrop method will be lost and you'll have to replace it, if it's needed. I am using XR Interaction Toolkit 0.9.4-preview. Edit later: I found that in Unity 2020.1.2 (and maybe others) the package gets "fixed" every time I task back to Unity so the only way to hold onto changes is to copy the package as described here: |
We implemented a solution that forces the intractable to stop interacting at all for a frame, this makes it get released, take a look at: And We are considering to stop individual interactions in a near future. |
I used the approach by @iangiblin above. The custom force drop worked for me. In my use case i disable my interactable gameobject right after force releasing it. However, when I do this, for some reason the interactable stays in the hover state and as soon as I press the trigger it snaps back to the interactor hand and is selected again, although the interactable gameobject is disabled. This is an issue because the interactor is now blocked from picking up any interactable. I solved this issue by setting the interaction layer mask on the interactable to 0, right before i disable the interactable.
I assume that when this is called, the InteractionManager removes the interactable/unregisters it from any hand causing the hover and select state to be cleared. Correct me if I'm wrong. Definitely hacky, worked for me though. |
I would love a first party fix for this! |
Starting from Starting from I have add extension methods to interactor and interactable to wrap the cancel call. They should work with public static class XRBaseInteractableExtension
{
/// <summary>
/// Force deselect the selected interactable.
///
/// This is an extension method for <c>XRBaseInteractable</c>.
/// </summary>
/// <param name="interactable">Interactable that has been selected by some interactor</param>
public static void ForceDeselect(this XRBaseInteractable interactable)
{
interactable.interactionManager.CancelInteractableSelection(interactable);
Assert.IsFalse(interactable.isSelected);
}
}
public static class XRBaseInteractorExtension
{
/// <summary>
/// Force deselect any selected interactable for given interactor.
///
/// This is an extension method for <c>XRBaseInteractor</c>.
/// </summary>
/// <param name="interactor">Interactor that has some interactable selected</param>
public static void ForceDeselect(this XRBaseInteractor interactor)
{
interactor.interactionManager.CancelInteractorSelection(interactor);
Assert.IsFalse(interactor.isSelectActive);
}
} |
Thanks for the Extension Classes, where do you put them to be able to use them? Adding the methods to the XSBaseInteractable does not work as it is abstract. |
I think C#'s extension method works on abstract classes. Maybe you tried to call the extension method on the You can read more about extension method on abstract class here: https://stackoverflow.com/a/17546768 |
Oh, i have to use the whole classes |
Hey, I've managed to try this solution, but the interactor (XRSocketInteractor) directly grabs onto the object again after i've deselected it. Moving it immediately after deselection does not work either, it snaps back anyways. |
I tried your solution Holi0317 on my mobile AR, but it just won't unselect the object. private IXRSelectInteractor arg1; And then I call a method with these lines: XRBaseInteractableExtension.ForceDeselect(arg2 as XRBaseInteractable); Did I missed something? |
Apologies for necro'ing the thread, though as stated above by @lucafro one can drop a held interactable by forcing the interaction layer mask to be different from the interactor's before cancelling selection, at least on version 2.5.2 of XR Interaction Toolkit. In the Editor, you may want to edit the interactor's Interaction Layer Mask to only interact with certain layers, i.e. "ActiveGrab". Set the interactable's layer mask to also contain "ActiveGrab", such that it can be picked up. For the code part: // In my case, the interactable is set in the Editor
[SerializeField] private XRGrabInteractable grabInteractable; Inside the method for force-dropping: // Set the interaction layer to something that is on a different interaction layer than the interactor's
// This prevents the interactor from immediately picking the object back up after it's force-dropped
grabInteractable.interactionLayers = InteractionLayerMask.GetMask("InertLayer");
// Cancel the selection (this is the force-drop part, taken from @Holi0317 's extension method)
// In my case, a cast is needed to force the usage of the non-deprecated method
grabInteractable.interactionManager.CancelInteractableSelection((IXRSelectInteractable) grabInteractable);
Assert.IsFalse(grabInteractable.isSelected); Of course, you may want to re-enable the interaction later at some point. If that is the case, you can simply set the interactable's interaction layer mask back to what it was before. grabInteractable.interactionLayers = InteractionLayerMask.GetMask("ActiveGrab"); I hope this helps! |
Interesting approach @MekalBoy thank you. I am currently just doing this, which works fine AFAIK:
You still have to re-enable it if you want the object to be grabbable later. |
Setting |
How can I force the XRDirectInteractor to release its held interactable?
The text was updated successfully, but these errors were encountered: