2011-08-28 18 views
7

He estado aprendiendo algo de lua para el desarrollo de juegos. Escuché sobre corutinas en otros idiomas, pero realmente surgió en lua. Simplemente no entiendo lo útiles que son, escuché mucho hablar de cómo puede ser una manera de hacer cosas de subprocesos múltiples, pero ¿no se ejecutan en orden? Entonces, ¿qué beneficio habría de las funciones normales que también funcionan en orden? Simplemente no entiendo qué tan diferentes son de las funciones, excepto que pueden pausar y dejar que otra se ejecute por un segundo. Parece que los escenarios de casos de uso no serían tan grandes para mí.¿Cuáles son los beneficios de corutinas?

¿Alguien quiere arrojar algo de luz sobre por qué alguien se beneficiaría de ellos?

Especialmente penetración de una perspectiva de programación de juegos sería bueno ^^

+0

Son del siglo pasado. La CPU multinúcleo y las demoras punitivas de juntar el caché de la CPU ponen fin a su utilidad. Los hilos son eso. –

+2

@ Hans Passant: Esto no entiende las corutinas. Las corutinas no son un reemplazo de los hilos y no los usa para lo mismo que usaría los hilos. El objetivo es escribir código limpio y cómodo (¡no simultáneo!) En el que una llamada a función puede pausarse, de modo que pueda regresar cuando tenga más información, sin bloquear el ciclo principal. No hay sobrecarga para hacer esto, como lo hace lua. Los hilos del sistema operativo serían un mal sustituto en ese caso de uso. –

Respuesta

0

Las usamos en un proyecto que estoy trabajando. El principal beneficio para nosotros es que a veces con el código asíncrono, hay puntos en los que es importante que ciertas partes se ejecuten en orden debido a algunas dependencias. Si usa coroutines, puede forzar a un proceso a esperar a que se complete otro proceso. No son la única forma de hacerlo, pero pueden ser mucho más simples que algunos otros métodos.

0

No entiendo qué tan diferentes son de las funciones excepto que pueden pausar y dejar que se ejecute por un segundo.

Esa es una propiedad bastante importante. Trabajé en un motor de juego que los usó para medir el tiempo. Por ejemplo, teníamos un motor que funcionaba a 10 tics por segundo, y podíamos WaitTicks (x) esperar x número de tics, y en la capa de usuario, podíamos ejecutar WaitFrames (x) para esperar x frames.

Incluso las bibliotecas de concurrencia nativas profesionales utilizan el mismo tipo de comportamiento flexible.

16

Bien, piense en términos de desarrollo de juegos.

Digamos que estás haciendo una escena o tal vez un tutorial. De cualquier manera, lo que tienes es una secuencia ordenada de comandos enviados a algunas entidades. Una entidad se mueve a un lugar, habla con un hombre y luego se va a otra parte. Etcétera. Algunos comandos no pueden comenzar hasta que otros hayan terminado.

Ahora mira cómo funciona tu juego. En cada cuadro, debe procesar AI, pruebas de colisión, animación, renderizado y sonido, posiblemente entre otras cosas. Solo puedes pensar cada cuadro. Entonces, ¿cómo pones este tipo de código, donde tienes que esperar a que se complete alguna acción antes de hacer la siguiente?

Si construiste un sistema en C++, lo que tendrías es algo que se ejecutó antes que la IA. Tendría una secuencia de comandos para procesar. Algunos de esos comandos serían instantáneos, como "dile a la entidad X que vaya aquí" o "genere la entidad Y aquí". Otros tendrían que esperar, como "decirle a la entidad Z que vaya aquí y no procese más comandos hasta que haya llegado aquí". El procesador de comandos debería llamarse en cada cuadro, y debería comprender condiciones complejas como "la entidad está en la ubicación", etc.

En Lua, que se vería así:

local entityX = game:GetEntity("entityX"); 
entityX:GoToLocation(locX); 
local entityY = game:SpawnEntity("entityY", locY); 
local entityZ = game:GetEntity("entityZ"); 
entityZ:GoToLocation(locZ); 
do 
    coroutine.yield(); 
until (entityZ:isAtLocation(locZ)); 
return; 

del tamaño C++, podría reanudar este script una vez por cuadro hasta que se haga. Una vez que regrese, sabrá que el cutscene ha terminado, por lo que puede devolver el control al usuario.

Mire qué tan simple es esa lógica de Lua. Hace exactamente lo que dice que hace. Es claro, obvio y, por lo tanto, es muy difícil equivocarse.

El poder de coroutines es poder realizar parcialmente alguna tarea, esperar a que se cumpla una condición, luego pasar a la siguiente tarea.

+0

Entonces, por ejemplo, puedo tener una función de carga que inicializa algunas variables y dice algunos detalles de la pantalla de carga, luego pasa el control a la función de dibujo que los dibuja y transfiere el control a la función de carga para terminar de cargar todo para mi juego. – Isaiah

+0

@Isaiah: Sí, podrías hacer eso. –

+2

Si desea un ejemplo de "vida real" de este patrón, mire aquí: http://getmoai.com/moai-platform-tutorials/moai-tutorials-bug-squisher.html – catwell

0

Muchos buenos ejemplos para los desarrolladores de juegos. Le daré otro en el espacio de extensión de la aplicación. Considere el escenario donde la aplicación tiene un motor que puede ejecutar las rutinas de un usuario en Lua mientras realiza la funcionalidad principal en C. Si el usuario necesita esperar a que el motor llegue a un estado específico (por ejemplo, esperar que se reciban los datos), usted tiene que:

  • multi-hilo del programa C para funcionar Lua en un hilo separado y añadir en bloqueo y sincronización métodos,
  • terminación anormal de la rutina Lua y vuelva a intentar desde el principio con un estado pasa a la función para omitir cualquier cosa, al menos vuelve a ejecutar un código que solo debe ejecutarse una vez o
  • cede la rutina de Lua y reiníciela una vez que se haya alcanzado el estado en C

La tercera opción es la más fácil de implementar, evitando la necesidad de manejar multi-threading en múltiples plataformas. También permite que el código del usuario se ejecute sin modificaciones, apareciendo como si la función que llamaron tomó mucho tiempo.

1

Corutinas en un juego: Fácil de usar, fácil de atornillar cuando se utiliza en muchos lugares.

Solo tenga cuidado y no lo use en muchos lugares. No haga que todo su código AI dependa de Coroutines.

Coroutines son buenos para hacer una solución rápida cuando se introduce un estado que no existía antes.

Esto es exactamente lo que hace java. Sleep() y Wait() Ambas funciones son la mejor manera de imposibilitar la depuración de su juego. Si yo fuera usted, evitaría por completo cualquier código que tenga que usar una función Wait() como lo hace una Coroutine.

OpenGL API es algo que debe tener en cuenta. Nunca utiliza una función wait() sino que utiliza una máquina de estado limpio que sabe exactamente en qué estado se encuentra el objeto. Si usa coroutines, termina con tantas piezas de código sin estado que seguramente será abrumador depurarlas.

Coroutines es bueno cuando se está haciendo una aplicación como el Editor de texto .. aplicación de banco ... servidor ... base de datos, etc. (no es un juego). Malo cuando estás haciendo un juego donde cualquier cosa puede suceder en cualquier punto del tiempo, necesitas tener estados.

Por lo tanto, en mi opinión corutinas son una mala forma de programación y una excusa para escribir pequeños códigos sin estado.

Pero así soy yo.

Cuestiones relacionadas