Soy un programador inexperto que crea un juego "parecido a un roguelike" en la línea de FTL , usando Python (no PyGame hasta ahora, ya que todavía solo me preocupa el texto).
Mi juego contendrá una gran cantidad de armas (alrededor de 50 para empezar) que producen habilidades únicas. Me cuesta entender cómo estructurar el código objeto de una manera que sea poderosa (en términos de permitir que las armas tengan efectos radicalmente diferentes) y extensible (para poder agregar más armas fácilmente más tarde, por ejemplo, colocándolas en una carpeta )
Mi primer instinto fue tener una clase BasicWeapon y tener diferentes armas heredadas de esa clase. Sin embargo, esto me parece problemático: o tengo que hacer que la clase BasicWeapon sea tan básica que es básicamente inútil (las únicas características que todas las armas tienen en común son el nombre y el tipo (pistola, hacha, etc.), o tengo que predecir cada efecto único que se me ocurrirá y codificaré en BasicWeapon.
Lo último es claramente imposible, pero lo primero todavía se puede trabajar. Sin embargo, eso me deja con la pregunta: ¿dónde pongo el código para armas individuales?
¿Creo plasmarifle.py, rocketlauncher.py, swarmofbees.py, etc., etc. y los dejo en una carpeta desde donde el juego puede importarlos?
¿O hay una manera de tener un archivo de estilo de base de datos (tal vez algo tan simple como una hoja de cálculo de Excel) que de alguna manera contiene un código único para cada arma, sin necesidad de recurrir a eval / exec?
En términos de la última solución (base de datos), creo que el problema fundamental con el que estoy luchando es que, si bien entiendo que es deseable mantener la separación entre el código y los datos, siento que las armas desdibujan la línea entre el "código" y "datos" un poco; representan la gran variedad de cosas similares que se pueden encontrar en el juego, en cuyo sentido son como datos, pero la mayoría de ellos requerirán al menos algún código único que no se comparta con ningún otro elemento, en ese sentido, naturalmente, código.
Una solución parcial que he encontrado en otra parte de este sitio sugiere dar a la clase BasicWeapon un montón de métodos vacíos: on_round_start (), on_attack (), on_move (), etc., y luego anular esos métodos para cada arma. En la fase relevante del ciclo de combate, el juego llamará al método apropiado para el arma de cada personaje, y solo aquellos que tengan métodos definidos realmente harán algo. Esto ayuda, pero aún no me dice dónde debo poner el código y / o los datos para cada arma.
¿Existe algún idioma o herramienta diferente que pueda usar como una especie de quimera de medio código y medio código? ¿Estoy matando por completo las buenas prácticas de programación?
Mi comprensión de OOP es incompleta en el mejor de los casos, por lo que agradecería las respuestas que no son demasiado informáticas.
EDITAR: Vaughan Hilts ha dejado claro en su publicación a continuación que de lo que estoy hablando esencialmente es de la programación basada en datos. La esencia de mi pregunta es esta: ¿cómo puedo implementar un diseño basado en datos de tal manera que los datos puedan contener secuencias de comandos, permitiendo que nuevas armas hagan cosas nuevas sin cambiar el código del programa principal?
fuente
Respuestas:
Desea un enfoque basado en datos casi con seguridad, a menos que su juego sea completamente inesperado y / o genere procedimientos para el núcleo.
Esencialmente, esto implica almacenar información sobre sus armas en un lenguaje de marcado o formato de archivo de su elección. XML y JSON son opciones buenas y legibles que se pueden usar para hacer que la edición sea bastante simple sin la necesidad de editores complicados si solo está tratando de comenzar rápidamente. (¡ Y Python también puede analizar XML bastante fácil! ) Establecería atributos como 'poder', 'defensa', 'costo' y 'estadísticas' que son todos relevantes. La forma en que estructura sus datos dependerá de usted.
Si un arma necesita agregar un efecto de estado, dele un nodo de efecto de estado y luego especifique los efectos de un efecto de estado a través de otro objeto controlado por datos. Esto hará que tu código dependa menos del juego específico y que la edición y prueba de tu juego sean triviales. No tener que recompilar todo el tiempo también es una ventaja.
La lectura suplementaria está disponible a continuación:
fuente
(Lamento enviar la respuesta en lugar de un comentario, pero aún no tengo representante).
La respuesta de Vaughan es genial, pero me gustaría agregar mis dos centavos.
Una de las razones principales por las que desearía usar XML o JSON y analizarlo en tiempo de ejecución es cambiar y experimentar con nuevos valores sin tener que volver a compilar el código. Como Python se interpreta y, en mi opinión, es bastante legible, podría tener los datos en bruto en un archivo con un diccionario y todo organizado:
De esta manera, solo importa el archivo / módulo y lo usa como un diccionario normal.
Si desea agregar scripts, puede utilizar la naturaleza dinámica de Python y las funciones de primera clase. Podrías hacer algo como esto:
Aunque creo que eso estaría en contra del diseño basado en datos. Para ser 100% DDD, tendría información (datos) que especificaría cuáles serían las funciones y el código que usaría un arma específica. De esta manera, no rompes DDD, ya que no mezclas datos con funcionalidad.
fuente
Diseño basado en datos
Envié algo como esta pregunta a la revisión de código recientemente.
Después de algunas sugerencias y mejoras, el resultado fue un código simple que permitiría cierta flexibilidad relativa en la creación de armas basada en un diccionario (o JSON). Los datos se interpretan en tiempo de ejecución y la
Weapon
clase misma realiza verificaciones simples , sin la necesidad de contar con un intérprete de script completo.El diseño basado en datos, a pesar de que Python es un lenguaje interpretado (tanto los archivos de origen como los de datos se pueden editar sin la necesidad de volver a compilarlos), parece ser lo correcto en casos como el que usted presentó. Esta pregunta entra en más detalles sobre el concepto, sus pros y sus contras. También hay una buena presentación sobre la Universidad de Cornell al respecto.
En comparación con otros lenguajes, como C ++, que probablemente usarían un lenguaje de secuencias de comandos (como LUA) para manejar la interacción de datos x el motor y las secuencias de comandos en general, y un cierto formato de datos (como XML) para almacenar los datos, Python realmente puede hacer todo por sí mismo (considerando el estándar
dict
pero tambiénweakref
, este último específicamente para la carga de recursos y el almacenamiento en caché).Sin embargo, un desarrollador independiente no puede llevar el enfoque basado en datos al extremo como se sugiere en este artículo :
Tal vez, con Python, uno podría beneficiarse de lo mejor del enfoque orientado a objetos y basado en datos, con el objetivo de la productividad y la extensibilidad.
Procesamiento simple de muestras
En el caso específico discutido en la revisión de código, un diccionario almacenaría tanto los "atributos estáticos" como la lógica a interpretar, en caso de que el arma tenga un comportamiento condicional.
En el ejemplo a continuación, una espada debe tener algunas habilidades y estadísticas en manos de los personajes de la clase 'antipaladin', y ningún efecto, con estadísticas más bajas cuando son utilizadas por otros personajes):
Para fines de prueba, creé simples
Player
yWeapon
clases: el primero en sostener / equipar el arma (llamando así a su configuración condicional on_equip) y el último como una sola clase que recuperaría los datos del diccionario, en función del nombre del elemento pasado como un argumento durante laWeapon
inicialización. No reflejan el diseño adecuado de las clases de juego, pero aún pueden ser útiles para probar los datos:Con alguna mejora futura, espero que esto me permita tener un sistema de fabricación dinámico algún día, procesando componentes de armas en lugar de armas enteras ...
Prueba
Me gusta esto:
Debería imprimir:
Para un bardo
Para un antipaladin
fuente