unity3d 如何获得当前由XRRayInteractor悬停的UI元素的引用?

mwngjboj  于 2023-02-23  发布在  其他
关注(0)|答案(3)|浏览(340)

我正在使用XR交互工具包2.2.0和Unity 2022.2.7f1,我的场景中有一个完整的XR原点设置预置,其中有一些UI元素可供单击(按钮与跟踪设备射线投射器脚本)。我有一个XR设备模拟器移动控制器和相机,一切正常,鼠标悬停在按钮上时,光标变为蓝色,按钮的颜色也随之改变。
我需要从悬停的UI元素中获取一些属性,以便对控制器外观进行一些更改。因此,最好在控制器上附加一个脚本,以便访问当前悬停的UI元素。
我制作了一个测试脚本,并将其附加到Ray Interactor中,以查看是否可以用一种简单的方法来实现:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.XR.Interaction.Toolkit;

[RequireComponent(typeof(XRRayInteractor))]
public class AccessCurrentlyHoveredElement : MonoBehaviour
{

    private XRRayInteractor rayInteractor = null;

    void Start(){
        rayInteractor = GetComponent<XRRayInteractor>();
        rayInteractor.hoverEntered.AddListener(Test);
    }

    private void Test(HoverEnterEventArgs arg0)
    {
        Debug.Log("Hover Enter Triggered");
    }

    void Update(){
        if(rayInteractor.IsOverUIGameObject()){
            Debug.Log(rayInteractor.interactablesHovered.Count);
            Debug.Log(rayInteractor.GetOldestInteractableHovered());
        }
    }
}

我的问题是,当我测试它时,IsOverUIGameObject方法工作正常,但hoverEntered事件从未被触发,interactablesHovered始终为空,GetOldestInteractableHovered始终返回null。因此,我知道UI元素何时被悬停,但无法访问它。
有什么办法吗?

vs3odd8k

vs3odd8k1#

所以我最后通过修改UI Interaction Tool Kit UIInputModule doc的代码示例来使它工作。(UIInputModule来自Complete Xr Origin Set UpEventSystem对象)。以下是最终代码:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.XR.Interaction.Toolkit.UI;

public class AccessCurrentlyHoveredElement: MonoBehaviour
{
    [SerializeField]
    UIInputModule inputModule;

    private void OnEnable()
    {
        if (inputModule != null)
        {
            inputModule.pointerEnter += OnDevicePointerEnter;

        }
    }

    private void OnDisable()
    {
        if (inputModule != null)
        {
            inputModule.pointerEnter -= OnDevicePointerEnter;
        }
    }

    // This method will fire after registering with the UIInputModule callbacks. The UIInputModule will
    // pass the PointerEventData for the device responsible for triggering the callback and can be used to
    // find the pointerId registered with the EventSystem for that device-specific event.
    private void OnDevicePointerEnter(GameObject selected, PointerEventData pointerData)
    {
        if (EventSystem.current.IsPointerOverGameObject(pointerData.pointerId))
        {
            Debug.Log($"Entered {EventSystem.current.currentSelectedGameObject} with pointer Id {pointerData.pointerId}", this);
        }
    }
}

如果您使用的是XR Device Simulator,则必须禁用EventSystemXR UI Input Module组件中的Enable Mouse Input,否则,EventSystem.current.currentSelectedGameObject对于非鼠标指针将始终为空。

tkqqtvp1

tkqqtvp12#

因此,一个解决方案是为您要跟踪的每个UI元素附加一个事件触发器,这样,每当触发悬停事件时,您就可以调用AccessCurrentlyHoveredElement脚本中的自定义函数。
您必须为每个UI元素执行以下操作:

  • 在场景视图或层次窗口中选择UI按钮,然后在检查器窗口中单击“添加组件”按钮并搜索“事件触发器”。
  • 在“事件触发器”组件中,单击“+”按钮添加新事件,然后从“事件类型”下拉菜单中选择“指针输入”。
  • 将带有AccessCurrentlyHoveredElement脚本的游戏对象拖放到“无(对象)”字段中。
  • 然后从下拉菜单中选择AccessCurrentlyHoveredElement脚本,并从函数下拉菜单中选择“Test”函数(或触发悬停事件时要调用的函数)。

现在,只要指针进入UI按钮,就会调用AccessCurrentlyHoveredElement脚本中的Test函数,您可以从那里访问当前悬停的UI元素。
要从UI元素中获取信息/数据,应该能够使用事件触发器方法的eventData参数获取所需的所有内容,因此,需要如下修改Test方法:

private void Test(BaseEventData eventData)
{
    // Get the GameObject that raised the event
    GameObject hoveredObject = eventData.selectedObject;

    // Do something with the hoveredObject, like print the name
    Debug.Log("Currently hovered object: " + hoveredObject.name);
}
oyxsuwqo

oyxsuwqo3#

试用一下我自己就看出问题了,哎呀!
重新思考了整个事情,我去做了一些关于UnityEngine.XR.Interaction.Toolkit的工作
通过使用XRUIInputModule(它是XR交互工具包中的一个组件,负责处理UI元素上的输入事件),您可以使用它来获取当前悬停的UI元素及其属性。请确保场景中有一个带有EventSystem和XRUI Input Module组件的对象。
然后你可以创建一个脚本来引用XRUIInputModule并使用它的GetCurrentRaycastResult方法来获取当前悬停的UI元素的RaycastResult。

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.UI;

public class AccessCurrentlyHoveredElement : MonoBehaviour
{
    [SerializeField] private XRUIInputModule uiInputModule;
    [SerializeField] private XRRayInteractor rayInteractor;

    private void Start()
    {
        // You could find the references to the XRUIInputModule and XRRayInteractor components rather than setting them in the inspector
        //uiInputModule = FindObjectOfType<XRUIInputModule>();
        //rayInteractor = GetComponent<XRRayInteractor>();

        // Subscribe to the hoverEntered event of the rayInteractor
        rayInteractor.hoverEntered.AddListener(OnHoverEntered);
    }

    private void OnHoverEntered(HoverEnterEventArgs args)
    {
        // Get the current UI element that is being hovered
        GameObject hoveredObject = uiInputModule.GetCurrentRaycastResult().gameObject;

        // Do something with the hovered object, e.g. change its appearance
        hoveredObject.GetComponent<RectTransform>().sizeDelta = new Vector2(200, 200);
    }

    private void OnDestroy()
    {
        // Unsubscribe from the hoverEntered event to avoid memory leaks
        rayInteractor.hoverEntered.RemoveListener(OnHoverEntered);
    }
}

此脚本使用XRUIInputModule组件,该组件由XR Interaction Toolkik添加到EventSystem对象。然后,它订阅XRRayInteractor组件的hoverEntered事件,并在事件处理程序中使用XRUIInputModule的GetCurrentRaycastResult方法获取当前悬停的UI元素的RaycastResult。最后,它对悬停的对象执行某些操作🤞

相关问题