1 00:00:07,120 --> 00:00:12,500 Vamos a hablar de las corrutinas, que son, para qué sirven y cómo se usan. 2 00:00:13,099 --> 00:00:17,660 Pero antes de hacerlo voy a hablar de un concepto, que es el de la ejecución asíncrona de un script. 3 00:00:17,980 --> 00:00:23,260 Normalmente cuando en programación ejecutamos scripts, pues lógicamente se ejecutan, pues como hemos visto, 4 00:00:23,739 --> 00:00:25,739 según van saliendo las líneas de código. 5 00:00:26,379 --> 00:00:30,359 Y de hecho hasta que no se termina la ejecución de una línea o de un bucle, ahí está la clave, 6 00:00:30,899 --> 00:00:34,960 pues no sigue ejecutándose el script, lo cual nos produce bastantes limitaciones a la hora de 7 00:00:34,960 --> 00:00:41,020 de programar ciertos comportamientos complejos. Lo voy a ejemplificar mediante 8 00:00:41,020 --> 00:00:49,799 un código que nos ayudará a entenderlo. Voy a crear un nuevo script que no 9 00:00:49,799 --> 00:00:52,359 necesito que esté asociado a ningún GameObject y, por tanto, me viene muy bien, como ya 10 00:00:52,359 --> 00:00:55,960 hemos visto hasta ahora, crear un EmptyObject. Lo voy a renombrar, le voy a llamar 11 00:00:55,960 --> 00:01:02,820 contador y le voy a añadir un componente, un script, al que le voy a llamar, por 12 00:01:02,820 --> 00:01:07,819 ejemplo, counter, para saber que voy a crear un contador en ese texto. Sabiendo 13 00:01:07,819 --> 00:01:12,079 que ya tengo control sobre el texto voy a hacer un ejemplo para entender por qué 14 00:01:12,079 --> 00:01:16,840 a veces la ejecución de los scripts tiene que ser asíncrona. Vamos a poner 15 00:01:16,840 --> 00:01:23,540 un ejemplo. Imaginemos que yo en la función start voy a crear un bucle, tal como 16 00:01:23,540 --> 00:01:29,060 hemos aprendido, por ejemplo con un for, y le voy a decir que el texto 17 00:01:29,060 --> 00:01:36,319 de esa user interface sea igual a n, diciéndole que ponga un texto 18 00:01:36,319 --> 00:01:42,049 contador, dos puntos, espacio, y concateno, con lo cual eso ya es un texto, 19 00:01:42,170 --> 00:01:45,510 aunque incluya un número entero, pero el conjunto general ya es una variable de tipo texto. 20 00:01:46,329 --> 00:01:48,290 Entonces, ¿qué es lo que acabamos de hacer? 21 00:01:48,329 --> 00:01:51,790 Un bucle que se va a repetir 11 veces, porque empezamos a contar por cero, 22 00:01:52,549 --> 00:01:57,829 y en cada vuelta va a cambiar el texto y le va a decir que ponga contador seguido de el número. 23 00:01:58,269 --> 00:02:01,969 Y una persona, digamos, un humano pensaría que lo que vamos a ver es una cuenta hacia adelante, 24 00:02:01,969 --> 00:02:05,950 0, 1, 2, 3, 4, 5, hasta 10, pero si lo ejecuto, veremos que se produce algo. 25 00:02:05,950 --> 00:02:12,849 Lo lanzo y ¿qué texto me aparece aquí? Mi contador es 10. De golpe. ¿Por qué ocurre esto? 26 00:02:13,330 --> 00:02:19,469 Porque el código se ha quedado aquí dando vueltas y él no ha seguido ejecutando todo lo demás hasta que ha terminado este bucle. 27 00:02:19,849 --> 00:02:23,930 Y cuando ha terminado ese bucle ha seguido con la ejecución. ¿Y qué valor tenía esto cuando ha terminado el bucle? 28 00:02:24,069 --> 00:02:28,689 Pues contador igual a 10. Y claro, yo no he visto ese proceso. Así que para eso existen las corrutinas. 29 00:02:28,689 --> 00:02:36,949 Las corrutinas existen precisamente para poder ejecutar un script mientras se continúa la ejecución de todo lo demás. 30 00:02:37,490 --> 00:02:43,909 Es como una especie de, bueno, quédate tú ejecutando mientras yo sigo con todo el procesamiento. 31 00:02:44,389 --> 00:02:50,870 Pero además las corrutinas nos ofrecen algo que ahora mismo necesito, que es, vale, yo quiero que te quedes ahí ejecutándote, 32 00:02:51,030 --> 00:02:56,270 pero además necesito, pues lo que acabo de hacer, hacer un bucle, pero ese bucle que no se ejecute de golpe, 33 00:02:56,270 --> 00:02:59,289 sino que se vaya ejecutando cada cierto tiempo, lo que sería un contador. 34 00:02:59,909 --> 00:03:05,610 Imaginémonos que yo voy a contar 10 segundos hacia adelante, 0, 1, 2, 3, 4, 5, y cada uno tiene que durar un segundo. 35 00:03:06,090 --> 00:03:11,210 Con lo cual, aunque eso lo podría hacer con el método update de una forma un poco rebuscada, 36 00:03:11,669 --> 00:03:14,330 lo realmente útil es usar las corrutinas. ¿Por qué? 37 00:03:14,449 --> 00:03:19,270 Porque aparte de ejecutarse de forma asíncrona, nos permiten meterle el parámetro de 38 00:03:19,270 --> 00:03:22,449 y cada cuánto tiempo se ejecuta esa corrutina. 39 00:03:22,770 --> 00:03:26,150 Vamos a ver cómo funcionan y cómo es la sintaxis. 40 00:03:26,270 --> 00:03:30,810 lo primero que tenemos que saber de las corrutinas es que funcionan como si fuesen métodos 41 00:03:30,810 --> 00:03:35,169 se utilizan mediante el método general de enumerator, se escribe así 42 00:03:35,169 --> 00:03:38,810 y funcionan como un método en el sentido de que le tenemos que dar un nombre 43 00:03:38,810 --> 00:03:41,610 por ejemplo le voy a decir cronómetro, cuidado con las tildes 44 00:03:41,610 --> 00:03:49,580 así que si nos fijamos, esto es como si fuese un método 45 00:03:49,580 --> 00:03:54,360 y lo tenemos que llamar, de hecho ahora me está dando un error porque me está diciendo que no estoy dándole 46 00:03:54,360 --> 00:03:58,240 el parámetro apropiado para continuar esta corrutina, ¿y cuál es el parámetro adecuado? 47 00:03:58,240 --> 00:04:11,599 Pues uno que siempre tendremos que poner, que es así. Se escribe yield return. Y eso lo tenemos que escribir. Y le tenemos que dar un valor. ¿Cuál? El tiempo que queremos que pase entre una vuelta y otra. 48 00:04:12,000 --> 00:04:21,500 Si le decimos que null, directamente se ejecuta en cada fotograma. Un poco parecido al update. Pero, cuidado, esto no es un bucle. No nos confundamos. 49 00:04:21,500 --> 00:04:24,060 esto no es como el update 50 00:04:24,060 --> 00:04:25,620 que se ejecuta de forma permanente 51 00:04:25,620 --> 00:04:27,779 esto se ejecutaría una vez 52 00:04:27,779 --> 00:04:29,339 si yo lo llamo, si yo quiero 53 00:04:29,339 --> 00:04:31,879 que haga un bucle, lo tengo que crear yo 54 00:04:31,879 --> 00:04:33,980 por ejemplo, mediante un while 55 00:04:33,980 --> 00:04:35,920 y while si nos recordamos 56 00:04:35,920 --> 00:04:37,639 lo que tenemos que decirle es para 57 00:04:37,639 --> 00:04:39,819 un parámetro 58 00:04:39,819 --> 00:04:42,160 o una condición que mientras se dé while se va a ejecutar 59 00:04:42,160 --> 00:04:43,800 pero si le escribimos true 60 00:04:43,800 --> 00:04:45,680 directamente, acabo de crear un bucle infinito 61 00:04:45,680 --> 00:04:48,040 y es en ese bucle infinito 62 00:04:48,040 --> 00:04:51,240 donde yo le puedo decir que 63 00:04:51,240 --> 00:04:57,480 ejecútate cada fotograma. Lo vamos a comprobar y esta vez no lo voy a mandar a la ventana del 64 00:04:57,480 --> 00:05:01,920 texto, sino que lo voy a mandar a la consola para que lo veamos mejor. Voy a ejecutarlo, pero esto es como 65 00:05:01,920 --> 00:05:06,620 si fuese un método. Alguien lo tiene que llamar, alguien lo tiene que ejecutar. Pues bien, para ejecutar 66 00:05:06,620 --> 00:05:13,779 una corrutina, para que empiece a funcionar, existe el comando start corrutin. Y entre paréntesis 67 00:05:13,779 --> 00:05:17,839 y entre comillas, porque es un nombre, le tenemos que dar el nombre de la corrutina que queremos 68 00:05:17,839 --> 00:05:26,420 ejecutar. Así que cuando se ejecute el script, llamará la corrutina, que lo que hace es 69 00:05:26,420 --> 00:05:30,980 un bucle infinito, en el que le he dicho que me muestre hola en la consola y además ejecute 70 00:05:30,980 --> 00:05:38,879 cada fotograma. Vamos a ver si funciona. Lo lanzo. Y si todo va bien, ahí lo tenemos. 71 00:05:39,019 --> 00:05:42,920 Me está diciendo hola, pero si nos fijamos, me está mandando todos esos mensajes en cada 72 00:05:42,920 --> 00:05:46,259 fotograma. Eso está bien, pero no es lo que quiero. Además, para eso ya tenía el update. 73 00:05:46,439 --> 00:05:49,980 Vamos a la función realmente interesante de las corrutinas, que es poder decirle, 74 00:05:50,560 --> 00:05:53,040 espera un tiempo antes de volver a dar una vuelta. 75 00:05:53,680 --> 00:05:58,560 En vez de decirle aquí null, le podemos crear una instancia 76 00:05:58,560 --> 00:06:03,360 llamado waitForSeconds, por lo tanto, tenemos que llamarlo 77 00:06:03,360 --> 00:06:07,500 mediante la instanciación de una clase llamada waitForSeconds 78 00:06:07,500 --> 00:06:11,019 y aquí está esperando un número decimal, un float, 79 00:06:11,240 --> 00:06:12,399 que nos dirá cuántos segundos. 80 00:06:12,579 --> 00:06:14,939 Yo le puedo decir que uno, con la F para indicarle que es un float, 81 00:06:15,379 --> 00:06:17,899 y eso significa que va a esperar un segundo en cada vuelta del ciclo. 82 00:06:18,319 --> 00:06:18,959 Vamos a comprobarlo. 83 00:06:19,920 --> 00:06:20,319 Guardo. 84 00:06:20,560 --> 00:06:29,740 Lo lanzo, y de nuevo si todo va bien, aquí me lanzará a consola hola, igual que antes, 85 00:06:29,740 --> 00:06:33,220 pero si nos fijamos la cadencia como la hace, efectivamente la está lanzando una vez cada 86 00:06:33,220 --> 00:06:34,220 segundo. 87 00:06:34,220 --> 00:06:35,399 Bien, nos vamos acercando. 88 00:06:35,399 --> 00:06:37,379 Así que nada, ahora es echar la imaginación. 89 00:06:37,379 --> 00:06:42,000 Voy a crear un contador, ya sabemos cómo, voy a crear una corrutina que se ejecute cada 90 00:06:42,000 --> 00:06:47,240 segundo, y lo que voy a hacer es que ese texto que mandaba la pantalla en cada vez, en cada 91 00:06:47,240 --> 00:06:48,620 ciclo pues lo voy a cambiar. 92 00:06:48,620 --> 00:06:49,620 ¿Por qué? 93 00:06:49,620 --> 00:06:50,620 Por un número. 94 00:06:50,620 --> 00:06:55,079 cero y voy a seguir avanzando. Así que, ¿cómo hacíamos bucles en los que un valor va cambiando? 95 00:06:55,660 --> 00:07:01,319 Pues con el bucle for. Aquí, en vez de un while, voy a borrarlo para hacerlo de cero 96 00:07:01,319 --> 00:07:05,139 y así le vamos cogiendo el tranquillo. De hecho, voy a borrar la función de update 97 00:07:05,139 --> 00:07:09,800 porque ya no la necesito. De hecho, las corrutinas pueden sustituir a update si lo necesitamos. 98 00:07:10,360 --> 00:07:14,920 Pues bien, voy a crear un bucle for creando una variable llamada n de número entero, 99 00:07:15,800 --> 00:07:19,740 cuyo valor inicial es cero. Le doy una condición, es decir, mientras n sea menor o igual que 100 00:07:19,740 --> 00:07:29,600 100, por ejemplo, pues súmale 1 a n. ¿Y qué es lo que hago? Mandar al texto, como 101 00:07:29,600 --> 00:07:35,699 hemos visto antes, un nuevo texto, que va a ser contador, dos puntos, y a continuación 102 00:07:35,699 --> 00:07:41,459 ahora sí, n. Y muy importante recordar, por eso me está aquí dando error, le tengo que 103 00:07:41,459 --> 00:07:49,480 decir a mi corrutina cada cuánto tiempo se tiene que ejecutar. La sintaxis es con yel 104 00:07:49,480 --> 00:07:51,040 return, y en este caso le voy a decir 105 00:07:51,040 --> 00:07:53,240 new waitForSeconds 106 00:07:53,240 --> 00:07:55,540 y lo he dicho. 107 00:07:57,959 --> 00:07:58,680 Un segundo. 108 00:07:59,379 --> 00:08:00,120 ¿Qué tenemos ahora mismo? 109 00:08:01,879 --> 00:08:02,579 Un contador. 110 00:08:03,420 --> 00:08:03,899 Ahí lo tenéis. 111 00:08:05,139 --> 00:08:07,199 Ya está. Así de sencillo. 112 00:08:08,360 --> 00:08:09,300 Tengo que decir que 113 00:08:09,300 --> 00:08:11,339 existe, igual que podemos 114 00:08:11,339 --> 00:08:12,879 lanzar un contador, podemos, o sea, igual que 115 00:08:12,879 --> 00:08:15,300 lanzamos una corrutina con el startCorroutine, también la podemos 116 00:08:15,300 --> 00:08:17,240 parar. Es decir, si ya llega un momento en el que tenemos que detener 117 00:08:17,240 --> 00:08:19,139 esa ejecución, pues 118 00:08:19,139 --> 00:08:20,819 la podemos parar mediante stopCodeRoutine. 119 00:08:21,680 --> 00:08:22,019 De hecho, 120 00:08:23,180 --> 00:08:24,879 voy a hacer una cosa, por si alguien no lo sabe. 121 00:08:25,360 --> 00:08:27,199 Aquí le he dicho un bucle for en el que le he dicho 122 00:08:27,199 --> 00:08:29,379 que mientras n sea menor o igual que 100. 123 00:08:29,480 --> 00:08:30,759 Pero ¿y si yo no quiero que pare nunca? 124 00:08:31,319 --> 00:08:32,419 Podéis borrar esta condición. 125 00:08:32,799 --> 00:08:35,279 Ponéis lo que hay entre los puntos y coma vacío 126 00:08:35,279 --> 00:08:37,039 y entonces no le estamos dando una condición. 127 00:08:37,279 --> 00:08:38,799 Se va a estar ejecutando de forma permanente. 128 00:08:39,220 --> 00:08:40,179 ¿Ok? Y similar al while. 129 00:08:40,879 --> 00:08:43,039 Pero lo que decía, ¿y si yo quiero parar 130 00:08:43,039 --> 00:08:44,019 en un momento dado la corrutina? 131 00:08:45,039 --> 00:08:46,659 Pues bien, en este bucle que acabo de crear 132 00:08:46,659 --> 00:08:49,080 yo puedo directamente decirle, oye, si n 133 00:08:49,080 --> 00:08:52,100 es igual a 10 134 00:08:52,100 --> 00:08:54,360 pues vamos a ser más precisos 135 00:08:54,360 --> 00:08:55,620 si es mayor o igual que 10 136 00:08:55,620 --> 00:08:59,090 para la corrutina 137 00:08:59,090 --> 00:09:01,590 con el comando 138 00:09:01,590 --> 00:09:02,990 stop corrutin 139 00:09:02,990 --> 00:09:03,970 igual que el start 140 00:09:03,970 --> 00:09:04,490 pasándole 141 00:09:04,490 --> 00:09:07,850 el nombre de la corrutina 142 00:09:07,850 --> 00:09:08,669 ahora mismo 143 00:09:08,669 --> 00:09:09,289 lo que acabo de hacer 144 00:09:09,289 --> 00:09:10,049 es lo mismo que he hecho antes 145 00:09:10,049 --> 00:09:11,129 un contador que empieza en 0 146 00:09:11,129 --> 00:09:11,690 y va avanzando 147 00:09:11,690 --> 00:09:13,350 y que avanza cada segundo 148 00:09:13,350 --> 00:09:15,889 pero el mismo 149 00:09:15,889 --> 00:09:16,610 cuando llegue a 10 150 00:09:16,610 --> 00:09:17,850 detendrá esa corrutina 151 00:09:17,850 --> 00:09:18,610 es decir 152 00:09:18,610 --> 00:09:19,330 detendrá ese ciclo 153 00:09:19,330 --> 00:09:20,169 vamos a comprobarlo 154 00:09:20,169 --> 00:09:21,769 9 155 00:09:21,769 --> 00:09:22,710 y 10 156 00:09:22,710 --> 00:09:25,990 bien, vale, cosas de la precisión 157 00:09:25,990 --> 00:09:26,769 ¿por qué ha ocurrido esto? 158 00:09:27,450 --> 00:09:29,370 porque este if lo he puesto aquí 159 00:09:29,370 --> 00:09:31,830 y si lo hubiese puesto 160 00:09:31,830 --> 00:09:33,169 justo antes de esto 161 00:09:33,169 --> 00:09:34,789 pues habría llegado hasta 10, no hasta 11 162 00:09:34,789 --> 00:09:36,649 pero bueno, cosas que vamos viendo 163 00:09:36,649 --> 00:09:37,929 pequeños bugs que van saliendo 164 00:09:37,929 --> 00:09:41,029 vayamos un paso más allá 165 00:09:41,029 --> 00:09:43,230 pulamos nuestras corrutinas 166 00:09:43,230 --> 00:09:45,289 ¿y si el parámetro que determina 167 00:09:45,289 --> 00:09:47,669 cuando se ejecuta es una variable? 168 00:09:48,250 --> 00:09:49,149 imaginemos, no sé 169 00:09:49,149 --> 00:09:51,110 que estoy lanzando elementos 170 00:09:51,110 --> 00:09:53,049 a mi escena, por ejemplo prefabs 171 00:09:53,049 --> 00:09:54,230 instanciando prefabs 172 00:09:54,230 --> 00:09:56,990 y los voy a lanzar pues cada X tiempo 173 00:09:56,990 --> 00:09:58,970 pero ese X tiempo no es fijo 174 00:09:58,970 --> 00:10:01,090 sino que viene determinado 175 00:10:01,090 --> 00:10:03,289 por otros parámetros, el nivel en el que estoy 176 00:10:03,289 --> 00:10:05,570 la velocidad a la que me muevo 177 00:10:05,570 --> 00:10:07,330 la energía de la que 178 00:10:07,330 --> 00:10:08,669 dispongo, en fin, una variable 179 00:10:08,669 --> 00:10:09,970 ¿podemos hacer eso? 180 00:10:10,490 --> 00:10:12,950 como siempre que se hace una pregunta en programación 181 00:10:12,950 --> 00:10:14,090 sí, se puede hacer 182 00:10:14,090 --> 00:10:19,110 vamos a ver cómo, voy a borrar esto 183 00:10:19,110 --> 00:10:21,110 ¿de acuerdo? porque ahora lo que me interesa 184 00:10:21,110 --> 00:10:23,389 es que este parámetro que ahora mismo 185 00:10:23,389 --> 00:10:25,009 lo he dado fijo, sea ahora una variable. 186 00:10:25,370 --> 00:10:27,129 Así que antes que nada voy a crear aquí una variable 187 00:10:27,129 --> 00:10:29,210 de tipo serialize, para así poder acceder a ella 188 00:10:29,210 --> 00:10:31,350 desde la 189 00:10:31,350 --> 00:10:33,250 interfaz de Unity. Le voy a llamar speed 190 00:10:33,250 --> 00:10:35,429 a la velocidad a la que se mueve. 191 00:10:36,090 --> 00:10:37,250 Y entonces, donde antes 192 00:10:37,250 --> 00:10:39,090 decía que se ejecutase cada segundo, 193 00:10:39,250 --> 00:10:40,769 le voy a poner aquí speed. 194 00:10:41,769 --> 00:10:43,409 Eso significa que ahora mi contador 195 00:10:43,409 --> 00:10:46,759 voy a parar la ejecución 196 00:10:46,759 --> 00:10:48,240 ahora mi contador depende 197 00:10:48,240 --> 00:10:50,580 de esta variable que tengo aquí a disposición. 198 00:10:51,179 --> 00:10:52,039 De hecho, ahora mismo, si lanzo 199 00:10:52,039 --> 00:10:54,740 la corrutina, como esa variable vale 0 200 00:10:54,740 --> 00:10:56,039 pues 201 00:10:56,039 --> 00:10:59,240 se ejecuta cada fotograma 202 00:10:59,240 --> 00:11:00,720 vale 203 00:11:00,720 --> 00:11:02,639 es como si le hubiese dado un return 204 00:11:02,639 --> 00:11:03,759 como hemos dicho antes 205 00:11:03,759 --> 00:11:06,460 pero si le doy un valor de 1 206 00:11:06,460 --> 00:11:09,220 ahora mismo si lo ejecuto 207 00:11:09,220 --> 00:11:12,110 vemos que la corrutina 208 00:11:12,110 --> 00:11:13,309 se ejecuta cada segundo 209 00:11:13,309 --> 00:11:14,830 pero no solo eso, sino que además 210 00:11:14,830 --> 00:11:17,710 mientras dure la ejecución voy a modificar el parámetro 211 00:11:17,710 --> 00:11:18,929 de la velocidad 212 00:11:18,929 --> 00:11:21,009 le voy a decir que se ejecute cada medio segundo 213 00:11:21,009 --> 00:11:21,669 ahí está 214 00:11:21,669 --> 00:11:24,029 o cada décima de segundo 215 00:11:24,029 --> 00:11:25,289 ahí está 216 00:11:25,289 --> 00:11:26,850 o cada dos segundos 217 00:11:26,850 --> 00:11:31,019 y ahora mi contador se ejecuta 218 00:11:31,019 --> 00:11:31,659 cada segundo 219 00:11:31,659 --> 00:11:32,340 cada dos segundos