How to make IPointer work on respective box collider?

天涯浪子 提交于 2019-12-13 03:47:39

问题


I tried to implement IPointerEnter, IPointerExit, IPointerDown and IPointerUp.

All of them were working fine until they start overlapping.

My question is how do I make IPointer... to work on their respective collider?

A and B are BoxCollider2D, B is inside of A. Both of them have a script that has above IPointer... implemented. Below are the issues that I am having with this condition.

  1. Upon clicking mouse down inside B, only 1 box will trigger the IPointerDown. (This is solved by this link) How to detect multiple/Overlapping GameObjects with the EventSystem?
  2. If my pointer (mouse) is inside of A and I move the pointer (mouse) to B, A will get triggered (IPointerExit). What I try to achieve is A IPointerExit should be triggered on it's respective collider.

If I enter A then 'IPointerEnter' A should be triggered and if enter B, IPointerEnter B should then be triggered.


回答1:


I manage to create a script for above issue, It works for simple overlapping. which means any BoxCollider2D that need to be inside another box must be the most top order layer. Just extend 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;
        }

    }


}


来源:https://stackoverflow.com/questions/46274674/how-to-make-ipointer-work-on-respective-box-collider

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!