Coroutine

Od dawna miałem się zabrać za pojęcie ‚współprogramów’ (ang. coroutines), jednak wydawały mi się trudne i radziłem sobie bez nich. Równo miesiąc temu podczas Sensei Game Jam dostałem za zadanie napisać prosty timer. Banalny. Skrypt na kilkadziesiąt linijek kodu. Kolega zasugerował zastosowanie Coroutine, a jako że ich nie umiałem to nabazgrałem coś po swojemu. Okazało się że często wracaliśmy do tego pliku, ponieważ akcja postaci była ściśle powiązania z licznikiem na GUI (krzyk Gandalfa zwiększał poziom przegrzania jego gardła). Za każdym razem płakaliśmy czytając skrypt, bo po około godzinie od powstania doszło do standardowej sytuacji:

Jak najprościej wytłumaczyć czym jest współprogram? Standardowy kod wykonuje się sekwencyjnie – jedna instrukcja po drugiej. Jeśli chcielibyśmy stworzyć nieskończoną pętlę, to przy takim podejściu program by się zawiesił. Przykład takiej pętli? Wróg idzie w prawo 10 jednostek, czeka 2 sekundy, idzie w lewo 10 jednostek, czeka 2 sekundy, i tak w koło Macieju.

Nie wiem jaki wpływ będzie miało wprowadzenie .NET 4.6 na Unity, bo jest ciągle w fazie testów, jednak pojawiają się już takie artykuły: Async-Await instead of coroutines in Unity 2017. Zaletą Coroutines jest ich prostota i w małych grach nie powinny sprawiać problemów. Wystarczy zmienić zwracany typ na IEnumerator, bo wymaga tego yield umożliwiający wyjście i powrót do metody.

Prosta implementacja może wyglądać tak:

W efekcie czego powstał ten biedny gif:

Warto też wiedzieć że istnieje metoda StopCoroutine(). Najbezpieczniej jest przechować Coroutine jako obiekt o typie IEnumerator i przekazać go do niej. Można też zatrzymywać je po nazwie, ale wtedy ubity zostanie pierwszy napotkany współprogram.

Inny przykład:

I kolejny biedny gif (sorry za 20 FPS):

Warto też zastosować się do słów Herman’a Tulleken z 50 Tips and Best Practices for Unity (2016 Edition) i nauczyć się jak odpalić Coroutines jedna po drugiej oraz równolegle: