Delegados, Eventos y Acciones

Pues estamos en Agosto… algo tórrido para pensar… así que vamos con algo sencillo:

¡Los delegados!
tes2

Nada como delegar en otros, especialmente en periodo vacacional. Aunque el juego de palabras realmente acaba aquí, ya que me gustaría empezar a explicar (mas o menos) que son los delegados y para que se suelen usar.

Empecemos por el principio ¿Que son?

Segun MSDN:

Un delegate es un tipo de referencia que puede utilizarse para encapsular un método con nombre o anónimo.   Los delegados son similares a los punteros a funciones de C++

Es decir, es una variable de métodos (así a grosso modo). Podemos almacenar en un delegado uno o mas métodos que compartan la “Signature” del delegado. Cuando invoquemos al delegado, todos los métodos almacenados se ejecutan también con los parámetros que se le pasen al delegado. Para hablar bien en la jerga de los delegados, cambiad las palabras “Almacenar” por “Suscribir”. Los métodos se suscriben y de-suscriben de los delegados.


Signature:

Antes de continuar, la signature de un método es “Que parámetros tiene (de que tipo), cuantos, en que orden y qué devuelve este metodo”. Por ejemplo aquí tenéis una “Signature” (o Firma) de un método cualquiera:

signature

Este método no devuelve nada y acepta 2 enteros.


 

Ahora podemos ir por pasos para manejar los delegados.

Nota: En este Post voy a comentar solamente los delegados cuyo tipo de valor devuelto es “void” ya que es aconsejable no usarlos de otro tipo, ya que si tenemos 3 métodos subscritos a nuestro delegado que devuelven valores y lo invocamos solo obtendremos de vuelta el resultado de uno de ellos (teóricamente del ultimo, pero no se garantiza). Lógicamente hay maneras de obtener todos los valores devueltos de todos los métodos subscritos individualmente, pero esto lo dejo para otro momento.

1.) Definición del Delegado

Se definen como si fuera una Clase, Struct, Enum… indicando la Signature requerida:

Declaración.JPG

Ahora podremos declarar uno o varios delegados del tipo “miDelegado”. (Puede ser Definido dentrofuera de una clase)

2.) Declarar Delegado

Generalmente como parte de una clase. No nos hace falta instanciar, ya que es un tipo de referencia; es decir, no nos hace falta llamar a un constructor.

Declaración.JPG

Notese que podemos declarar mas de un delegado del mismo tipo:

Declaracion 2.JPG

3.) Suscribir Métodos

En nuestro ejemplo: ahora podemos subscribir métodos que devuelvan “void” y reciban 2 parámetros enteros. Como por ejemplo mirad estos dos métodos:

metodos.JPG

Durante el método predeterminado de Unity de “Start”, “Awake” ó “OnEnable” (por ejemplo) podemos subscribir estos métodos a su respectivo delegado. Podemos hacerlo desde donde creamos conveniente, según la situación. De esto hablaré mas adelante. Para suscribirlos usaremos ‘+=’ y el nombre del método sin paréntesis ya que se trata del método en sí, no del resultado del método, es decir de su invocación:

suscribir.JPG

Por motivos de demostración el delegado (sumatorio o multiplicatorio) está en el mismo objeto que el método a suscribir (sumar o multiplicar) aunque generalmente el delegado está en otro Script en otro GameObject que se encarga de invocarlo.

Además, es conveniente Siempre añadir una condición por la que los métodos se de-suscriban usando ‘-=’. En nuestro ejemplo usaré “OnDisable”, que se lanzara cuando el GameObject se deshabilite:

desus

4.) Invocar Delegado

Se invocan como un método normal es decir: “sumatorio(4,4)” en nuestro ejemplo valdría. Aunque no es absolutamente necesario ademas habria que comprobar que el delegado no está vació(sin nada suscrito) antes de invocarlo:

summon.JPG

En el ejemplo, los delegados se lanzan al pulsar el botón de “Espacio” en el teclado. Si adjuntamos ésto a un GameObject (debería) funcionar:

debug.JPG

Al hacer “OnEnable” (al principio del juego) el método “sumar” se suscribe a “sumatorio“. Durante el “Update” se invoca “sumatorio” y por tanto se ejecuta “sumar” con los parametros de “sumatorio“. Lo mismo con “multiplicar” y “multiplicatorio” (yo y los nombres). Resulta un tanto raro, pero tiene su sentido 😉


 

A tener en cuenta: Podemos suscribir mas de un método a un delegado. Esto se llama “Multicasting”, al invocar el método todos los metodos suscritos se ejecutan.

En ocasiones querremos usar Multicasting, y en otras querremos que nuestro delegado solo contenga 1 método tened en cuenta lo siguiente:

  • con “+= método” suscribimos (añadimos un método al delegado)
  • con “-= método” de-suscribimos (retiramos ese método del delegado, si no lo encuentra no pasará nada)
  • con “= método” haremos que el método sea el único método suscrito
  • con “= null” limpiamos el delegado.

Utilidad:

Muy bien Mese, ya sabemos como funciona esto. ¿Para que nos vale?.

Por ejemplo, áreas de efecto por zonas en vuestro juego. El script de vuestro PJ y/o enemigos puede tener un metodo del tipo “void RecibirDaño(int Cantidad)”. En tal caso si el Jugador o enemigo entra en la zona de efecto se suscribe su “RecibirDaño” al delegado correspondiente y cada X segundos lo invocáis. Cuando salgan del efecto se desuscribe el método y listo!.

También para programar Callbacks, ó como Eventos. Pero antes de hablar de esto, hagamos un pequeño parón para ver las “Action”


 

Actions

A grandes rasgos: Son delegados, pero que no devuelven nada (“void”) es decir, lo mismo que hemos visto, con la ventaja de que no tenemos que definirlos sino que ya vienen “Definidos” (Es decir, nos podemos saltar el paso 1 de mas arriba). También, a las Actions no les importa un carajo el nombre de nuestros parámetros, tan solo el tipo y el orden:

Actions.JPG

El resto del funcionamiento es exactamente igual a un delegado!

Personalmente, recomiendo el uso de Actions en lugar de delegados, salvo que sepamos lo que estamos haciendo.

Nota: Debemos usar el “namespace” System poniendo “using System;” al principio de nuestro script.


Eventos

Tal vez sea una decepción, peeeero….

A grandes rasgos: Son delegados Multicast (como los hemos visto). Pero está vez a la hora de declararlos (paso 2) ponemos la palabra clave “event” delante tal que así:

Events.JPG

Suelen ser públicos y suelen ser estáticos, para poder ser llamados desde cualquier sitio y funcionan exactamente igual que los delegados salvo lo siguiente:

  • Pueden ser declarados en “Interfaces”.
  • Tienen su propio “get y set” llamados “add y remove” para convertirlos en una propiedad, y hacer cosas extra al suscribir o desuscribir métodos.
  • La invocación de un delegado está restringida a la clase que lo declara. Un evento puede ser invocado por cualquiera que tenga acceso (por ejemplo, si es “público”, puede ser lanzado desde otro sitio).

Es decir, claramente superiores y mas personalizables. Tenéis mas info aquí.

En cuanto a jerga de eventos común: suelen llamarse “EventHander” y su nomenclatura suele llevar un “On” delante por ejemplo “OnClicked”. El método que se suscribe a un evento se le suele llamar “Listener”. De manera que cuando un evento se dispara (se invoca) todos los listener se ejecutan.

Un ejemplo de uso de Eventos muy común para Unity es el manejo, precisamente, del “OnClicked”:

Clickmanager.JPG

Esto va en un objeto (y solo uno). Podría considerarse un “singleton“.

soldado.JPG

Y esto en todos aquellos objetos susceptibles de ser clickados.

Y con pocas lineas de código tenéis un sistema de clicks!


CallBacks

Por ultimo voy a (intentar) explicar con mis palabras que es un callback.

Se le llama callback a un Action, o delegado, que es llamado hacia atrás, es decir, a niveles superiores de la invocación, suele ser pasado como parámetro. Esto es importante cuando tengamos un sistema de “Datos” diferenciado del sistema de Unity.

No es extraño hacer el “Cerebro” del juego en C#, sin API de Unity, (es decir sin heredar de MonoBehaviour) que genere los datos, acciones y eventos; y por otro lado tener otra parte del juego dedicada a representar estos datos, acciones y eventos en la pantalla a través de la API de Unity (Es decir, esta vez si heredando de MonoBehaviour).

En esencia un “Callback” puede ser “Action<int, float> ActualizarInterfaz“. Desde la parte de MonoBehaviour se rellena este Callback (suscribe) con lo que se hace para Actualizar la interfaz. Pero es el Cerebro, es decir la parte SIN MonoBehaviour la que decide cuando lanzarlo. De esta manera podemos ejecutar código de MonoBehaviour desde una parte del código que no hereda de MonoBehaviour.

Mas concretamente, los callbacks se suelen pasar como parámetro a funciones que no tienen el API correcto para ejecutar esa parte del código ó que sencillamente queremos que ejecuten un trocito de código que pertenece a otra clase u objeto, haciendo nuestro código dinámico. Ahí va un ejemplo:

Callback.JPG

 


 

Mas info de todo esto:

Así como otras entradas relacionadas en mi blog:

Esto es todo!

Muchas gracias! si os a gustado seguidme en Twitter! o ponedme en vuestro feed de blogs!

Y también tengo un canal de Gaming en Youtube!

Cualquier duda, dejadme un comentario!

Hasta la próxima!

 

Advertisements

One thought on “Delegados, Eventos y Acciones

  1. Pingback: Timer | Mecze Entertainment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s