with unity tutoriales tutorial programming pro learning learn language juegos c# unity3d

c# - unity - ¿Cómo detectar GamePoints múltiples/superpuestos con EventSystem?



unity programming language (2)

Lo que trato de lograr: el cepillo de dientes debe aparecer donde el usuario haga clic dentro de BoxCollider A , incluido el espacio dentro de BoxCollider B Pero al parecer, hacer clic dentro de B no mostrará el cepillo de dientes (OnPointerDown no se activa).

Lo que he intentado: cambiar el orden de las capas.

El cepillo de dientes se muestra después de que el usuario hace clic dentro del colisionador A caja, pero si el usuario hace clic dentro del colisionador B caja, el cepillo de dientes no se mostrará, lo que significa que OnPointerDown no se activará.

Creo que es debido a la superposición de un BoxCollider2D dentro de otro BoxCollider2D . En mi caso B dentro de A , supongo que es el culpable, pero no tengo idea de cómo resolverlo o si tal vez hay otro método para implementar OnPointerDown .

Estoy usando la cámara Perspective . pero en esta escena, todos los elementos están en la misma z position que es 0. ¿Es posible activar el evento IPointerHander en cada BoxCollider2D respectivo?

DragableObject.cs

Este script está adjunto al cepillo de dientes. El BoxCollider2D A también pertenece al cepillo de dientes.

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

Este script está adjunto a 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; } }

Si hago clic en A se mostrará el cepillo de dientes, excepto cuando hago clic dentro de B Aquí el registro de depuración.

Este es el BoxCollider2D A al que se adjunta, que es el *Toothbrush junto con el script dragable.cs .

ACTUALIZACIÓN: Gracias a otros que responden, el problema se vuelve más claro para mí. A continuación se muestra BoxCollider2D A y BoxCollider2D B. Ambos tienen script que tienen la mayor parte de OnPointerHander . ¿Cómo me aseguro de que todo OnPointerHandler se OnPointerHandler en BoxCollider2D respectivo?

Problemas que estoy teniendo:

  1. OnPointerExit en A se activa cuando mi puntero ingresa B
  2. si hace clic dentro de B , OnPointerDown solo se activa en B pero no en A

¿Cuál es la funcionalidad prevista aquí? ¿Sospecho que quieres que el cepillo de dientes se muestre cada vez que un usuario hace clic dentro del espacio de la boca?

  1. Si es así, una manera divertida de solucionar esto sería ajustar el orden de los objetos ''B'' para que estén por encima del objeto ''A'' en la Jerarquía, de modo que se superpongan al área de colisión A. Esto a su vez permitirá que su interacción bloquee la interacción del área definida debajo del área de colisión definida por cada colisionador ''B''.

    Lo que estamos haciendo con esta metodología es forzar el evento OnPointerDown para que ocurra con el colisionador ''B'' antes de que tenga la oportunidad de colisionar con el colisionador ''A''.

Avíseme si tiene sentido y siéntase libre de hacer preguntas de seguimiento sobre el método.

Todavía no estoy seguro si su caso es lo que creo que es, pero aquí hay un video del método que mencioné: Video de demostración


Una de las ventajas y ventajas de EventSystem es que los eventos no pasan por GameObjects. El primero que es golpeado es devuelto. Aunque, parece que no quieres eso. Es complicado hacer que EventSystem devuelva múltiples GameObjects,

Hay dos soluciones para ti:

1. Obtenga ride de EventSystem ( OnPointerDown y IPointerDownHandler ) y use el sistema raycast de la vieja escuela.

Physics2D.RaycastAll y Physics2D.RaycastNonAlloc pueden hacer esto. Este ejemplo usará RaycastNonAlloc por razones de rendimiento. Es muy fácil.

Adjuntar a solo un GameObject (GameObject vacío) :

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 usando EventSystem pero EventSystem lanzar el evento.

En primer lugar, lanza raycast con EventSystem.current.RaycastAll luego invoca manualmente el evento con ExecuteEvents.Execute .

Adjunte a GameObject con 2D Collider y asegúrese de que Physics2DRaycaster esté conectado a la cámara :

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