如何使用EventSystem检测多个/重叠的GameObject? [英] How to detect multiple/Overlapping GameObjects with the EventSystem?

查看:69
本文介绍了如何使用EventSystem检测多个/重叠的GameObject?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要达到的目的:牙刷应该在用户单击BoxCollider A内的任何位置显示,包括BoxCollider B内的空间.但是显然单击B内部不会显示牙刷(未触发OnPointerDown).

What I try to achieve: Toothbrush should show up wherever the user clicks inside BoxCollider A, including space inside BoxCollider B. But apparently clicking inside B will not show the toothbrush (OnPointerDown is not being triggered).

我尝试过的:更改图层的顺序.

What I have tried: Changing the order of the layers.

在用户单击盒对撞机A内后显示牙刷,但是如果用户在盒对撞机B内单击,牙刷将不会显示,这表示不会触发OnPointerDown.

Toothbrush is showed after user clicks inside box collider A, but if the user clicks inside box collider B- the toothbrush will not show up, which means OnPointerDown is not triggered.

我认为这是因为一个BoxCollider2D与另一个BoxCollider2D之间的重叠.就我在A中的B而言,我认为是罪魁祸首,但是我不知道如何解决它,或者是否有实现OnPointerDown的另一种方法?

I think it is because of the overlapping of one BoxCollider2D inside another BoxCollider2D. In my case B inside A, I assume that is the culprit, but I have no idea how to solve it or if maybe there is another method to implement OnPointerDown?

我正在使用Perspective相机.但是在此场景中,所有元素都位于相同的z position中,该值为0.是否可以在每个相应的BoxCollider2D中触发IPointerHander事件?

I am using Perspective camera. but in this scene all elements are in same z position which is 0. Is it possible to trigger IPointerHander event in every respective BoxCollider2D ?

此脚本已附加到牙刷上. BoxCollider2D A也属于牙刷.

This script is attached to the toothbrush. The BoxCollider2D A also belongs to toothbrush.

public void OnPointerDown(PointerEventData eventData)
{
    Debug.Log("pointer down");

    if (GetComponent<DragableObject>() == null)
        return;

    currentObject = GetComponent<DragableObject>();

    MeshRenderer renderer = GetComponent<MeshRenderer>();

    if (ShowOnTouch)
        ShowObject();

    // Store original state
    originalPosition = transform.position;
    originalOrderLayer = renderer.sortingOrder;
    // Snap to mouse
    Vector3 newPos = cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 30));
    newPos.z = 30;
    transform.position = newPos;

    if (BringToFront)
    {
        if (renderer != null)
        {
            renderer.sortingOrder = 90;
        }
    }

    ObjectActive.Invoke();
}

TargetListener.cs

此脚本附加到BoxCollider2D B.

public void OnPointerDown(PointerEventData eventData)
{
    for (int i = 0; i < Affectors.Count; i++) 
    {
        if (Affectors [i] == DragableObject.currentObject)
        {
            DragableObject.currentObject.OnEnterTarget(transform);

            ITriggerEffect[] iTrigger = GetComponents<ITriggerEffect>();

            for (int j = 0; j < iTrigger.Length; j++) 
            {
                Debug.Log("iTrigger enter");
                Debug.Log(iTrigger [j]);
                iTrigger [j].Execute(eventData, PointerState.Down);
            }
        }
        else
            continue;
    }
}

如果我单击A,则牙刷会出现,但当我在B内部单击时除外.这是调试日志.

If i click on A the toothbrush will show up, except when i click inside B. Here the debug log.

这是BoxCollider2D A的附件,它是*Toothbrush本身以及dragable.cs脚本.

This is the BoxCollider2D A is attached to, which is the *Toothbrush itself together with the dragable.cs script.

更新:感谢其他回答,这个问题对我来说更加清楚.下面是BoxCollider2D A和BoxCollider2DB.它们都具有包含OnPointerHander大部分内容的脚本.我如何确保在所有BoxCollider2D上都触发了所有OnPointerHandler?.

UPDATE: Thanks to others who answers, the problem become more clearer for me. Below is BoxCollider2D A and BoxCollider2D B. Both of them have script that have most of OnPointerHander. How do i make sure that all OnPointerHandler is triggered on respective BoxCollider2D ?.

问题是我有:

    当我的指针进入B时,触发A上的
  1. OnPointerExit.
  2. 如果在B中单击,OnPointerDown仅在B上触发,而不在A
  3. 上触发
  1. OnPointerExit on A is triggered when my pointer enter B.
  2. if click inside B ,OnPointerDown only triggered on B but not A

推荐答案

EventSystem的优点和优点之一是事件不会通过GameObjects传递.返回第一个被击中的.虽然,看起来您不想要那样.使EventSystem返回多个GameObject非常复杂,

One of the good and advantages of the EventSystem is that events don't go through GameObjects. The first one that is hit is returned. Although, it looks like you don't want that. It complicated to make EventSystem return multiple GameObjects,

为您提供两种解决方案:

There two solutions for you:

1 .搭乘EventSystem(OnPointerDownIPointerDownHandler)并使用旧式的射线广播系统.

1.Get ride of EventSystem (OnPointerDown and IPointerDownHandler) and use the old school raycast system.

Physics2D.RaycastAllPhysics2D.RaycastNonAlloc可以做到这一点.出于性能原因,本示例将使用RaycastNonAlloc.非常简单.

Physics2D.RaycastAll and Physics2D.RaycastNonAlloc can do this. This example will use RaycastNonAlloc for performance reasons. It's very easy.

仅附加一个GameObject(空GameObject):

public class HitAll : MonoBehaviour
{
    //Detect up to 100 Objects
    const int raycastAmount = 100;
    RaycastHit2D[] result = new RaycastHit2D[raycastAmount];

    void Update()
    {
        #if UNITY_IOS || UNITY_ANDROID
        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
        {
            checkRaycast(Input.GetTouch(0).position);
        }
        #else
        if (Input.GetMouseButtonDown(0))
        {
            checkRaycast(Input.mousePosition);
        }
        #endif
    }

    void checkRaycast(Vector2 mousePos)
    {
        Vector3 origin = Camera.main.ScreenToWorldPoint(mousePos);

        int hitCount = Physics2D.RaycastNonAlloc(origin, Vector2.zero, result, 200);
        Debug.Log(hitCount);

        for (int i = 0; i < hitCount; i++)
        {
            Debug.Log("Hit: " + result[i].collider.gameObject.name);
        }
    }
}


2 .继续使用EventSystem,但重新引发事件.


2.Continue using EventSystem but rethrow the event.

首先,使用EventSystem.current.RaycastAll引发raycast,然后使用ExecuteEvents.Execute手动调用该事件.

First, you throw raycast with EventSystem.current.RaycastAll then you manually invoke the event with ExecuteEvents.Execute.

使用2D Collider附加所有GameObject,并确保将Physics2DRaycaster附加到相机上:

Attach to all the GameObject with 2D Collider and make sure that Physics2DRaycaster is attached to the camera:

public class ThroughEventScript : MonoBehaviour, IPointerDownHandler
{

    public void OnPointerDown(PointerEventData eventData)
    {
        rethrowRaycast(eventData, eventData.pointerCurrentRaycast.gameObject);

        //DO STUFF WITH THE OBJECT HIT BELOW
        Debug.Log("Hit: " + eventData.pointerCurrentRaycast.gameObject.name);
    }

    void rethrowRaycast(PointerEventData eventData, GameObject excludeGameObject)
    {
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);

        pointerEventData.position = eventData.pressPosition;
        //pointerEventData.position = eventData.position;}

        //Where to store Raycast Result
        List<RaycastResult> raycastResult = new List<RaycastResult>();

        //Rethrow the raycast to include everything regardless of their Z position
        EventSystem.current.RaycastAll(pointerEventData, raycastResult);

        //Debug.Log("Other GameObject hit");
        for (int i = 0; i < raycastResult.Count; i++)
        {
            //Debug.Log(raycastResult[i].gameObject.name);

            //Don't Rethrow Raycayst for the first GameObject that is hit
            if (excludeGameObject != null && raycastResult[i].gameObject != excludeGameObject)
            {
                //Re-simulate OnPointerDown on every Object hit
                simulateCallbackFunction(raycastResult[i].gameObject);
            }
        }
    }

    //This causes functions such as OnPointerDown to be called again
    void simulateCallbackFunction(GameObject target)
    {
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
        //pointerEventData.ra
        RaycastResult res = new RaycastResult();
        res.gameObject = target;
        pointerEventData.pointerCurrentRaycast = res;
        ExecuteEvents.Execute(target, pointerEventData, ExecuteEvents.pointerDownHandler);
    }
}

这篇关于如何使用EventSystem检测多个/重叠的GameObject?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆