No estoy seguro si todavía estás leyendo esto, pero he luchado con este tipo de problema durante mucho tiempo.
He diseñado numerosos tipos diferentes de sistemas de afecto. Los revisaré brevemente ahora. Todo esto se basa en mi experiencia. No pretendo saber todas las respuestas.
Modificadores estáticos
Este tipo de sistema se basa principalmente en enteros simples para determinar cualquier modificación. Por ejemplo, +100 a Max HP, +10 a atacar y así sucesivamente. Este sistema también podría manejar porcentajes también. Solo necesita asegurarse de que el apilamiento no se salga de control.
Realmente nunca almacené en caché los valores generados para este tipo de sistema. Por ejemplo, si quisiera mostrar la salud máxima de algo, generaría el valor en el acto. Esto evitó que las cosas fueran propensas a errores y simplemente más fácil de entender para todos los involucrados.
(Trabajo en Java, por lo que lo que sigue está basado en Java, pero debería funcionar con algunas modificaciones para otros idiomas). Este sistema se puede hacer fácilmente usando enumeraciones para los tipos de modificación, y luego enteros. El resultado final se puede colocar en algún tipo de colección que tenga pares ordenados de clave y valor. Esto será una búsqueda rápida y cálculos, por lo que el rendimiento es muy bueno.
En general, funciona muy bien con solo modificadores estáticos. Sin embargo, el código debe existir en los lugares adecuados para que se usen los modificadores: getAttack, getMaxHP, getMeleeDamage, y así sucesivamente.
Donde este método falla (para mí) es una interacción muy compleja entre aficionados. No hay una manera realmente fácil de interactuar, excepto por un poco de gueto. Tiene algunas posibilidades simples de interacción. Para hacerlo, debe realizar una modificación en la forma en que almacena los modificadores estáticos. En lugar de utilizar una enumeración como clave, utiliza una cadena. Esta cadena sería el nombre Enum + variable adicional. 9 de cada 10 veces, la variable adicional no se utiliza, por lo que aún conserva el nombre de enumeración como clave.
Hagamos un ejemplo rápido: si quisiera poder modificar el daño contra criaturas no muertas, podría tener un par ordenado como este: (DAMAGE_Undead, 10) El DAÑO es la enumeración y los no muertos es la variable adicional. Entonces, durante tu combate, puedes hacer algo como:
dam += attacker.getMod(Mod.DAMAGE + npc.getRaceFamily()); //in this case the race family would be undead
De todos modos, funciona bastante bien y es rápido. Pero falla en interacciones complejas y tener código "especial" en todas partes. Por ejemplo, considere la situación de "25% de posibilidades de teletransportarse en caso de muerte". Este es uno "bastante" complejo. El sistema anterior puede manejarlo, pero no fácilmente, ya que necesita lo siguiente:
- Determina si el jugador tiene este mod.
- En algún lugar, tenga algún código para ejecutar la teletransportación, si tiene éxito. ¡La ubicación de este código es una discusión en sí misma!
- Obtenga los datos correctos del mapa Mod. ¿Qué significa el valor? ¿Es la habitación donde se teletransportan también? ¿Qué pasa si un jugador tiene dos modos de teletransporte? ¿¿No se sumarán las cantidades juntas ?????? ¡FRACASO!
Entonces esto me lleva a la siguiente:
El último sistema de mejora compleja
Una vez intenté escribir un MMORPG 2D solo. ¡Fue un error terrible, pero aprendí mucho!
Reescribí el sistema de afecto 3 veces. El primero utilizó una variación menos poderosa de lo anterior. El segundo fue de lo que voy a hablar.
Este sistema tenía una serie de clases para cada modificación, por lo que cosas como: ChangeHP, ChangeMaxHP, ChangeHPByPercent, ChangeMaxByPercent. Tenía un millón de estos tipos, incluso cosas como TeleportOnDeath.
Mis clases tenían cosas que harían lo siguiente:
- applyAffect
- removeAffect
- checkForInteraction <--- importante
Aplicar y eliminar explicarse a sí mismos (aunque para cosas como porcentajes, el efecto mantendría un registro de cuánto aumentó el HP para garantizar que cuando el efecto desapareciera, solo eliminaría la cantidad que agregó. Esto fue buggy, lol y Me llevó mucho tiempo asegurarme de que era correcto. Todavía no tenía un buen presentimiento al respecto).
El método checkForInteraction fue un código horrendísimo complejo. En cada una de las clases de afectos (es decir: ChangeHP), tendría un código para determinar si esto debería ser modificado por el afecto de entrada. Entonces, por ejemplo, si tuvieras algo como ...
- Buff 1: inflige 10 de daño de Fuego en el ataque
- Buff 2: aumenta todo el daño de fuego en un 25%.
- Buff 3: aumenta todo el daño de fuego en 15.
El método checkForInteraction manejaría todos estos efectos. ¡Para hacer esto, cada efecto en TODOS los jugadores cercanos tenía que ser verificado! Esto se debe a la clase de afectos que tuve con varios jugadores en un área. Esto significa que el código NUNCA TENÍA ninguna declaración especial como la anterior: "si acabamos de morir, debemos verificar el teletransporte en caso de muerte". Este sistema lo manejaría automáticamente correctamente en el momento adecuado.
Intentar escribir este sistema me tomó como 2 meses y explotó varias veces por la cabeza. SIN EMBARGO, era REALMENTE poderoso y podía hacer una cantidad increíble de cosas, especialmente cuando se tienen en cuenta los siguientes dos hechos para las habilidades en mi juego: 1. Tenían rangos objetivo (es decir, solo, auto, solo grupo, PB AE auto , PB AE objetivo, AE objetivo, etc.). 2. Las habilidades podrían tener más de 1 efecto sobre ellas.
Como mencioné anteriormente, este fue el segundo sistema de afecto tercero para este juego. ¿Por qué me alejé de esto?
¡Este sistema tuvo el peor rendimiento que he visto!Fue muy lento, ya que tenía que hacer muchas comprobaciones para cada cosa que sucedía. Traté de mejorarlo, pero lo consideré un fracaso.
Entonces llegamos a mi tercera versión (y otro tipo de sistema de mejora):
Clase de afecto complejo con manejadores
Así que esto es más o menos una combinación de los dos primeros: podemos tener variables estáticas en una clase de Afecto que contiene mucha funcionalidad y datos adicionales. Luego solo llame a los controladores (para mí, más o menos algunos métodos de utilidad estáticos en lugar de subclases para acciones específicas. Pero estoy seguro de que podría ir con subclases para acciones si también lo desea) cuando queremos hacer algo.
La clase Affect tendría todas las cosas buenas y jugosas, como los tipos de objetivos, la duración, el número de usos, la posibilidad de ejecutar, etc.
Todavía tendríamos que agregar códigos especiales para manejar las situaciones, por ejemplo, teletransportarse en caso de muerte. Todavía tendríamos que verificar esto manualmente en el código de combate, y luego, si existiera, obtendríamos una lista de afectos. Esta lista de efectos contiene todos los efectos aplicados actualmente en el jugador que se ocupó de teletransportarse al morir. Luego solo miraríamos cada uno y verificaríamos si se ejecutó y tuvo éxito (Nos detendríamos en el primero). Si fue exitoso, simplemente llamaríamos al manejador para encargarse de esto.
La interacción se puede hacer, si quieres también. Solo tendría que escribir el código para buscar beneficios específicos en los jugadores / etc. Debido a que tiene un buen rendimiento (ver más abajo), debería ser bastante eficiente hacerlo. Simplemente necesitaría controladores más complejos, etc.
Por lo tanto, tiene mucho rendimiento del primer sistema y aún mucha complejidad como el segundo (pero no tanto). Al menos en Java, puede hacer algunas cosas difíciles para obtener el rendimiento de casi el primero en la MAYORÍA de los casos (es decir, tener un mapa de enumeración ( http://docs.oracle.com/javase/6/docs/api/java /util/EnumMap.html ) con Enums como las claves y ArrayList de los afectos como los valores. Esto le permite ver si tiene efectos rápidamente [ya que la lista sería 0 o el mapa no tendría la enumeración] y no tener iterar continuamente sobre las listas de afectos del jugador sin ninguna razón. No me importa iterar sobre los afectos si los necesitamos en este momento. Lo optimizaré más adelante si se convierte en un problema).
Actualmente estoy volviendo a abrir (reescribiendo el juego en Java en lugar de la base de código FastROM en la que estaba originalmente) mi MUD que terminó en 2005 y recientemente me he encontrado con ¿cómo quiero implementar mi sistema de mejora? Voy a usar este sistema porque funcionó muy bien en mi juego fallido anterior.
Bueno, espero que alguien, en algún lugar, encuentre algunas de estas ideas útiles.