Não tenho certeza se você ainda está lendo isso, mas luto com esse tipo de problema há muito tempo.
Eu projetei vários tipos diferentes de sistemas afetados. Vou examiná-los brevemente agora. Tudo isso é baseado na minha experiência. Não pretendo saber todas as respostas.
Modificadores estáticos
Esse tipo de sistema depende principalmente de números inteiros simples para determinar quaisquer modificações. Por exemplo, +100 a Max HP, +10 a atacar e assim por diante. Este sistema também pode lidar com porcentagens também. Você só precisa garantir que o empilhamento não fique fora de controle.
Eu nunca realmente armazenei em cache os valores gerados para esse tipo de sistema. Por exemplo, se eu quisesse exibir a saúde máxima de alguma coisa, geraria o valor no local. Isso impedia que as coisas fossem propensas a erros e apenas mais fáceis de entender para todos os envolvidos.
(Eu trabalho em Java, o que segue é baseado em Java, mas deve funcionar com algumas modificações para outras linguagens.) Esse sistema pode ser feito facilmente usando enumerações para os tipos de modificação e depois números inteiros. O resultado final pode ser colocado em algum tipo de coleção que possui pares de chave e valor ordenados. Serão pesquisas e cálculos rápidos, portanto o desempenho é muito bom.
No geral, ele funciona muito bem com apenas modificadores estáticos. No entanto, o código deve existir nos locais apropriados para que os modificadores sejam usados: getAttack, getMaxHP, getMeleeDamage e assim por diante.
Onde esse método falha (para mim) é uma interação muito complexa entre os buffs. Não existe uma maneira muito fácil de interagir, exceto por guiá-lo um pouco. Ele tem algumas possibilidades de interação simples. Para fazer isso, você deve fazer uma modificação na maneira como armazena os modificadores estáticos. Em vez de usar uma enumeração como chave, você usa uma String. Essa String seria o nome do Enum + variável extra. 9 vezes em 10, a variável extra não é usada; portanto, você ainda mantém o nome da enumeração como chave.
Vamos dar um exemplo rápido: se você quiser modificar o dano contra criaturas mortas-vivas, poderá ter um par ordenado como este: (DAMAGE_Undead, 10) O DAMAGE é o Enum e o Undead é a variável extra. Portanto, durante o seu combate, você pode fazer algo como:
dam += attacker.getMod(Mod.DAMAGE + npc.getRaceFamily()); //in this case the race family would be undead
De qualquer forma, funciona bastante bem e é rápido. Mas falha em interações complexas e em ter código "especial" em todos os lugares. Por exemplo, considere a situação de "25% de chance de se teletransportar na morte". Este é um "bastante" complexo. O sistema acima pode lidar com isso, mas não com facilidade, pois você precisa do seguinte:
- Determine se o jogador tem este mod.
- Em algum lugar, tenha algum código para executar o teletransporte, se for bem-sucedido. A localização desse código é uma discussão em si!
- Obtenha os dados corretos no mapa Mod. O que o valor significa? É a sala onde eles se teletransportam também? E se um jogador tiver dois mods de teleporte? Os montantes não serão somados ?????? FALHA!
Então isso me leva ao meu próximo:
O melhor sistema de buff complexo
Uma vez tentei escrever um MMORPG 2D sozinho. Este foi um erro terrível, mas eu aprendi muito!
Reescrevi o sistema afetado 3 vezes. O primeiro usou uma variação menos poderosa do que foi dito acima. O segundo foi o que eu vou falar.
Esse sistema tinha uma série de classes para cada modificação, assim como: ChangeHP, ChangeMaxHP, ChangeHPByPercent, ChangeMaxByPercent. Eu tinha um milhão desses caras - até coisas como TeleportOnDeath.
Minhas aulas tinham coisas que fariam o seguinte:
- applyAffect
- removeAffect
- checkForInteraction <--- importante
Aplicar e remover se explicam (embora em coisas como porcentagens, o efeito acompanhe o quanto aumentou o HP para garantir quando o efeito se dissipou, apenas removeria a quantidade adicionada. demorei muito tempo para me certificar de que estava certo. Ainda não tive um bom pressentimento.).
O método checkForInteraction era um trecho de código horrivelmente complexo. Em cada uma das classes afeta (ie: ChangeHP), ele teria código para determinar se isso deve ser modificado pelo efeito de entrada. Por exemplo, se você tivesse algo como ...
- Buff 1: Causa 10 de dano de Fogo ao ataque
- Buff 2: Aumenta em 25% todo o dano de fogo.
- Buff 3: aumenta em 15 todo o dano de fogo.
O método checkForInteraction lidaria com todos esses efeitos. Para fazer isso, cada efeito em TODOS os jogadores por perto tinha que ser verificado! Isso ocorre porque o tipo de afeto que eu lidei com vários jogadores ao longo de uma área. Isso significa que o código NUNCA TINHA quaisquer declarações especiais como acima - "se acabamos de morrer, devemos verificar se há teletransporte na morte". Este sistema trataria automaticamente corretamente no momento certo.
Tentar escrever esse sistema levou dois meses e explodiu de cabeça várias vezes. No entanto, era REALMENTE poderoso e poderia fazer uma quantidade insana de coisas - especialmente quando você leva em consideração os dois fatos a seguir para habilidades no meu jogo: 1. Eles tinham intervalos de alvo (ou seja: único, auto, apenas grupo, PB AE auto). , PB AE alvo, AE alvo e assim por diante). 2. As habilidades podem ter mais de um efeito sobre elas.
Como mencionei acima, este foi o segundo do terceiro sistema de afetação para este jogo. Por que me afastei disso?
Este sistema teve o pior desempenho que eu já vi! Era muito lento, pois tinha que fazer muita verificação para cada coisa que acontecia. Tentei melhorá-lo, mas considerou um fracasso.
Então chegamos à minha terceira versão (e outro tipo de sistema de buffs):
Classe afetada complexa com manipuladores
Portanto, é praticamente uma combinação dos dois primeiros: podemos ter variáveis estáticas em uma classe Affect que contém muita funcionalidade e dados extras. Em seguida, basta chamar manipuladores (para mim, praticamente alguns métodos de utilidade estática em vez de subclasses para ações específicas. Mas tenho certeza de que você poderia usar subclasses para ações, se quisesse também) quando quisermos fazer alguma coisa.
A classe Affect teria todos os itens bons e interessantes, como tipos de destino, duração, número de usos, chance de executar e assim por diante.
Ainda teríamos que adicionar códigos especiais para lidar com as situações, por exemplo, teleportar na morte. Ainda teríamos que verificar isso manualmente no código de combate e, se existisse, obteríamos uma lista de efeitos. Esta lista de afetos contém todos os afetos atualmente aplicados no jogador que lidou com o teletransporte na morte. Depois, olhamos cada uma delas e verificamos se ela foi executada e foi bem-sucedida. Se fosse bem-sucedido, chamaríamos o manipulador para cuidar disso.
A interação pode ser feita, se você quiser também. Teria apenas que escrever o código para procurar buffs específicos nos players / etc. Por ter um bom desempenho (veja abaixo), deve ser bastante eficiente fazer isso. Só precisaria de manipuladores mais complexos e assim por diante.
Portanto, ele tem muito desempenho do primeiro sistema e ainda muita complexidade como o segundo (mas não tanto). Pelo menos em Java, você pode fazer algumas coisas complicadas para obter o desempenho da quase primeira nos MOST casos (por exemplo: ter um mapa de enumeração ( http://docs.oracle.com/javase/6/docs/api/java) /util/EnumMap.html ) com Enums como as chaves e ArrayList de afeta como os valores.Isto permite que você veja se você tem afetos rapidamente [já que a lista seria 0 ou o mapa não teria a enumeração] e não possui para iterar continuamente as listas de afetos do jogador sem motivo. Não me importo de repetir os afetos se precisarmos deles neste momento. Otimizarei mais tarde se isso se tornar um problema.
Atualmente, estou reabrindo (reescrevendo o jogo em Java, em vez da base de código FastROM em que ele estava originalmente) meu MUD que terminou em 2005 e recentemente me deparei com como quero implementar meu sistema de buff? Vou usar esse sistema porque funcionou muito bem no meu jogo com falha anterior.
Bem, espero que alguém, em algum lugar, ache algumas dessas idéias úteis.