如何使IPointer在相应的对撞机上工作? [英] How to make IPointer work on respective box collider?
问题描述
我尝试实现IPointerEnter
,IPointerExit
,IPointerDown
和IPointerUp
.
在它们开始重叠之前,它们都工作正常.
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?
A
和B
是BoxCollider2D
,B
在A
内部.他们两个都具有已实现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.
- 在
B
内单击鼠标右键时,只有1个框会触发IPointerDown
. (通过此链接解决)如何检测多个/重叠带有EventSystem的GameObjects? - 如果我的指针(鼠标)在
A
内,并且将指针(鼠标)移动到B
,则A
将被触发(IPointerExit
).我尝试实现的是A
IPointerExit
应该在其各自的对撞机上触发.
- Upon clicking mouse down inside
B
, only 1 box will trigger theIPointerDown
. (This is solved by this link) How to detect multiple/Overlapping GameObjects with the EventSystem? - If my pointer (mouse) is inside of
A
and I move the pointer (mouse) toB
,A
will get triggered (IPointerExit
). What I try to achieve isA
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屋!