2

这些天在 Unity 中,您使用 raycaster 非常容易检测到对象的触摸......

public class DragThreeDee:MonoBehaviour,IPointerDownHandler
       IPointerUpHandler, IBeginDragHandler,
       IDragHandler, IEndDragHandler
       {
       public void OnPointerDown (PointerEventData data)
          { etc

因此,关于您的 UI 层,它正确地忽略了 UI 层上的触摸等等。

如果您希望发生以下情况怎么办,

您想收集(同时,在同一帧中,两者)在 3D 对象和 UI 项目上的触摸?

(想象一下,比如说,屏幕上有几个透明的 UI 按钮;还有普通的 3D 机器人在四处奔跑。用户点击屏幕上的一个点,那里有一个 UI 按钮,“下方”是一个机器人。机器人的两个上面的脚本和按钮应该响应。)

你会怎么做?我广泛尝试使用单独的相机、单独EventSystem的、调整图层、遮挡蒙版等。我找不到办法。

如何在 Unity 中执行此操作?

4

1 回答 1

2

看起来很复杂,但可以做到。

1 .Route 来自PointerEventData您要取消阻止 3D GameObjects 光线投射的所有 UI 组件中的数据。

2PhysicsRaycaster .获取with的所有实例FindObjectsOfType<PhysicsRaycaster>()。在性能方面,缓存它是有意义的。

3 .执行 RaycastPhysicsRaycaster.Raycast将返回所有附有 Collider 的 GameObjects。

4.使用ExecuteEvents.Execute将相应的事件发送到结果中存储RaycastResult

RaycastForwarder脚本:

public class RaycastForwarder : MonoBehaviour
{
    List<PhysicsRaycaster> rayCast3D = new List<PhysicsRaycaster>();
    List<RaycastResult> rayCast3DResult = new List<RaycastResult>();

    private static RaycastForwarder localInstance;
    public static RaycastForwarder Instance { get { return localInstance; } }


    private void Awake()
    {
        if (localInstance != null && localInstance != this)
        {
            Destroy(this.gameObject);
        }
        else
        {
            localInstance = this;
        }
    }

    public void notifyPointerDown(PointerEventData eventData)
    {
        findColliders(eventData, PointerEventType.Down);
    }

    public void notifyPointerUp(PointerEventData eventData)
    {
        findColliders(eventData, PointerEventType.Up);
    }

    public void notifyPointerDrag(PointerEventData eventData)
    {
        findColliders(eventData, PointerEventType.Drag);
    }

    private void findColliders(PointerEventData eventData, PointerEventType evType)
    {
        UpdateRaycaster();

        //Loop Through All Normal Collider(3D/Mesh Renderer) and throw Raycast to each one
        for (int i = 0; i < rayCast3D.Count; i++)
        {
            //Send Raycast to all GameObject with 3D Collider
            rayCast3D[i].Raycast(eventData, rayCast3DResult);
            sendRayCast(eventData, evType);
        }
        //Reset Result
        rayCast3DResult.Clear();
    }

    private void sendRayCast(PointerEventData eventData, PointerEventType evType)
    {
        //Loop over the RaycastResult and simulate the pointer event
        for (int i = 0; i < rayCast3DResult.Count; i++)
        {
            GameObject target = rayCast3DResult[i].gameObject;
            PointerEventData evData = createEventData(rayCast3DResult[i]);

            if (evType == PointerEventType.Drag)
            {
                ExecuteEvents.Execute<IDragHandler>(target,
                                        evData,
                                        ExecuteEvents.dragHandler);
            }

            if (evType == PointerEventType.Down)
            {
                ExecuteEvents.Execute<IPointerDownHandler>(target,
                               evData,
                               ExecuteEvents.pointerDownHandler);
            }

            if (evType == PointerEventType.Up)
            {
                ExecuteEvents.Execute<IPointerUpHandler>(target,
                    evData,
                    ExecuteEvents.pointerUpHandler);
            }
        }
    }

    private PointerEventData createEventData(RaycastResult rayResult)
    {
        PointerEventData evData = new PointerEventData(EventSystem.current);
        evData.pointerCurrentRaycast = rayResult;
        return evData;
    }

    //Get all PhysicsRaycaster in the scene
    private void UpdateRaycaster()
    {
        convertToList(FindObjectsOfType<PhysicsRaycaster>(), rayCast3D);
    }

    private void convertToList(PhysicsRaycaster[] fromComponent, List<PhysicsRaycaster> toComponent)
    {
        //Clear and copy new Data
        toComponent.Clear();
        for (int i = 0; i < fromComponent.Length; i++)
        {
            toComponent.Add(fromComponent[i]);
        }
    }

    public enum PointerEventType
    {
        Drag, Down, Up
    }
}

RayCastRouter脚本:

public class RayCastRouter : MonoBehaviour, IPointerDownHandler,
       IPointerUpHandler,
       IDragHandler
{
    public void OnDrag(PointerEventData eventData)
    {
        RaycastForwarder.Instance.notifyPointerDrag(eventData);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        RaycastForwarder.Instance.notifyPointerDown(eventData);
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        RaycastForwarder.Instance.notifyPointerUp(eventData);
    }
}

用法:

A .AttachRaycastForwarder到一个空的游戏对象。

B . 附加RayCastRouter到您不想阻止 3D 游戏对象的任何 UI 组件,例如 Image。就是这样。任何附加到它的 UI 组件RayCastRouter都将能够允许其后面的 3D 游戏对象接收光线投射。

现在将向 3D 对象发送一个事件,该对象具有一个脚本,该脚本实现来自和IPointerDownHandler接口的函数。IPointerUpHandlerIDragHandler

不要忘记连接Physics Raycaster到相机。

于 2016-11-13T08:31:14.990 回答