Unity IDropHandler with 2D objects in 3D space

Unity IDropHandler with 2D objects in 3D space

我已经实现了一个实现 IDragHandler 的 Unity 组件,以及另一个实现 IDropHandler 的组件。 IDragHandler 组件放置在我要拖动的对象上,但 IDropHandler 组件附加到我可以 将对象拖放到 上的对象,而不是我 可以拖放的对象.

我正在使用透视相机进行 3D 工作。

我下面的代码适用于将 3D 对象放置在 3D 对象上,以及将 3D 对象放置在 2D UI 对象上,但不适用于将 2D UI 对象放置在 3D 对象上或 2D UI 二维对象 UI 个对象。

我遇到的问题是,由于 EventSystem 的 Raycasting(即使我没有在该对象上实现 IDropHandler),我正在拖动的对象会阻止 OnDrop 并将其占为己有。

对于 3D 对象,我在我的 IDragHandler 组件中拖动时暂时禁用了 Collider,以确保决定给哪个对象提供 OnDrop 的 Raycast 通过被拖动的对象并到达它后面的对象。 但是,2D UI 对象不适用于拖放碰撞器,因此没有可禁用的碰撞器。我不知道如何确保 EventSystem Raycast 绕过拖动的对象以将 OnDrop 传递给它后面的对象。

    public void OnBeginDrag(PointerEventData eventData)
    {
        ...

        if (UIObject)
        {
            // What to do here?
        }
        else
        {
            var collider = gameObject.GetComponent<Collider>();
            collider.enabled = false;
        }

    }

    public void OnDrag(PointerEventData eventData)
    {
        // Move object and stuff
        ...
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (UIObject)
        {
            // What to do here?
        }
        else
        {
            var collider = gameObject.GetComponent<Collider>();
            collider.enabled = true;
        }
    }

到目前为止我尝试过的是:

1) 暂时将gameObject放在IgnoreRaycast层

2) 给对象添加一个canvas组,暂时关闭"Block Raycast"

我在 OnBeginDrag 中所做的任何事情似乎都没有效果,直到我出于某种原因实际放下了对象。尝试上面提到的 #2 导致它直到对象被放下后才关闭 "Block Raycast",这导致对象甚至不再可拖动。

我做了一个变通方法,在 OnEndDrag 光线投射中拖动对象并确定它是否落在某物上,如果是,则在该对象上调用 OnDrop。禁用和启用 3D 对象上的碰撞器现在已过时,因此已将其删除。

    public void OnBeginDrag(PointerEventData eventData)
    {
        ...
    }

    public void OnDrag(PointerEventData eventData)
    {
        // Move object and stuff
        ...
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        // Currently using transform.position as raycast origin, could easily be something else if desired.
        var rayCastOrigin = transform.position;

        // Save the current layer the dropped object is in,
        // and then temporarily place the object in the IgnoreRaycast layer to avoid hitting self with Raycast.
        int oldLayer = gameObject.layer;
        gameObject.layer = 2;

        var raycastOriginInScreenSpace = Camera.main.WorldToScreenPoint(rayCastOrigin);
        var screenRay = Camera.main.ScreenPointToRay(new Vector3(raycastOriginInScreenSpace.x, raycastOriginInScreenSpace.y, 0.0f));

        // Perform Physics.Raycast from transform and see if any 3D object was under transform.position on drop.
        RaycastHit hit3D;
        if (Physics.Raycast(screenRay, out hit3D))
        {
            var dropComponent = hit3D.transform.gameObject.GetComponent<IDropHandler>();
            if (dropComponent != null)
                dropComponent.OnDrop(eventData);
        }

        // Perform Physics2D.GetRayIntersection from transform and see if any 2D object was under transform.position on drop.
        RaycastHit2D hit2D = Physics2D.GetRayIntersection(screenRay);
        if (hit2D)
        {
            var dropComponent = hit2D.transform.gameObject.GetComponent<IDropHandler>();
            if (dropComponent != null)
                dropComponent.OnDrop(eventData);
        }

        // Reset the object's layer to the layer it was in before the drop.
        gameObject.layer = oldLayer;
    }

我想要的行为是,当一个对象的 transform.position 掉落在某物上时,它被算作掉落。默认行为,即当鼠标指针在放置的对象内时触发 onDrop,可以通过交换

轻松实现
var raycastOriginInScreenSpace = Camera.main.WorldToScreenPoint(rayCastOrigin);
var screenRay = Camera.main.ScreenPointToRay(new Vector3(raycastOriginInScreenSpace.x, raycastOriginInScreenSpace.y, 0.0f));

var screenRay = Camera.main.ScreenPointToRay(new Vector3(eventData.position.x, eventData.position.y, 0.0f));