03/10/26 · 6 min de lectura

Events en C#

Cómo crear un sistema de transmisión dinámico usando Eventos

Imagen por Vadim Bogulov .

Los eventos son delegados especializados que son útiles cuando quieres alertar a otras clases que algo está ocurriendo.

En la práctica, verás que los eventos funcionan de manera similar a los delegados públicos de multidifusión. Para obtener más información sobre los delegados, por favor consulta la lección sobre delegados vinculada en la parte inferior de este tutorial.

Un evento puede considerarse como un sistema de emisión, cualquier clase que esté Interesada en un evento puede suscribirle métodos. Cuando esa situación específica ocurra, como hacer clic en un botón, un potenciador o la herida a un jugador, invocamos nuestro evento y este a su vez invoca los métodos de las clases suscritas.

Tenemos una escena con dos esferas. Una esfera tiene un script llamado TeleportScript, mientras el otro tiene un script llamado TurnColorScript. Anexado a nuestra cámara esta el script EventManager

Un evento puede usarse para casi cualquier situación.

Pero en este ejemplo queremos invocar un evento cuando el jugador haga clic en un botón que estamos mostrando en la pantalla.

En nuestro EventManager, podemos ver que primero creamos un tipo de delegado al que vamos a llamar ClickAction().

public delegate void ClickAction();

Vemos que cualquier método que desee suscribirse a nuestro evento no debe tomar parámetros y debe tener un retorno de tipo void.

Luego, creamos nuestra variable tipo evento. Lo hacemos con la palabra reservada event. Ten en cuenta que esta variable también es estática, de esa manera podremos usarla fuera de la clase sin tener que instanciar un objeto de esta clase.

public static event ClickAction OnClicked;

Nuestra variable objeto, la misma que hemos llamado ClickAction(), es del tipo del delegado que creamos antes. Lo único más de lo que es responsable esta clase es invocar el evento cuando la situación apropiada se presente.

Como lo hemos dicho antes, invocamos este evento cuando el jugador haga clic en nuestro botón. Por lo tanto, este script tiene un método OnGUI(). Dentro del método OnGUI(), creamos un botón en nuestra pantalla.

void OnGUI()
{
    if(GUI.Button(new Rect(
        /*x*/ Screen.width / 2 - 50,
        /*y*/ 5,
        /*width*/ 100,
        /*height*/ 30),
        /*text*/ "Click"))
    {
        if(OnClicked != null)
        {
            OnClicked();
        }
    }
}

Cuando el jugador hace clic en el botón usamos nuestra variable evento como si fuera una función. Esto, efectivamente, invoca nuestro evento.

Ten en cuenta que, al igual que los delegados, provoca un error Si invocamos un evento sin suscriptores. Por lo tanto, siempre debemos asegurarnos de que el evento no sea igual a null antes de invocarlo.

Si recuerdas, las dos esferas en nuestra escena tienen dos scripts diferentes anexados a ellas. Estos scripts actuarán como suscriptores a ese evento. Vamos a echarle un vistazo ahora.

En el TeleportScript hemos creado un método llamado Teleport(). Este es el método al que suscribiremos el evento que hemos creado en el EventManager.

Tal vez te habrás dado cuenta de que el método Teleport() no toma parámetros y tiene un retorno tipo void, al igual que nuestro delegado.

void Teleport()
{
    Vector3 pos = transform.position;
    pos.y = Random.Range(1.0f, 3.0f);
    transform.position = pos;
}

El método Teleport() es el que ubica el objeto al azar a lo largo del eje vertical.

Cerca de la parte superior de nuestro script tenemos un método llamado Teleport(). Este es un método integrado que se invocará cuando el objeto al que el script está anexado se cree o se habilite en una escena.

void OnEnable()
{
    EventManager.OnClicked += Teleport;
}

Usaremos este método para suscribir nuestro método Teleport() al evento OnClicked en el EventScript. Podemos ver que suscribimos un evento al método usando el operador +=.

EventManager.OnClicked += Teleport;

Al suscribir un método a un evento nos aseguramos de que cuando el evento ocurra, se invocará nuestro método.

Luego, tenemos el método OnDisable(). Al contrario del método OnEnable() el método OnDisable se invoca cuando se destruye o se deshabilita un objeto en una escena Dentro del método OnDisable(), estamos cancelando la suscripción de nuestro método del evento.

void OnDisable()
{
    EventManager.OnClicked -= Teleport;
}

Cancelamos la suscripción de un método a un evento usando el operador -=.

EventManager.OnClicked -= Teleport;

Al hacerlo nos aseguramos de que nuestro método no se invoque más cuando ocurra un evento.

Este paso es muy importante y no hacerlo puede llevar a fugas de memoria y errores en tu juego. Una regla a seguir es que cuando suscribas un método a un evento, también debes tener la cancelación correspondiente.

Nuestro TurnColorScript está estructurado de manera muy similar a nuestro TurnColorScript. En este caso, tenemos un método llamado TurnColor(), que no toma parámetros y tiene un retorno tipo void. El método TurnColor() torna el material del objeto a un color al azar.

void TurnColor()
{
    Color col = new Color(
        /*r*/ Random.value,
        /*g*/ Random.value,
        /*b*/ Random.value);

    GetComponent<Renderer>().material.color = col;
}

Una vez más, tenemos los métodos OnEnable() y OnDisable(). Esta vez están suscribiendo y cancelando la suscripción al evento de nuestro método TurnColor(). También vale la pena recalcar otra vez que cancelar la suscripción al evento de nuestro método es importantísimo para usar los eventos correctamente y prevenir errores en nuestro código.

void OnEnable()
{
    EventManager.OnClicked += TurnColor;
}

void OnDisable()
{
    EventManager.OnClicked -= TurnColor;
}

De regreso en Unity, podemos rodar nuestra escena. Lo primero de lo que te darás cuenta es el botón que aparece cerca de la parte superior.

Al hacer clic en ese botón invocamos nuestro evento e invocamos los métodos Teleport() y TurnColor(). Podemos hacer clic en el botón muchas veces y cada vez los métodos suscritos se invocarán. Como puedes ver, nuestro EventManager solo debe preocuparse sobre el evento mismo y los desencadenantes del evento.

No necesitaba saber sobre los scripts Teleport o TurnColor. De la misma manera, esos scripts no necesitaban saber el uno sobre el otro. De esta manera, podemos crear un sistema de difusión muy robusto y flexible

Tal vez te estés preguntando por qué usamos una variable estática event en vez de una variable delegada pública en nuestro EventManager. Lo cierto es que puedes lograr la misma funcionalidad de event con variables delegadas públicas.

De hecho, como lo dijimos al principio de esta lección, los eventos son delegados especializados. La razón por la que usamos event en vez de las variables delegadas públicas para situaciones como esta es que los event tienen seguridad integrada a ellos intrínsicamente, mientras que las variables delegadas no.

Con los event, otras clases solo puedes suscribirse y cancelar la suscripción. Si usaras un variable delegada pública, otras clases podrían invocar o sobrescribir nuestra variable delegada para hacer cosas muy perversas.

Generalmente, si quieres crear un sistema de método dinámico que implica a más de una clase, usa las variables event en vez de variables delegadas.

Gist del proyecto

Apoya el contenido de mi blog a través de:

Fuente:

Copiado!