What I try to achieve: Toothbrush should show up wherever the user clicks inside BoxCollider
A
, including space inside BoxCollider
B
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.Get ride of EventSystem
(OnPointerDown
and IPointerDownHandler
) and use the old school raycast system.
Physics2D.RaycastAll
and Physics2D.RaycastNonAlloc
can do this. This example will use RaycastNonAlloc
for performance reasons. It's very easy.
Attach to only one GameObject(empty 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.Continue using EventSystem
but rethrow the event.
First, you throw raycast with EventSystem.current.RaycastAll
then you manually invoke the event with ExecuteEvents.Execute
.
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 = new List();
//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);
}
}