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.
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?
fuente
Respuestas:
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.
fuente
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.
fuente
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.
fuente
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.
fuente