Así que estoy haciendo un juego donde puedes enviar barcos a lugares para vender o comprar recursos como madera, hierro, oro, etc.
Ahora me preguntaba cómo deberían crearse los recursos en el juego. Se me ocurrieron 2 opciones
Crea una clase para cada recurso:
public class ResourceBase { private int value; // other base properties } public class Gold : ResourceBase { public Gold { this.value = 40 // or whatever } }
Crear instancias de una clase de recurso
public class Resource { string name; int value; public Resource(string name, int value) { this.name = name; this.value = value; } } // later on... Resource gold = new Resource("Gold",40);
Con la segunda opción es posible llenar los recursos del juego desde un archivo resources.json, me gusta un poco esa estructura.
¡Nuevas ideas / patrones de diseño / estructuras son siempre bienvenidas!
EDITAR: es un poco como la aplicación complementaria de Assassins Creed Black Flag. Vea la barra de recursos en la imagen a continuación
EDIT 2: He investigado un poco más sobre "cargar elementos / recursos del archivo JSON" y encontré este blog: Poder de JSON en el desarrollo de juegos - Elementos . Muestra lo mejor de la opción 1 y la opción 2. Aún puede agregar funcionalidad a cada recurso :)
fuente
enum
en su lugar.Respuestas:
Vaya con el segundo enfoque, simplemente debido al hecho de que puede introducir nuevos tipos de recursos o elementos en cualquier momento sin tener que reescribir o actualizar el código ( desarrollo basado en datos ).
Editar:
Para elaborar un poco más sobre por qué esto es una buena práctica en general, incluso si está 100% seguro de que algún valor nunca cambiará.
Tomemos el ejemplo del juego de consola mencionado en los comentarios, porque proporciona una muy buena razón por la que no debe codificar nada, a menos que realmente tenga (o quiera), por ejemplo, claves de cifrado, su propio nombre, etc.
Cuando se lanza un juego en consolas, estos generalmente tienen que pasar por un proceso de revisión, donde el control de calidad del fabricante de la consola probará el juego, lo jugará, buscará problemas, etc. Esto es obligatorio y cuesta dinero, mucho dinero. Creo que una vez leí que un lanzamiento podría costar entre 30,000 y 50,000 dólares solo por la certificación.
Ahora imagine que está presionando su juego para su lanzamiento, pagando los $ 30,000 y espere. Y de repente te das cuenta de que algunos de los valores de tu juego están literalmente rotos. Digamos que puedes comprar barras de hierro por 50 de oro y venderlas por 55 de oro.
¿Qué haces? Si ha codificado esas cosas, tendrá que crear una nueva versión de actualización / lanzamiento, que tendrá que pasar por una revisión una vez más, ¡así que el peor de los casos pagará una vez más por la nueva certificación! Apuesto a que a Ubisoft no le importará, pero para tu propio bolsillo de desarrollador de juegos independientes ... ¡ay!
Pero imagine que el juego solo verificaría ocasionalmente las definiciones actualizadas del juego (por ejemplo, en forma de un archivo JSON). Tu juego podría descargar y usar la última versión en cualquier momento sin requerir una nueva actualización. Puede corregir ese desequilibrio / explotación / error en cualquier momento sin requerir una nueva certificación o cualquier otro dinero pagado. Solo una pequeña decisión de diseño, no creías que valiera la pena, ¡solo te ahorró una suma de dinero de 5 dígitos! ¿No es asombroso? :)
Solo no me malinterpretes. Esto también se aplica a otros tipos de software y plataformas. La descarga de archivos de datos actualizados es en general mucho más fácil y factible para el usuario estándar, sin importar si es un juego o algún tipo de aplicación / herramienta. Imagine un juego instalado bajo Archivos de programa en Windows. Su actualizador necesita derechos de administrador para modificar cualquier cosa y no puede modificar los programas en ejecución. Con DDD, su programa simplemente descarga los datos y los usa. Es posible que el jugador ni siquiera note que ha habido una actualización.
fuente
Una regla general es que use diferentes clases cuando los objetos requieren diferentes códigos e instancias de la misma clase cuando los objetos solo requieren diferentes valores.
Cuando los recursos tienen diferentes mecánicas de juego que son únicas para ellos, puede tener sentido representarlos con clases. Por ejemplo, cuando tienes Plutonio que tiene una vida media y conejos que procrean de acuerdo con la secuencia de Fibonacci , entonces podría tener sentido tener una clase base
Resource
con un métodoUpdate
implementado como no operativo y dos clases derivadasHalfLifeResource
ySelfGrowingResource
que anule ese método para disminuir / aumentar el valor (y tal vez también incluya lógica para controlar lo que sucede cuando almacena ambos uno al lado del otro).Pero cuando sus recursos son realmente solo números tontos, entonces no tiene sentido implementarlos con algo más elegante que una simple variable.
fuente
Me gustaría agregar que hay dos opciones adicionales:
Interfaz: puede considerar si la clase de recurso sería solo un "almacenamiento" para 5 enteros y cada entidad tendría lógica diferente con respecto a los recursos (por ejemplo, gasto / botín del jugador, producción de la ciudad recurso). En ese caso, es posible que no desee una clase en absoluto; simplemente quería exponer que una entidad tiene una variable con la que otras pueden interactuar:
Además, esto tiene la ventaja de que puedes saquear una ciudad con exactamente el mismo código que saquearías la flota enemiga, promoviendo la reutilización del código.
La desventaja es que implementar dicha interfaz puede resultar tedioso si muchas clases lo implementan, por lo que podría terminar usando interfaces pero no para el problema original, resolviéndolo con la opción 1 o 2:
Instancias (con enum): en algunos casos, sería deseable usar enum en lugar de cadena al definir el tipo de recurso:
esto proporcionará un poco de "seguridad", porque su IDE le dará una lista de todos los recursos válidos cuando lo asigne después de escribir el punto
ResourceType = Resource.
, además hay más "trucos" con enumeraciones que podría necesitar, como Tipo explícito o composición / banderas que puedo imaginar que sea útil al elaborar:En cuanto a lo que es mejor: no hay una bala de plata, pero personalmente me inclinaría por cualquier forma de casos, puede que no sean tan elegantes como la interfaz, pero son simples, no abarrotan el árbol de herencia y son ampliamente entendidos.
fuente
my-great-enum
) a alguna representación C # de la enumeración (MyGreatEnum
).Debe usar la opción 1, que tiene 3 ventajas:
new Gold(50)
resource instanceof Gold
fuente
Si sus recursos no tienen lógica de negocios propia, o escenarios de casos especiales con cómo interactúan con el entorno, otros recursos (además del comercio que ha cubierto) o el jugador, la opción dos hace que agregar nuevos sea muy fácil.
Si necesita considerar situaciones como lo que sucedería si combina dos recursos para la elaboración, si los recursos pueden tener propiedades muy diferentes (un balde de agua es muy diferente a un trozo de carbón) u otras interacciones económicas complejas, entonces el enfoque 1 es mucho más flexible para el motor, pero no para los datos.
fuente