Usar Delegates y Events en Unity

0
11513
Título del tutorial

Introducción

El objetivo de este tutorial es entender cómo usar Delegates y Events en Unity. No existen muchos ejemplos prácticos en este tema en español por lo que con este tutorial trato de llenar ese hueco.

Para seguir este tutorial se asume que se tiene un conocimiento básico de Unity: se sabe navegar en el editor, crear componentes y trabajar con colisiones con Colliders y Triggers. Para empezar en Unity recomiendo este tutorial oficial de un proyecto en 3D y por supuesto el manual.

Entorno

El tutorial se ha realizado en el siguiente entorno:

  • Portatil MSI GL62M (CPU 7700HQ, GPU 1050Ti y 8 GB de RAM).
  • Windows 10 Education.
  • Unity 2020.2 Personal.

Conceptos

Un Delegate es una referencia a un método. Nos permite tratar ese método como una variable y pasarlo como variable para un callback. Cuando se invoca, notifica a todos los métodos que hacen referencia al Delegate. El funcionamiento es el del patrón Observador.

Por poner un ejemplo del mundo real es como el de un periódico. Una persona puede suscribirse a dicho periódico y cada vez que salga una nueva entrega todas las personas suscritas la recibirán.

Los eventos añaden una capa de abstracción y protección al Delegate. Esto previene al cliente del Delegate de resetearlo y eliminar la lista de suscriptores.

Ejemplo práctico

Vamos a aplicarlo en un ejemplo práctico. Tenemos una escena en la que hay una puerta y una baldosa en el suelo que funciona como interruptor. Queremos que cuando un objeto entre en contacto con la baldosa se abra la puerta.

En la imagen se muestra la escena:

En la imagen se muestra la escena con los distintos objetos.

El cubo azul va a ser lo que mueva el jugador, la baldosa marrón claro el interruptor y el prisma rojo la puerta. El resto de la escena son cubos que hacen de pared y suelo.

Interruptor

El interruptor es un cubo con un Box Collider con el valor trigger activado.

Definamos un script para la puerta:

using UnityEngine;
using System.Collections;

public class DoorSwitch : MonoBehaviour
{

    public delegate void Contact();
    public event Contact OnContact;
     
    private void OnColliderEnter(Collider other)
    {
        if(OnContact != null)
            OnContact();
    }

}

Estamos usando OnColliderEnter, que se va a disparar en la frame en la que el objeto entre en contacto con un Collider. Para que este evento se dispare es necesario que:

  1. Alguno de los dos objetos que participan en el contacto debe tener un Rigidbody.
  2. El objeto que entra en contacto tiene un Collider y no es trigger.

Es una imagen de los componentes del objeto del interruptor.

Puerta

Necesitamos que la puerta se suscriba al evento de OnContact del interruptor para que se abra cuando se dispare. Hay que dar de baja el evento con el método OnDisable() (el cual se llama cuando se elimine el objeto o se desactive el componente) para evitar que se quede en memoria, ya que Unity no va a encargarse de ello.

using UnityEngine;
using System.Collections;

public class Door : MonoBehaviour
{

    public DoorSwitch doorSwitch;

    void Start()
    {
        doorSwitch.OnContact += Open;
    }

    private void Open()
    {
        transform.Translate(Vector3.up * 3f);
    }

    void OnDisable()
    {
        doorSwitch.OnContact -= Open;
    }

}

La puerta, al recibir el evento de OnContact, va invocar el método Open() y subir 3 metros hacia arriba. Hemos definido el campo doorSwitch como public para poder arrastrar el objeto del interruptor en el editor.

Es una imagen de los componentes del objeto puerta.

Jugador

El jugador va a ser el objeto que colisione con el interruptor y abra la puerta. Visualmente va a ser un simple cubo, que va a tener un Box Collider y un Rigidbody. Le vamos a añadir un componente con el siguiente script para que pueda moverse en el plano horizontal con las teclas WASD:

using UnityEngine;
using System.Collections;public class Player : MonoBehaviour
{

    void Update()
    {
        if (Input.GetKey(KeyCode.A))
            transform.Translate(2 * Time.deltaTime * Vector3.left);
        if (Input.GetKey(KeyCode.D))
            transform.Translate(2 * Time.deltaTime * Vector3.right);
        if (Input.GetKey(KeyCode.W))
            transform.Translate(2 * Time.deltaTime * Vector3.up);
        if (Input.GetKey(KeyCode.S))
            transform.Translate(2 * Time.deltaTime * Vector3.down);
    }
}

Es una imagen de los componentes del objeto jugador.

Probar el juego

Al entrar en el modo Play y mover el cubo azul hasta el interruptor comprobamos que la puerta sube.

Se muestra la escena en la que la puerta ha subido.

Conclusión

En este tutorial se ha visto cómo  usar Delegates y Events en Unity, montando una pequeña escena de ejemplo.

El uso de Delegates y Events de C# nos permite tener un código más simple y evitar referencias directas entre los componentes. La clase que emite el evento no tiene que saber qué objetos van a querer estar suscritos al evento y en tiempo de ejecución pueden añadirse o eliminarse suscriptores.

Tiene la limitación de que no tiene representación en el editor y para los miembros del equipo que no sean programadores es un obstáculo, pero en caso de que se quieran manejar eventos en el editor siempre se pueden utilizar UnityEvents.

También hay que recordar dar de baja los eventos cuando se eliminen los objetos que lo usan, para evitar fugas de memoria.

Referencias

http://www.unitygeek.com/delegates-events-unity/

 

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad