Unity IDropHandler与3D空间中的2D对象

时间:2017-01-19 14:03:56

标签: c# unity3d unity5

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

我使用透视相机在3D中工作。

下面的代码可以很好地删除3D对象上的3D对象和2D UI对象上的3D对象,但不能用于删除3D对象上的2D UI对象或2D UI对象上的2D UI对象。

我遇到的问题是,由于EventSystem的Raycasting(即使我没有实现IDropHandler),我拖动的对象会阻止OnDrop并自行接收它。那个对象)。

对于3D对象,我在我的IDragHandler组件中拖动时暂时禁用了碰撞器,以确保决定哪个对象提供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)向对象添加画布组并暂时关闭&#34; Block Raycast&#34;在它上面。

我在OnBeginDrag中做的任何事情似乎都没有效果,直到我因某种原因实际丢弃了对象。尝试上面提到的#2导致它没有关闭&#34; Block Raycast&#34;直到物体掉落之后,这导致物体不再可以拖动。

1 个答案:

答案 0 :(得分:1)

我做了一个解决方法,在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));