c# unity3d interface

c# - En Unity, ¿cómo llama Unity mágicamente todas las "Interfaces"?



unity3d (2)

Unity tiene una "interfaz" como lo llaman IPointerDownHandler ( doco ).

Simplemente implementa OnPointerDown ...

public class Whoa:MonoBehaviour,IPointerDownHandler { public void OnPointerDown (PointerEventData data) { Debug.Log("whoa!"); } }

y Unity llamará "mágicamente" al OnPointerDown en cualquier MonoBehavior.

NO tiene que registrarlos, establecer un evento o hacer cualquier otra cosa .

Todo lo que haces es agregar "IPointerDownHandler" y "public void OnPointerDown" a una clase, y puedes obtener esos mensajes en todo momento mágicamente.

(Si no eres un desarrollador de Unity, ¡incluso funciona si de repente agregas uno en el Editor mientras el juego se ejecuta!)

¿Cómo diablos hacen eso?

¿Cómo puedo hacer eso con una extensión? Es más como una clase abstracta: ¿cómo lo hacen? Entonces, quiero hacer esto:

public interface IGetNews { void SomeNews(string s); }

y luego puedo agregar SomeNews a cualquier MonoBehavior , y así "enviar noticias" a esos artículos en cualquier momento.

Estoy completamente familiarizado con las diversas soluciones alternativas. Quiero saber cómo logran ese comportamiento "mágico".

(Por cierto: siento que Unity no debería haber llamado a estas interfaces , ya que básicamente no es nada como una interfaz, ¡es todo lo contrario! Se podría decir que mágicamente hicieron una forma de heredar de más de una clase abstracta, supongo .)

Aparte:

solo para mayor claridad, si no ha utilizado Unity anteriormente, la forma convencional de hacerlo (es decir, ya que no tenemos acceso a la magia de Unity) es así: simplemente agregue un UnityEvent a su daemon que enviará el mensaje en pregunta:

public class BlahDaemon:MonoBehaviour { public UnityEvent onBlah; ... onBlah.Invoke();

Supongamos que tiene clases Aaa, Bbb, Ccc que quieren recibir el mensaje. Si eres nuevo en UnityEvent, a menudo simplemente "arrastras el editor" de Aaa, Bbb, Ccc al evento en BlahDaemon. Sin embargo, puede "registrarse" en el código:

public class Aaa:MonoBehaviour { void Awake() { BlahDaemon b = Object.FindObjectOfType<BlahDaemon>(); b.onBlah.AddListener(OnBlah); } public void OnBlah() { Debug.Log("almost as good as Unity''s"); } }

Esto es "casi tan bueno" como usar la magia interna de Unity, aunque es mucho más complicado en el código. Dado que te estás "registrando" por así decirlo en Awake , de hecho estás aprovechando el mismo uso mágico de la Unidad.


Puede usar reflection para obtener todos los tipos en un ensamblado que implementa una interfaz específica y luego crear instancias de esos tipos y llamar a los métodos en esas instancias a través de la interfaz.

var types = this.GetType().Assembly.GetTypes() .Where(t=>t.GetInterfaces().Contains(typeof(IGetNews))); foreach (var type in types) { var instance = (IGetNews) Activator.CreateInstance(type); instance.SomeNews("news"); }


Cuando se trata de XXXUpdate, OnCollisionXXX y otros MonoBehaviours, la forma en que Unity se registra no es un reflejo, como se creía, sino un proceso interno de compilación.

CÓMO SE LLAMA LA ACTUALIZACIÓN

No, Unity no usa System.Reflection para encontrar un método mágico cada vez que necesita llamar a uno.

En cambio, la primera vez que se accede a un comportamiento mono de un tipo determinado, el script subyacente se inspecciona a través del tiempo de ejecución de scripts (ya sea Mono o IL2CPP) si tiene algún método mágico definido y esta información se almacena en caché. Si un MonoBehaviour tiene un método específico, se agrega a una lista adecuada, por ejemplo, si un script tiene el método de actualización definido, se agrega a una lista de scripts que deben actualizarse en cada fotograma.

Durante el juego, Unity simplemente itera a través de estas listas y ejecuta métodos desde allí, así de simple. Además, esta es la razón por la que no importa si su método de actualización es público o privado.

http://blogs.unity3d.com/2015/12/23/1k-update-calls/

En el caso de una interfaz, supongo que hace un poco más ya que se requiere la interfaz. De lo contrario, solo agregaría el método como cualquier otro método de comportamiento en mono.

Mi suposición (que podría ser incorrecta), usa un GetComponents básico en este GameObject. A continuación, itere la matriz resultante y llame al método que DEBE implementarse, ya que proviene de la interfaz.

Puedes reproducir el patrón con:

NewsData data; if(GetNews(out data)) { IGetNews [] getNews = data.gameObject.GetComponents<IGetNews>(); foreach(IGetNews ign in getNews){ ign.SomeNews(); } }

GetNews es un método que verifica si se deben enviar algunas noticias al objeto. Podrías pensar en ello como Física.Raycast que asigna valores a un RaycastHit. Aquí completa una referencia de datos si ese objeto está destinado a recibir noticias por algún motivo válido.