如何让IPointer在相应的盒式对撞机上工作?

时间:2017-09-18 08:21:54

标签: c# unity3d unity5

我尝试实施IPointerEnterIPointerExitIPointerDownIPointerUp

所有这些都正常工作,直到它们开始重叠。

我的问题是如何让IPointer...在各自的对撞机上工作?

ABBoxCollider2DB位于A内。它们都有一个高于IPointer...的脚本。以下是我遇到这种情况的问题。

  1. B内单击鼠标后,只有1个框会触发IPointerDown。 (这可以通过此链接解决)How to detect multiple/Overlapping GameObjects with the EventSystem?
  2. 如果我的指针(鼠标)在A内,我将指针(鼠标)移动到BA将被触发(IPointerExit)。我试图实现的是A IPointerExit应该在它的相应对手上触发。
  3. 如果我输入A,那么' IPointerEnter'应触发A,如果输入B,则应触发IPointerEnter B

    enter image description here

1 个答案:

答案 0 :(得分:0)

我设法为上述问题创建一个脚本,它适用于简单的重叠。这意味着需要在另一个框内的任何BoxCollider2D必须是最顶级的订单层。只需展开OverlapEventTrigger

using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using System.Linq;

namespace TFTM.Event
{
    public enum EventExecuteType
    {
        PointerEnter,
        PointerExit,
        PointerDown,
        PointerUp,
        PointerDrag,
    }

    public abstract class OverlapEventTrigger : EventTrigger, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler, IDragHandler
    {
    public virtual void MouseDown(PointerEventData eventData){}
    public virtual void MouseUp(PointerEventData eventData){}
    public virtual void MouseEnter(PointerEventData eventData){}
    public virtual void MouseExit(PointerEventData eventData){}
    public virtual void MouseDrag(PointerEventData eventData){}

    List<GameObject> ObjectsInCollider = new List<GameObject>();
    public List<RaycastResult> lastTotalRaycastResult = new List<RaycastResult>();

    public override void OnPointerDown(PointerEventData eventData)
    {
        Debug.Log("Down: " + eventData.pointerCurrentRaycast.gameObject.name);

        MouseDown(eventData);

        rethrowRaycast(eventData, eventData.pointerCurrentRaycast.gameObject, EventExecuteType.PointerDown);
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        Debug.Log("Up: " + eventData.pointerCurrentRaycast.gameObject.name);

        MouseUp(eventData);

        rethrowRaycast(eventData, eventData.pointerCurrentRaycast.gameObject, EventExecuteType.PointerUp);
    }

    public override void OnPointerEnter(PointerEventData eventData)
    {
        if (IsPointerInsideCollider(eventData) && ObjectsInCollider.Contains(gameObject))
            return;

        Debug.Log("Enter: " + eventData.pointerCurrentRaycast.gameObject.name);

        MouseEnter(eventData);

        ObjectsInCollider.Add(gameObject);
    }

    public override void OnPointerExit(PointerEventData eventData)
    {
        //Debug.Log("Is " + gameObject.name + " inside his respective collider : " + IsPointerInsideCollider(eventData));

        if (IsPointerInsideCollider(eventData))
            return;

        Debug.Log("Exit: " + gameObject.name);

        MouseExit(eventData);

        ObjectsInCollider.Remove(gameObject);
    }

    public override void OnDrag(PointerEventData eventData)
    {
        //Debug.Log("Drag: " + eventData.pointerCurrentRaycast.gameObject.name);

        MouseDrag(eventData);

        rethrowRaycast(eventData, eventData.pointerCurrentRaycast.gameObject, EventExecuteType.PointerDrag);
    }

    bool IsPointerInsideCollider(PointerEventData eventData)
    {
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
        pointerEventData.position = eventData.position;

        List<RaycastResult> raycastResult = new List<RaycastResult>();

        EventSystem.current.RaycastAll(pointerEventData, raycastResult);

        for (int i = 0; i < raycastResult.Count; i++)
        {
            if (raycastResult[i].gameObject == gameObject)
            {
                return true;
            }
        }

        return false;
    }

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

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

        //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 || eventType == EventExecuteType.PointerDrag)
            {
                //Re-simulate OnPointerDown on every Object hit
                simulateCallbackFunction(raycastResult[i].gameObject, eventType);
            }
        }
    }

    //This causes functions such as OnPointerDown to be called again
    void simulateCallbackFunction(GameObject target, EventExecuteType eventType)
    {
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
        //pointerEventData.ra
        RaycastResult res = new RaycastResult();
        res.gameObject = target;
        pointerEventData.pointerCurrentRaycast = res;
        pointerEventData.position = Input.mousePosition;

        switch (eventType) {
            case EventExecuteType.PointerDown:
                ExecuteEvents.Execute(target, pointerEventData, ExecuteEvents.pointerDownHandler);
                break;
            case EventExecuteType.PointerUp:
                ExecuteEvents.Execute(target, pointerEventData, ExecuteEvents.pointerUpHandler);
                break;
            case EventExecuteType.PointerDrag:
                ExecuteEvents.Execute(target, pointerEventData, ExecuteEvents.dragHandler);
                break;
            default:
                break;
        }

    }


}