我尝试实现的目标:牙刷应该显示在用户点击BoxCollider
A
内的任何位置,包括BoxCollider
B
内的空间。但显然在B
内点击将不会显示牙刷(OnPointerDown未被触发)。
我尝试过的方法:更改图层的顺序。
用户在框架对撞机A
内点击后会显示牙刷,但如果用户点击框对撞机B
- 牙刷将不会显示,这意味着OnPointerDown
未被触发。
我认为这是因为一个BoxCollider2D
与另一个BoxCollider2D
重叠。在B
内A
,我认为这是罪魁祸首,但我不知道如何解决它,或者是否有其他方法可以实现OnPointerDown
?
我正在使用Perspective
相机。但是在这个场景中,所有元素都在同一个z position
,即0.是否可以在每个BoxCollider2D
中触发IPointerHander事件?
此脚本附在牙刷上。 BoxCollider2D
A也属于牙刷。
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();
}
此脚本已附加到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
内点击。这里是调试日志。
这是附加的BoxCollider2D
A,*Toothbrush
本身和dragable.cs
脚本。
更新:感谢其他人的回答,问题对我来说变得更加清晰。以下是BoxCollider2D
A和BoxCollider2D
B.他们都有大多数OnPointerHander
的脚本。如何确保在相应的OnPointerHandler
上触发所有BoxCollider2D
?
我遇到的问题:
A
时,会触发B
上的OnPointerExit。B
内点击,OnPointerDown
仅在B
而非A
点击答案 0 :(得分:2)
EventSystem的优点之一是事件不会通过GameObjects。返回第一个被击中的。虽然,看起来你不想要那样。使EventSystem返回多个GameObjects很复杂,
有两种解决方案:
1 。获取EventSystem
(OnPointerDown
和IPointerDownHandler
)并使用旧式学校光线投影系统。
Physics2D.RaycastAll
和Physics2D.RaycastNonAlloc
可以做到这一点。出于性能原因,此示例将使用RaycastNonAlloc
。这很容易。
仅附加到一个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
但重新抛出事件。
首先,您使用EventSystem.current.RaycastAll
投射光线投射,然后使用ExecuteEvents.Execute
手动调用该事件。
使用2D Collider附加到所有GameObject,并确保Physics2DRaycaster
附加到相机:
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);
}
}
答案 1 :(得分:0)
这里的预期功能是什么?我怀疑你是否希望用户在口腔内咔嗒一声显示牙刷?
如果是这样,那么解决这个问题的一种有趣方法是将“B”对象的排序调整为在层次结构中位于“A”对象之上,以便它们覆盖A碰撞区域。这反过来将允许它们的相互作用阻止由每个'B'对撞机定义的碰撞区域下面定义的区域的相互作用。
我们用这种方法做的是强迫OnPointerDown事件与'B'对撞机一起发生,然后它才有可能与'A'对撞机碰撞。
请告诉我这是否有意义,并随时询问有关该方法的后续问题。
仍然不确定你的情况是否符合我的想法,但这里是我提到的方法的视频:Demo Video