Search Unity

Question Filtering a socket by tag with new IXR interfaces?

Discussion in 'XR Interaction Toolkit and Input' started by RogueStargun, Dec 31, 2021.

  1. RogueStargun

    RogueStargun

    Joined:
    Aug 5, 2018
    Posts:
    296
    I have some code in my project for making a socket interactor filter by tag. Unfortunately it looks like the latest XRInteractionToolkit is telling me this code is already deprecated.

    Code (CSharp):
    1.  public class XRFilterSocketInteractor : XRSocketInteractor
    2.     {
    3.         // XRSnapInteractor is an XRSocketInteractor that filters socketable items by tag
    4.         [Header("Filter PARAMS")]
    5.         [SerializeField] protected bool doFilterByTag = true;
    6.         [SerializeField] protected string[] filterTags;
    7.        
    8.         public override bool CanHover(XRBaseInteractable interactable)
    9.         {
    10.             if (doFilterByTag)
    11.             {
    12.                 foreach (string filterTag in filterTags)
    13.                 {
    14.                     if (!interactable.CompareTag(filterTag))
    15.                     {
    16.                         return false;
    17.                     }
    18.                 }
    19.             }
    20.             return base.CanHover(interactable);
    21.         }
    22.         public override bool CanSelect(XRBaseInteractable interactable)
    23.         {
    24.             if (doFilterByTag)
    25.             {
    26.                 foreach (string filterTag in filterTags)
    27.                 {
    28.                     if (!interactable.CompareTag(filterTag))
    29.                     {
    30.                         return false;
    31.                     }
    32.                 }
    33.             }
    34.             return base.CanSelect(interactable);
    35.         }
    36.     }
    I'm honestly not seeing the benefit of replacing the old XRBaseInteractable behavior with interfaces. In fact the IXR interfaces feel like a terrible idea and are not particularly user friendly. Is there any guidance on the "correct" way to make a socket interactor filter by tag moving forward?
     
  2. VRDave_Unity

    VRDave_Unity

    Unity Technologies

    Joined:
    Nov 19, 2021
    Posts:
    275
    Hi RogueStargun,

    There are a couple of ways to adjust your script to do what you want. The first way is to use the Interaction Layer Mask feature of the XRI Toolkit to achieve your filtering. You can learn more about setting this up here: XR Interaction Toolkit Manual: InteractionLayerMask. It works very similar to Physics Layers and Tags. You can pick the Interaction Layers for the different objects (Interactors and Interactables), which will respond to each other if they share one or more layers (as well as the XR Controllers and XR Rig/Origin, as those also have an Interaction Layer Mask as well). Depending on your use-case, this may be the easiest way to do what you want to do.

    Alternatively, if you wanted to keep moving forward with your tags approach, you can make some minor adjustments to your script to handle the non-deprecated interface-typed parameter. Since most Interactables being passed into the CanHover and CanSelect will typically have a MonoBehaviour attached, you can check the type while also declaring a local variable to use later with a type-checking declaration pattern (see if-statements below). This will create a local variable for the gameObject with the CompareTag function for you to use in filtering against the tag set. Here is your updated class below:

    Code (CSharp):
    1. public class XRFilterSocketInteractor : XRSocketInteractor
    2. {
    3.     // XRSnapInteractor is an XRSocketInteractor that filters socketable items by tag
    4.     [Header("Filter PARAMS")]
    5.     [SerializeField] protected bool doFilterByTag = true;
    6.     [SerializeField] protected string[] filterTags;
    7.  
    8.  
    9.     public override bool CanHover(IXRHoverInteractable interactable)
    10.     {
    11.         if (doFilterByTag && interactable is MonoBehaviour gameObject)
    12.         {
    13.             foreach (string filterTag in filterTags)
    14.             {
    15.                 if (!gameObject.CompareTag(filterTag))
    16.                 {
    17.                     return false;
    18.                 }
    19.             }
    20.         }
    21.         return base.CanHover(interactable);
    22.     }
    23.  
    24.     public override bool CanSelect(IXRSelectInteractable interactable)
    25.     {
    26.         if (doFilterByTag && interactable is MonoBehaviour gameObject)
    27.         {
    28.             foreach (string filterTag in filterTags)
    29.             {
    30.                 if (!gameObject.CompareTag(filterTag))
    31.                 {
    32.                     return false;
    33.                 }
    34.             }
    35.         }
    36.         return base.CanSelect(interactable);
    37.     }
    38. }
     
  3. RogueStargun

    RogueStargun

    Joined:
    Aug 5, 2018
    Posts:
    296
    Thanks for the reply! The interaction layer approach might be a bit more performant here so I'll give it a shot, although I must say this is a very drastic api change
     
  4. chris-massie

    chris-massie

    Unity Technologies

    Joined:
    Jun 23, 2020
    Posts:
    231
    I'll add to above that both the
    IXRInteractor
    and
    IXRInteractable
    have a
    transform
    property to get the Transform associated with it. That way
    interactable.CompareTag(filterTag)
    could be changed to
    interactable.transform.CompareTag(filterTag)
    to get the old functionality.

    You can also use that if you were calling
    GetComponent<T>()
    on the interactor/interactable to find a component on the same GameObject.

    The addition of the interfaces allows users to have more flexibility and opens up the possibility for them to totally override the abstract base classes by making their own MonoBehaviour instead or even a plain C# class for the interactor/interactable. With the
    XRBaseInteractor
    /
    XRBaseInteractable
    as the only way to get added to the main interaction loop of the package, users couldn't adapt existing behaviors that needed another inheritance hierarchy.

    The change also means that users don't need to implement hover or select logic if their interactor/interactable does not need both since the interfaces are separated so they only have to implement what they need. We've had some users request that ability and are making use of it now.

    We expect most users will continue using the abstract base classes or the concrete behaviors so they will get implementations of hover and select. We also added some helper methods like
    bool IsHovering(IXRInteractable interactable)
    and
    bool IsSelecting(IXRInteractable interactable)
    to
    XRBaseInteractor
    which helps hide away some of the casting that is now necessary. There's a tradeoff between simplicity and flexibility, but I'm hoping most users will enjoy the change, and if there are ways we can improve how users need to handle it that we can find ways to improve that in future versions.
     
    VRDave_Unity likes this.
  5. RogueStargun

    RogueStargun

    Joined:
    Aug 5, 2018
    Posts:
    296
    Is there a time horizon for deprecation of the old api in favor of the new one?
     
    Last edited: Jan 15, 2022
  6. chris-massie

    chris-massie

    Unity Technologies

    Joined:
    Jun 23, 2020
    Posts:
    231
    We'll try to keep the old methods around for probably another year since we know how many developers and examples online are using the old ones. It will at least be around in Unity 2022.2. We do want to eventually remove them to avoid confusing new users and cut down on the backwards compatible code that bloats and makes it harder for users to understand the code in classes they extend.
     
  7. ANS_TT_VR

    ANS_TT_VR

    Joined:
    Nov 3, 2019
    Posts:
    7
    hey everyone,

    First, than you for the input on this question. I have tested your solutions and the script seems to work the first time the game starts. After you pick up the object attached, it never comes back again to the socket. Has there been any issues like this using this customization to the socket interactor?
     
  8. VRDave_Unity

    VRDave_Unity

    Unity Technologies

    Joined:
    Nov 19, 2021
    Posts:
    275
    Hey @ANS_TT_VR,
    Do you have any additional information about your configuration? I tested this on a very simple setup and it was working as intended. If you feel comfortable, feel free to file a bug report in Unity (Help > Report a Bug...) and attach the project for us to take a closer look at. The other thing you could do is post some screenshots of the various object configuration for the Interactor and Interactables you are trying to get this working for.