UNITY Coroutines

De MediaWiki
Revisión del 09:24 4 mar 2022 de Angelfg (discusión | contribuciones) (Coroutine Unity)
(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Ir a la navegación Ir a la búsqueda

Introducción

Una corutina es un método que permite ejecutarse en cada frame o, si queremos, que espere un cierto número de segundos antes de continuar su ejecución.

Recordar que cuando Unity llama al método Update de cualquier script, lo está llamando cada x milisegundos, indicado por el valor de Time.deltaTime.

Esto quiere decir, que si la máquina funciona a 60 frames por segundo (60fps) está llamando 60 veces al método y por consiguiente a cualquier método que llamemos desde update.

Una corutina me va a permitir que la ejecución se 'pare' durante un frame o durante un tiempo indicado por nosotros.

Normalmente una corutina se emplea para generar gameobjects a partir de un prefab de forma continua cada cierto tiempo, por ejemplo, enemigos que aparecen durante el juego, como ya vimos en los Prefabs.


IMPORTANTE:

  • Una corutina no es un hilo de ejecución separado del hilo principal. Si programamos un bucle infinito y no escribimos la orden para que salga de la corutina, Unity quedará bloqueado.
  • No llamar a una corutina de forma continua dentro del método Update de un script.



Funcionamiento

Para hacer uso de una corutina debemos de seguir estos pasos:

  • Definir un método que va a ser la corutina de la forma: private IEnumerator nombre_metodo { }
Para ello es necesario importar el espacio de nombres System.Collection: using System.Collections;
private IEnumerator Corutina()
{
}


  • Ahora, dentro del método siempre debemos de tener la orden: yield opción
Normalmente las opciones que se ponen son:
  • yield return null; => No continúa la ejecución hasta el siguiente frame.
  • yield return WaitForSeconds(num_segundos); => No continúa la ejecución hasta que pasen el número de segundos indicados.
  • yield break; => Sale de la corutina.
  • Otras opciones de Wait aparecen y son bastante sencillas de entender.


  • Se llama al método StartCoroutine enviando como parámetro el nombre del procedimiento que devuelve un IEnumerator. Este método está sobrecargado, y podemos llamarlo de varias formas:
  • StartCoroutine(Corutina()) => Va el nombre del método con paréntesis.
  • StartCoroutine("Corutina") => Va el nombre del método entre comillas y sin paréntesis.



Ejemplos

Ejemplo 1: Empleo de yield return null.

using System.Collections;

......

    private IEnumerator Corutina()
    {

        int cont = 0;
        while (true)
        {
            Debug.Log("Contador:" +cont);
            cont++;
            yield return null;
        }
    }
    void Start()
    {
        StartCoroutine(Corutina());
    }
    void Update()
    {
        Debug.Log("UPDATE");
    }
Fijarse que por consola aparecen los dos debug (UPDATE y CONTADOR).
Lo que está haciendo la corutina es sacar por pantalla un contador que se va incrementando, pero dicho incremento lo hace cada frame por segundo de la máquina.
Si no tuviéramos la orden yield, Unity quedaría bloqueado, ya que nunca saldría del bucle infinito.



Ejemplo 2: Cambio de color.

Para mostrar la diferencia de ejecutar un código dentro de una corutina, voy a hacer que el script cambie el color de un gameobject. Para ello tenéis que asociar el script a un gameobject de la escena que tenga material.
 1     private IEnumerator CambiarColorCorutine()
 2     {
 3         Renderer renderer = GetComponent<Renderer>();
 4         Color c = renderer.material.color;
 5         for (float valor = 0f; valor <= 200; valor += 0.1f)
 6         {
 7             c.r = valor;
 8             c.g = valor;
 9             renderer.material.color = c;
10             yield return null;
11         }
12     }
13 
14     void Start()
15     {
16         StartCoroutine("CambiarColorCorutine");
17     }
  • Al ejecutar el script podéis comprobar como se cambia el color del gameobject y lo hace rápidamente pero no de forma 'instantánea'.
Si vuestra máquina (CPU) funciona a 60fps, cada vez que el método ejecuta la orden yield return null; sale y al siguiente frame continúa la ejecución.
Por lo tanto, si el contador va desde 200 hasta 0, tarda 200 frames en terminar de ejecutarse, por lo tanto 200/60 => 3,3 segundos.


  • Se ejecutáis el mismo código sin emplear una corutina, podéis comprobar como el cambio es instantáneo, ya que dentro del mismo frame ejecuta el bucle completo:
 1     private void CambiarColorCorutine()
 2     {
 3         Renderer renderer = GetComponent<Renderer>();
 4         Color c = renderer.material.color;
 5         for (float valor = 0f; valor <= 200; valor += 0.1f)
 6         {
 7             c.r = valor;
 8             c.g = valor;
 9             renderer.material.color = c;
10         }
11     }
12     void Start()
13     {
14         CambiarColorCorutine();
15     }



Ejemplo 3: Esperar un número de segundos. Como comenté anteriormente, este recurso se suele emplear para crear enemigos (instanciar prefabs) cada cierto número de segundos. En este ejemplo podemos ver como el log aparece cada 3 segundos. Ejemplo de uso con prefabs lo tenéis en esta sección de la WIKI.

 1     private IEnumerator CadaSegundos(float segundos)
 2     {
 3         int cont = 0;
 4         while (true)
 5         {
 6             Debug.Log("Contador:" + cont);
 7             yield return new WaitForSeconds(segundos);
 8             cont++;
 9         }
10     }
11 
12     void Start()
13     {
14         StartCoroutine(CadaSegundos(3));  // Enviamos un parámetro a la coroutine
15     }


  • Por consola aparecerá el mensaje cada 3 segundos.



Ejemplo 4: Esperar un número de segundos y cuando llegue a 5 segundos sale de la corutina.

 1     private IEnumerator CadaSegundos(float segundos)
 2     {
 3         int cont = 0;
 4         while (true)
 5         {
 6             Debug.Log("Contador:" + cont);
 7             yield return new WaitForSeconds(segundos);
 8             cont++;
 9             if(cont==5)
10                 yield break;
11         }
12     }
13     void Start()
14     {
15         StartCoroutine(CadaSegundos(3));  // Enviamos un parámetro a la coroutine
16     }






Enlace a la página principal del curso




-- Ángel D. Fernández González -- (2018).