Como projetar a classe de ataque em um jogo de RPG?

37

Estou na fase de planejamento de um pequeno jogo estilo RPG.

O personagem terá um conjunto de atributos, como força, agilidade, etc, que são representados como números inteiros. O personagem também terá um conjunto de ataques representados como uma classe de ataque.

Em cada ataque, quero que ele cause dano com base nos atributos dos personagens, por exemplo: o ataque "golpe de espada" fará 10 dmg + o valor da força dos personagens.

O jeito que eu estava pensando em fazer isso é ter uma classe de ataque abstrata, que tem um método de ataque abstrato, e para cada ataque eu crio uma classe que implementa o método de ataque.

public class SwordSlash:Attack
{
    public void Attack(Character attacker, Character defender)
    {
        defender.DoDamage(10 + attacker.Strength);
    }
}

Vejo que isso tornará um pesadelo para manter.

Alguém tem uma idéia de como eu posso fazer isso de uma maneira melhor?

O que eu acho que é o principal problema é como inserir o atributo correto, com base no ataque.

eflles
fonte

Respostas:

34

Você provavelmente deve optar por um design orientado a dados aqui.

Faça uma classe de ataque genérica que contenha os parâmetros com os quais você deseja trabalhar - dano base, que estatísticas afetam o dano, um conjunto de possíveis efeitos de status ... coisas assim:

public enum AttackStat
{
  Strength,
  Agility,
  Intellect
  // etc.
}

public class Attack
{    
  private int baseDamage;
  private AttackStat stat;
  private double damageMultiplier;
  // ...and so on

  public void Attack(Character attacker, Character defender)
  {
    defender.DoDamage(baseDamage + attacker.GetStatValue(stat) * damageMultiplier);
  }    
}

// Put a method on Character to fetch the appropriate value given an AttackStat:
public int GetStatValue(AttackStat s)
{
  switch(s)
  {
    case AttackStat.Strength:
      return strength;
    case AttackStat.Agility:
      return agility;
    // etc.
  }
}

Em seguida, coloque seus ataques em um arquivo, por exemplo, um arquivo XML e carregue os dados a partir daí:

<Attacks>
  <Attack name="Sword Slash" damage="10" stat="Strength" multiplier="1" />
  <!-- More attacks here -->
</Attacks>

Você pode até estender isso para extrair valores de várias estatísticas, digamos, uma Bola de Fogo, onde o dano é calculado a partir das estatísticas de Intelecto e de Fogo:

<Attack name="Fireball" damage="20">
  <StatModifier stat="Intellect" multiplier="0.4" />
  <StatModifier stat="Fire" multiplier="0.8" />
</Attack>

Se você não quiser usar a mesma fórmula básica de dano para tudo (por exemplo, calcule o dano mágico de maneira diferente do dano físico), crie subclasses de Attack para cada fórmula necessária e substitua o Attack e especifique o tipo que deseja no seu arquivo XML.

Michael Madsen
fonte
11
+1, mas eu substituiria GetStatValue por uma tabela de pesquisa de algum tipo para evitar manter a instrução switch.
11
O problema com esse método é que você só pode ter ataques orientados a dados genéricos - não pode ter nada que use lógica especial. Você terminará com um conjunto muito genérico de itens (à medida que você entra em warcraft
Iain
2
@Iain: Isso é muito facilmente resolvido simplesmente adicionando mais dados para permitir isso. Por exemplo, você pode ter uma subclasse SpecialAttack que faz mais coisas ou calcula o dano de uma maneira totalmente diferente. É apenas uma questão de identificar o comportamento que você precisa e depois expressá-lo como dados.
Michael Madsen
2
@ Iain: Além de adicionar mais campos, você também pode resolver isso por alguns campos de dados serem expressões ou blocos de código, por exemplo, Lua. O bom uso de componentes ortogonais também produz resultados mais interessantes.
11
+1 para a ideia geral de ser orientado por dados. Não concordo em sugerir xml. Existem melhores formatos por aí - yaml, json ou um arquivo .lua simples, se você estiver incorporando Lua.
egarcia
2

Eu teria uma classe de armas que possui um método de ataque que você substitui pelo comportamento que deseja. Você também pode lidar com a aparência da arma no jogo, no inventário, quanto ela vende etc. na mesma classe.

Iain
fonte
6
-1, isso não é apenas orientado a dados, é uma hierarquia profunda em vez de orientado a componentes. É a pior solução possível.
4
Só porque esse método específico não é orientado por dados, não a torna uma má escolha e a hierarquia não seria tão profunda assim. É simples, mas ainda poderoso (o UnrealEngine é um exemplo perfeito disso) se feito corretamente (ou seja, sem valores codificados). Claro que tem suas desvantagens, mas mais adiante no ciclo de desenvolvimento de um sistema orientado a dados, tenho certeza de que suas desvantagens são mostradas. Eu acho que seu design básico de POO ainda é uma solução válida e se ele deseja editar rapidamente os valores padrão, ele pode ser implementado no topo de um sistema de hierarquia com a mesma facilidade.
Dalin Seivewright
6
Nem tudo precisa ser orientado a dados - depende da escala do jogo. Provavelmente é um pouco arrogante pensar que minha resposta está "errada", mas obrigado por sua honestidade. Acho que isso é apenas um choque de estilos entre o que funciona para mim, criar jogos em Flash todos os dias e seu modelo de desenvolvimento mais tradicional. Posso dizer que minha abordagem é muito mais rápida de implementar e você tem uma melhor verificação em tempo de compilação. O seu comentário re. Lua assume que o solicitante está trabalhando em uma plataforma que suportaria isso.
Iain
2
Sendo um jogo de RPG, provavelmente é impraticável implementar todos os itens como esse.
Vaughan Hilts 10/10/12
1

Eu sou realmente novo nisso, mas o jeito que eu faria isso é criar uma classe de ataque genérica.

Quando uma instância de personagem deseja atacar outra, ela criará uma instância da classe de ataque, preenchida com os dados necessários e o ID do personagem que a criou. Os ajustes de equipamento seriam aplicados ao objeto de ataque, usando dados que poderiam ser inseridos em um documento xml ou similar.

Essa instância de classe seria agrupada dentro de outra classe, para fornecer ganchos para o ambiente determinar o alcance ou similar. Se o ataque for válido, a instância do ataque será passada ao personagem que está sendo atacado, que aplicará os efeitos.

Espero que isso faça sentido.

Dave
fonte