Estoy tratando de escribir un breve "juego" en el que un jugador da vueltas y lucha contra monstruos, pero no tengo idea de cómo manejar el combate.
Por ejemplo, digamos que tengo un "Guerrero" y un "Troll". ¿Cómo se pelean los dos? Sé que puedo hacer algo como
Conan = Warrior.new();
CaveTroll = Troll.new();
Conan.attack(CaveTroll);
CaveTroll.attack(Conan);
Pero, ¿qué parte del juego controla al monstruo? ¿Acabo de pegar la secuencia anterior en un bucle hasta que uno de ellos muere? ¿O el "motor" del juego debe tener una parte que se ocupe específicamente del combate? ¿O es este un aspecto de la inteligencia artificial del Troll que necesita ocuparse de sus acciones?
Además, ¿quién / qué determina las acciones que toma el monstruo? Tal vez un Troll puede golpear, patear, morder, lanzar hechizos, beber pociones, usar un objeto mágico. ¿El motor del juego determina qué acción toma el Troll o es algo que la clase Troll maneja?
Lo siento, no puedo ser más específico, pero necesito alguna orientación sobre qué dirección tomar con esto.
Respuestas:
Me imagino una secuencia de batalla como minijuego dentro de tu juego. Los ticks de actualización (o ticks de giro) se dirigen a un componente que maneja estos eventos. Este enfoque encapsula la lógica de la secuencia de batalla en una clase separada, dejando libre el bucle principal del juego para la transición entre los estados del juego.
La clase de secuencia de batalla se vería así:
Tu Troll y Guerrero ambos heredan de una superclase común llamada Entidad. Dentro de HandleTurn, la entidad atacante puede moverse. Esto es equivalente a una rutina de inteligencia artificial.
El método de lucha decide lo que la entidad va a hacer. Tenga en cuenta que esto no necesita involucrar a la entidad opuesta, como beber una poción o huir.
Actualización: para admitir varios monstruos y un grupo de jugadores, presentas una clase grupal:
La clase de grupo reemplazará todas las ocurrencias de la entidad en la clase BattleSequence. La selección y el ataque serán manejados por la propia clase Entidad, por lo que la IA puede tener en cuenta a todo el grupo al seleccionar el mejor curso de acción.
fuente
Tendría un objeto de combate dedicado que gestiona el combate. Encapsularía el estado de combate completo, incluyendo cosas como la lista de personajes de jugadores, la lista de enemigos, el turno actual, el terreno de batalla, etc. El combate puede tener un método de actualización que gestiona la lógica de la batalla. No es una buena idea poner el código de combate en un bucle simple, porque terminaría muy rápido. Normalmente tendrías algo de tiempo y diferentes etapas de batalla.
Para las acciones tomadas, ciertamente puedes hacerlo aleatorio, pero no tendría mucho sentido que un monstruo con HP completo lanzara un hechizo de curación. Vale la pena tener una lógica básica para determinar qué acción tomar. Por ejemplo, algunas acciones podrían tener más prioridad que otras (p. Ej., El troll patea el 30% del tiempo), así como otras condiciones para hacer que las batallas sean más interesantes (p. Ej., Cuando el troll HP es inferior al 10% del HP completo, hay un 20% posibilidad de lanzar un hechizo de curación, de lo contrario, la probabilidad es del 1%). Esto podría ser tan complejo como quieras.
Creo que la clase de monstruos debería manejar la selección de qué acción hacer, el objeto de batalla le pide al monstruo una acción y el monstruo toma una decisión y luego procede a aplicarla. Una idea es tener un objeto de estrategia que se conecte a los monstruos y que seleccione de la lista de posibles acciones de monstruos en función de las prioridades, categorías y condiciones asignadas a cada acción de batalla. Entonces puede tener una clase de estrategia ofensiva, por ejemplo, que prioriza los ataques sobre las habilidades defensivas, y otra estrategia cautelosa que es más probable que sane. Un jefe puede cambiar dinámicamente la estrategia en función de su condición actual.
Una última cosa. Es posible que desee que tanto los personajes jugadores como los monstruos hereden de la misma clase, sean instancias de la misma clase (actor o combatiente, por ejemplo) o comparta un objeto común que encapsule la funcionalidad común. Esto reduce la duplicación de código y también te permitiría tener NPC controlados por la IA de tu lado que pueden implementar las mismas estrategias que ya codificaste para los monstruos.
fuente
Sí, debes tener una parte especial en tu motor que maneje el combate.
No sé exactamente cómo estás haciendo tu combate, pero asumiré que los jugadores deambulan por el mundo del juego, se encuentran con monstruos y la batalla se desarrolla en tiempo real. Si es así, el troll necesita conocer los alrededores dentro de un área determinada, tal vez definir qué tan lejos puede ver algo delante de él (el troll maneja esto).
Sobre la IA, creo que el motor necesita manejarlo por sí mismo, así que digamos que tienes más de un tipo de enemigo que puede hacer lo mismo (mordisco), ¡puedes asignar la IA a otro monstruo y listo!
fuente
Su jugador y su troll no son más que conjuntos de datos, lo que llamamos el Modelo de datos que describe su mundo. Vida, inventario, capacidades de ataque, incluso su conocimiento del mundo, todo consiste en el modelo de datos.
Mantenga un único objeto Modelo principal que contenga todos los datos que describan su mundo. Contendrá información general del mundo, como dificultad, parámetros físicos, etc. También contendrá una lista / matriz de datos de entidades específicas como he descrito anteriormente. Este modelo principal puede consistir en muchos subobjetos para describir su mundo. En ninguna parte de su modelo debería tener alguna función que controle la lógica del juego o la lógica de visualización; los captadores son la única excepción, y se usarían solo para permitirle obtener datos del modelo con mayor facilidad (si los miembros públicos aún no hacen el truco).
A continuación, cree funciones en una o más clases de "controlador"; puede escribirlos todos como funciones auxiliares en su clase principal, aunque esto puede aumentar un poco después de un tiempo. Se llamará a cada actualización para actuar sobre los datos de las entidades para diferentes propósitos (movimiento, ataque, etc.). Mantener estas funciones fuera de una clase de entidad es más eficiente en cuanto a recursos, y una vez que sepa qué describe su entidad, sabrá automáticamente qué funciones deben actuar sobre ella.
Una nota final es que también es útil mantener su lógica de visualización separada de la lógica de su juego. La lógica de visualización sería: "¿Dónde dibujo esto en la pantalla y de qué color?" vs. la lógica del juego es lo que describí en el pseudcode anterior.
(Nota de Dev: Al usar clases, esto sigue un enfoque de programación funcional que considera todos los métodos como idealmente sin estado, lo que permite un modelo de datos limpio y un enfoque de procesamiento que minimiza los errores causados por el estado retenido. FP es el MVC definitivo, ya que logra MVC objetivo de separación de preocupaciones explícitamente. Ver esta pregunta .)
fuente