如何使用EventSystem检测多个/重叠的GameObject? [英] How to detect multiple/Overlapping GameObjects with the EventSystem?
问题描述
我想要达到的目的:牙刷应该在用户单击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和BoxCollider2D
B.它们都具有包含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
?.
问题是我有:
-
当我的指针进入
- OnPointerExit.
- 如果在
B
中单击,OnPointerDown
仅在B
上触发,而不在A
上触发
B
时,触发A
上的- OnPointerExit on
A
is triggered when my pointer enterB
. - if click inside
B
,OnPointerDown
only triggered onB
but notA
推荐答案
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
(OnPointerDown
和IPointerDownHandler
)并使用旧式的射线广播系统.
1.Get ride of EventSystem
(OnPointerDown
and IPointerDownHandler
) and use the old school raycast system.
Physics2D.RaycastAll
和Physics2D.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屋!