He estado luchando con la forma de implementar secuencias de comandos en mi motor de juego. Solo tengo unos pocos requisitos: debe ser intuitivo, no quiero escribir un lenguaje, analizador e intérprete personalizados, y no quiero usar hilos. (Estoy seguro de que hay una solución más simple; no necesito la molestia de múltiples hilos de lógica de juego). Aquí hay un script de ejemplo, en Python (también conocido como pseudocódigo):
def dramatic_scene(actors):
alice = actors["alice"]
bob = actors["bob"]
alice.walk_to(bob)
if bob.can_see(alice):
bob.say("Hello again!")
else:
alice.say("Excuse me, Bob?")
Esa pieza épica de narración plantea problemas de implementación. No puedo evaluar todo el método a la vez, porque walk_to
lleva tiempo de juego. Si regresa de inmediato, Alice comenzaría a caminar hacia Bob y (en el mismo marco) saludaría (o sería saludada). Pero si walk_to
es una llamada de bloqueo que regresa cuando llega a Bob, entonces mi juego se atasca, porque está bloqueando el mismo hilo de ejecución que haría que Alice caminara.
Pensé en hacer que cada función pusiera en acción una acción: alice.walk_to(bob)
empujaría un objeto a una cola, que se despegaría después de que Alice llegara a Bob, donde sea que estuviera. Eso está más sutilmente roto: la if
rama se evalúa de inmediato, por lo que Bob podría saludar a Alice incluso si le da la espalda.
¿Cómo manejan otros motores / personas las secuencias de comandos sin crear hilos? Estoy empezando a buscar ideas en áreas que no sean de desarrollo de juegos, como las cadenas de animación jQuery. Parece que debería haber algunos buenos patrones para este tipo de problema.
Respuestas:
La forma en que algo como Panda hace esto es con devoluciones de llamada. En lugar de bloquearlo sería algo así como
Tener una devolución de llamada completa le permite encadenar este tipo de eventos tan profundamente como desee.
EDITAR: ejemplo de JavaScript ya que tiene una mejor sintaxis para este estilo:
fuente
El término que desea buscar aquí es " corutinas " (y generalmente la palabra clave del idioma o el nombre de la función es
yield
).La implementación dependerá en primer lugar de su idioma. Para un juego, desea que la implementación sea lo más liviana posible (más liviana que los hilos o incluso las fibras). La página de Wikipedia (vinculada) tiene algunos enlaces a varias implementaciones específicas del idioma.
Escuché que Lua tiene soporte incorporado para las corutinas. También GameMonkey.
UnrealScript implementa esto con lo que llama "estados" y "funciones latentes".
Si usa C #, podría mirar esta publicación de blog de Nick Gravelyn.
Además, la idea de "cadenas de animación", aunque no es lo mismo, es una solución viable para el mismo problema. Nick Gravelyn también tiene una implementación C # de esto .
fuente
yield return walk_to();
en su script.no ir enhebrado es inteligente.
La mayoría de los motores de juego funcionan como una serie de etapas modulares con cosas en la memoria que conducen cada etapa. Para su 'caminar al ejemplo', generalmente tiene una etapa de IA donde sus personajes caminados se encuentran en un estado en el que no deberían buscar enemigos para matar, una etapa de animación donde deberían ejecutar la animación X, una etapa de física (o etapa de simulación) donde se actualiza su posición real, etc.
en su ejemplo anterior, 'alice' es un actor compuesto por piezas que viven en muchas de estas etapas, por lo que un actor de bloqueo. walk_to call (o una rutina que llame next () una vez por cuadro) probablemente no tenga el contexto adecuado para tomar muchas decisiones
En cambio, una función 'start_walk_to' probablemente haría algo como:
Luego, su bucle principal ejecuta su tic ai, su tic de física, su tic de animación y su tic de escena, y la escena de corte actualiza el estado de cada uno de los subsistemas en su motor. El sistema de escena definitivamente debería rastrear lo que está haciendo cada una de sus escenas, y un sistema impulsado por la rutina para algo lineal y determinista como una escena custscene podría tener sentido.
La razón de esta modularidad es que solo mantiene las cosas agradables y simples, y para algunos sistemas (como la física y la inteligencia artificial), debe conocer el estado de todo al mismo tiempo para resolver las cosas correctamente y mantener el juego en un estado consistente .
¡espero que esto ayude!
fuente