¿Cómo implementar el comportamiento en una arquitectura de juego basada en componentes?

21

Estoy empezando a implementar IA de jugadores y enemigos en un juego, pero estoy confundido acerca de cómo implementar esto mejor en una arquitectura de juego basada en componentes.

Digamos que tengo un siguiente personaje jugador que puede ser estacionario, correr y balancear una espada. Un jugador puede transitar al estado de espada oscilante tanto desde el estado estacionario como el de carrera, pero luego debe completarse el swing antes de que el jugador pueda reanudar su posición de pie o correr. Durante el swing, el jugador no puede caminar.

Tal como lo veo, tengo dos enfoques de implementación:

  • Cree un solo componente AI que contenga toda la lógica del jugador (ya sea desacoplado del componente real o incrustado como un componente PlayerAIC). Puedo fácilmente cómo hacer cumplir las restricciones estatales sin crear un acoplamiento entre los componentes individuales que componen la entidad del jugador. Sin embargo, el componente AI no se puede dividir. Si tengo, por ejemplo, un enemigo que solo puede pararse y caminar o solo caminar y ocasionalmente balancear una espada, tengo que crear nuevos componentes de IA.
  • Divide el comportamiento en componentes, cada uno identificando un estado específico. Luego obtengo un StandComponent, WalkComponent y SwingComponent. Para hacer cumplir las reglas de transición, tengo que acoplar cada componente. SwingComponent debe deshabilitar StandComponent y WalkComponent durante la duración del swing. Cuando tengo un enemigo que solo está parado, balanceando una espada de vez en cuando, tengo que asegurarme de que SwingComponent solo desactive WalkComponent si está presente. Aunque esto permite mejores componentes de combinación y combinación, puede conducir a una pesadilla de mantenimiento, ya que cada vez que se agrega una dependencia, los componentes existentes deben actualizarse para jugar bien con los nuevos requisitos que la dependencia impone al personaje.

La situación ideal sería que un diseñador pueda construir nuevos enemigos / jugadores arrastrando componentes a un contenedor, sin tener que tocar una sola línea de motor o código de script. Aunque no estoy seguro de que se pueda evitar la codificación de scripts, quiero que sea lo más simple posible.

Resumiendo todo: ¿Debería unir toda la lógica AI en un componente o dividir cada estado lógico en componentes separados para crear variantes de entidad más fácilmente?

editar : sospecho que hay cierta confusión sobre lo que quise decir con la primera y segunda situación. He tratado de explicarlo en el siguiente diagrama.

Diagrama de componentes

Tenga en cuenta la relación entre los estados individuales y la entidad. En la primera situación, un componente de inteligencia artificial se construye previamente antes de colocarlo en la entidad. Un diseñador solo puede seleccionar entre un conjunto distinto de componentes AIC puestos a disposición por el programador. La segunda situación tiene los diferentes estados en el mismo nivel que otros componentes. Un diseñador ahora puede crear una entidad con IA única sin la interferencia de un programador.

La pregunta es, ¿son estas las dos únicas opciones para estructurar la IA en una entidad basada en componentes y, de ser así, qué daría la máxima flexibilidad?

fantasma
fuente
Creo que una buena respuesta dependerá de dónde quiera hacer cumplir la exclusividad de las acciones. Si desea que esté en los objetos mismos, el diseño sería muy diferente en comparación con decir, imponiéndolo a través de la interfaz de arrastrar y soltar (Este estado ya tiene una acción de movimiento, por lo que no puede tener otro, este contenedor de transición de estado ya contiene un estado final basado en el tiempo, etc. o lo que sea).
James
2 no es una opción viable.
Coyote

Respuestas:

6

Si tiene la intención de tener más enemigos o jugadores posibles que no puede imaginar en este momento, entonces definitivamente debe dividirlo. Lo que estás describiendo en tu segundo punto es básicamente el patrón de estado .

Creo que estoy de acuerdo con Gregory en que no deberías tener componentes separados de estado de pie y pie. Es solo un componente de movimiento con velocidad 0. Por otro lado, si tiene objetos que no se pueden mover, debe dividirlo o simplemente poner algún tipo de restricción booleana en el estado de movimiento que evita tener una velocidad distinta de cero .

Para el jugador, no creo que deba estar completamente separado. Todavía puede usar todos los demás componentes, con la adición de un componente de entrada. Este componente impulsa las transiciones entre estados, mientras que en el enemigo está controlado por una IA predeterminada, o si lo desea, diferentes subclases de IA que los diseñadores enemigos pueden elegir.

editar: en realidad, para tus enemigos estacionarios, en lugar de restringir el componente de movimiento, solo dales un componente de IA estacionario que nunca elija moverlos.

Tesserex
fuente
¿Un patrón de estado no implica la primera situación? Esto da como resultado que un solo componente AIC implemente una máquina de estados que contiene diferentes objetos de estado. Lo que quise decir con la segunda opción fue que WalkComponent y SwingComponent son del mismo tipo que, por ejemplo, RenderComponent y PhysicsComponent.
fantasma
@ghostonline En cuanto a la idea, más o menos. En la implementación, no realmente. AIComponent estaría separado, como en el segundo diagrama. No contendría los otros componentes. La pregunta más importante para su segunda situación es, si el diseñador solo elige componentes sin un programador, ¿cómo sabe la Entidad cuándo cambiar de estado? Diferentes estados implican diferentes transiciones de estado: alguien aún necesita especificarlos.
Tesserex
¿Te refieres a agregar un componente AIC a la entidad en el diagrama 2, que controlará el Componente Stand / Walk / Swing? Mi idea era que los componentes envían señales de bloqueo o activación bajo ciertas condiciones. Por ejemplo, SwingComponent emitiría señales genéricas, por ejemplo, señal "bound_feet" al iniciar y "release_feet" al finalizar el swing. WalkComponent se deshabilitaría y habilitaría en función de estas señales. Debido a que las 'transiciones de estado' están encapsuladas en los componentes mismos, el diseñador no necesitará un programador que conecte los componentes entre sí.
fantasma
@ghostonline Eso funciona bien para las cosas que tienen reglas fijas como "no se puede caminar mientras se balancea", pero ¿qué pasa con las transiciones entre estar de pie y caminar? Si el control está de pie, ¿cómo sabrá intentar caminar? La lógica de pie puede querer elegir caminar o columpiarse, lo que se ve afectado por la ausencia total de una habilidad para caminar; siempre debe elegir balancearse en ese caso. Pero sí creo que estás en el camino correcto.
Tesserex
2

Al menos mantendría Player AI (o lo que llamaría Player Controller) como su propio componente. Con la mayoría de los juegos, el jugador es fundamentalmente diferente de los NPC que no puedes generalizar de uno a otro, excepto en aspectos básicos como los puntos de vida.

Para los NPC, veo StandComponent y WalkComponent como aspectos de la misma cosa. ¿Alguna vez vas a tener un WalkComponent sin un StandComponent? Lo dudo. Del mismo modo, un RunComponent sería un WalkComponent con mayor velocidad y diferentes animaciones. Puedo ver el valor de tener un NPCMovementComponent y un NPCSwordFighterComponent separado, pero incluso eso me parece una ingeniería excesiva.

Gregory Avery-Weir
fuente
No separaría tanto el movimiento de la APN y el movimiento del jugador. Las acciones de movimiento que impulsan las animaciones y la física definitivamente podrían compartirse; es lo que selecciona las acciones o transiciones que es diferente (el jugador toma datos mientras AI es ... AI). Estoy de acuerdo en que tendrías un PlayerController, pero también tendrías un AIController, los cuales podrían usar Componentes de movimiento / Componentes de oscilación para realizar el trabajo de animación / física real.
homebrew
Cierto. Supongo que todos los objetos en movimiento tienen un Componente Físico o Componente de Movimiento que maneja su movimiento, y que el PlayerController y el AIController lo usarían para manejar el movimiento. El movimiento definitivamente debe ser un componente separado, ya que puede haber cosas que necesiten moverse que no tengan IA o que tengan la IA más simple posible (objetos de física tontos como cajas o basura).
Gregory Avery-Weir
2

Primero haría un componente de estado y luego crearía una máquina de estado para manejar las transiciones. Hazlo lo suficientemente genérico como para que puedas usarlo para tus jugadores y tu IA. Esto asegurará que la IA juegue con las mismas reglas y que no tenga que cambiar su lógica cuando cambie la forma en que funcionan los estados del jugador en comparación con los estados de la IA.

Máquina de estado finito C ++

Lo anterior tiene un ejemplo concreto de una máquina de estados en c ++ que puede ser utilizada tanto por jugadores como por IA.

Kyle C
fuente
1

Lo que quieres es un componente que maneje el movimiento de los personajes (jugador y NPC). El componente AI o un componente de jugador enviará comandos a este componente de movimiento y verificará si la acción puede iniciarse. Esto encapsulará sus restricciones de movimiento en un solo componente. Tu código de IA y el código de jugador no tienen que saber cómo se ejecuta Sword Sword. La IA tendría estados internos, por ejemplo, Inactivo, Atacar, Huir.

Stephen
fuente
1
TYPO: "Recibirá ..." ¿qué pasa con el componente AI?
Cachorro