Separar lógica y datos en el juego de navegador

8

He estado pensando esto durante días y todavía no estoy seguro de qué hacer. Estoy tratando de refactorizar un sistema de combate en PHP (... lo siento). Esto es lo que existe hasta ahora:

  • Hay dos (hasta ahora) tipos de entidades que pueden participar en el combate. Vamos a llamarlos jugadores y NPC. Sus datos ya están escritos bastante bien.
  • Cuando participan en el combate, estas entidades se envuelven con otro objeto en el DB llamado a Combatant, que les da información sobre la lucha en particular. Pueden participar en múltiples combates a la vez.
  • Estoy tratando de escribir el motor lógico para el combate inyectando combatientes en él.
  • Quiero poder burlarme de todo para las pruebas.

Para separar la lógica y los datos, quiero tener dos interfaces / clases base, una siendo ICombatantDatay la otra ICombatantLogic. Los dos implementadores de datos serán uno para los objetos reales almacenados en la base de datos y el otro para mis objetos simulados.

Ahora me encuentro con incertidumbres con el diseño del lado lógico de las cosas. Puedo tener un implementador para cada jugador y NPC, pero tengo un problema. Un combatiente necesita poder devolver la entidad que envuelve. ¿Debería este método getter ser parte de la lógica o los datos? Creo firmemente que debería estar en los datos, porque la parte lógica se usa para ejecutar el combate, y no estará disponible si alguien solo está buscando información sobre una próxima pelea. Pero las clases de datos solo separan el simulacro de DB, no el jugador de NPC. Si trato de tener dos clases secundarias del implementador de datos DB, una para cada tipo de entidad, ¿cómo puedo diseñar eso mientras mantengo mis simulaciones en el bucle? ¿Necesito una tercera interfaz como IEntityProvideresa que inserto en las clases de datos?

Además, con algunas de las ideas que he estado considerando, siento que tendré que poner controles en su lugar para asegurarme de que no coincidan las cosas, como hacer que la lógica de un NPC envuelva accidentalmente los datos de un jugador. ¿Eso tiene algún sentido? ¿Es esa una situación que incluso sería posible si la arquitectura es correcta, o el diseño correcto lo prohibiría por completo para que no necesite verificarlo?

Si alguien pudiera ayudarme a diseñar un diagrama de clase o algo para esto, me ayudaría mucho. Gracias.

editar

También es útil tener en cuenta que la clase de datos simulados realmente no necesita Entity, ya que solo especificaré todos los parámetros como estadísticas de combate directamente. Entonces, tal vez eso afecte el diseño correcto.

Tesserex
fuente
Mi suposición es Combatant.entityque no se usa durante el combate y, por lo tanto, no debería existir. ¿Quizás necesites otra clase como la EntityVsEntityCombatque envuelve la lógica de combate, contiene Entity <--> Combatantmapeos y actualiza Entityestados una vez que el combate ha terminado? Tal vez algo más de información sobre su arquitectura actual podría ayudar.
Torious el

Respuestas:

1

Parte de la forma en que he abordado esto en el pasado es, en lugar de tener representaciones completamente separadas para los jugadores y los NPC, al tiempo que requiero que ambos implementen una interfaz común, conduciendo hacia la convergencia de la representación entre ellos en la mayor medida que pueda, como subclasificándolos de un Charactermodelo común en el que presiono tanto sobre ellos como tiene sentido generalizar. Esto ayuda a evitar problemas con la ejecución de operaciones de NPC en jugadores y similares al hacer que las operaciones sean más aplicables en general, ya que las representaciones tienen una tendencia menos natural a divergir que si fueran implementaciones completamente independientes. El apalancamiento básico del polimorfismo ayuda a manejar los casos que tienen que divergir (por ejemplo, si realizó suCombatantLogicresponsable de manejar lo que sucede cuando alguien muere, tendrías que hacer una verificación de tipo para asegurarte de usar la lógica correcta; así que no, haga que los jugadores y los NPC implementen die()métodos separados y apropiados ).

Estoy de acuerdo en que tu Entityes parte de los datos. Sin embargo, sobre la base de lo que estaba diciendo, en realidad tendería a eliminar o limitar el papel de usted CombatantDataa favor de que la lógica de combate extraiga valores directamente de Entity, quizás CombatantDatasolo almacenando valores calculados costosos y específicos de combate único. Sus maquetas de prueba estarían más orientadas a proporcionar Entitymodelos falsos que a poblarse CombatantData. (Habiendo CombatantDataduplicado mucha información del Entityme molesta de la misma manera que lo hace una base de datos desnormalizada. Sin embargo, si crees en la Ley de Demeter, que apasionadamente no, no querrás hacer las cosas como yo Estoy sugiriendo. Por supuesto, si crees en la Ley de Demeter, no estoy seguro de que tuCombatantDataincluso debería proporcionar acceso a la Entity.)

caos
fuente
CombatantData realmente no duplica los datos de la entidad, incluye el estado de la entidad en combate, como la salud actual y cualquier efecto de estado en ella.
Tesserex
@Tesserex: Ah, está bien. Si ese estado no persiste entre combates, entonces eso es sensato. Ignora esa parte, entonces. :) ¿Tiene sentido el resto de lo que digo?
caos