如何使IPointer在相应的对撞机上工作? [英] How to make IPointer work on respective box collider?

查看:81
本文介绍了如何使IPointer在相应的对撞机上工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试实现IPointerEnterIPointerExitIPointerDownIPointerUp.

在它们开始重叠之前,它们都工作正常.

All of them were working fine until they start overlapping.

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

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

ABBoxCollider2DBA内部.他们两个都具有已实现IPointer...的脚本.以下是我在这种情况下遇到的问题.

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. B内单击鼠标右键时,只有1个框会触发IPointerDown. (通过此链接解决)如何检测多个/重叠带有EventSystem的GameObjects?
  2. 如果我的指针(鼠标)在A内,并且将指针(鼠标)移动到B,则A将被触发(IPointerExit).我尝试实现的是A IPointerExit应该在其各自的对撞机上触发.
  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.

如果我输入A,则应触发"IPointerEnter" A;如果输入B,则应触发IPointerEnter B.

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

推荐答案

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

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;
        }

    }


}

这篇关于如何使IPointer在相应的对撞机上工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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