¿Cómo diseñar la clase de ataque en un juego de rol?

37

Estoy en la fase de planificación de un pequeño juego de estilo RPG.

El personaje tendrá un conjunto de atributos, como fuerza, agilidad, etc., que se representan como enteros. El personaje también tendrá un conjunto de ataques representados como una clase de ataque.

En cada ataque quiero que haga daño basado en los atributos de los personajes, por ejemplo: el ataque "corte de espada" hará 10 dmg + el valor de la fuerza de los personajes.

La forma en que pensaba hacer esto es tener una clase de ataque abstracta, que tiene un método de ataque abstracto, y para cada ataque creo una clase que implementa el método de ataque.

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

Veo que esto hará que sea una pesadilla mantenerlo.

¿Alguien tiene una idea de cómo puedo lograr esto de una manera más agradable?

Lo que creo que es el problema principal es cómo ingresar el atributo correcto, basado en el ataque.

eflles
fuente

Respuestas:

34

Probablemente debería optar por un diseño basado en datos aquí.

Crea una clase de ataque genérico que contenga los parámetros con los que quieres trabajar: daño base, qué estadísticas afectan el daño, un conjunto de posibles efectos de estado ... cosas como esas:

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.
  }
}

Luego, coloca tus ataques en un archivo, por ejemplo, un archivo XML, y carga los datos desde allí:

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

Incluso podría extender esto para extraer valores de múltiples estadísticas, por ejemplo, una Bola de Fuego donde el daño se calcula tanto a partir de una estadística de Intelecto como de Fuego:

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

Si no desea utilizar la misma fórmula de daño básico para todo (por ejemplo, calcular el daño mágico de manera diferente al daño físico), cree subclases de ataque para cada fórmula que necesite y anule el ataque, y especifique qué tipo desea en su archivo XML.

Michael Madsen
fuente
1
+1, pero incluso reemplazaría GetStatValue con una tabla de búsqueda de algún tipo para evitar mantener esa declaración de cambio.
1
El problema con este método es que solo puede tener ataques genéricos controlados por datos; no puede tener nada que use una lógica especial. Terminarás con un conjunto de artículos muy genérico (a medida que ingreses en warcraft
Iain el
2
@Iain: Eso se resuelve muy fácilmente simplemente agregando más datos para permitir esto. Por ejemplo, puede tener una subclase SpecialAttack que hace más cosas o calcula el daño de una manera completamente diferente. Es solo una cuestión de identificar el comportamiento que necesita y luego expresarlo como datos.
Michael Madsen
2
@Iain: además de agregar más campos, también puede resolverlo mediante la expresión de algunos campos de datos o bloques de código en, por ejemplo, Lua. El buen uso de componentes ortogonales también produce resultados más interesantes.
1
+1 para la idea general de estar basado en datos. No estoy de acuerdo con sugerir xml. Existen mejores formatos: yaml, json o un archivo .lua simple si está incrustando Lua.
egarcia
2

Tendría una clase de arma que tiene un método de ataque que anula con el comportamiento que desea. También puedes controlar cómo se ve el arma en el juego, en el inventario, cuánto se vende, etc. en la misma clase.

Iain
fuente
66
-1, no solo no está basado en datos, es una jerarquía profunda en lugar de estar basada en componentes. Es la peor solución posible.
44
El hecho de que este método en particular no esté basado en datos no lo convierte en una mala elección y la jerarquía no sería tan profunda de todos modos. Es simple pero aún poderoso (UnrealEngine es un ejemplo perfecto de esto) si se hace correctamente (es decir, sin valores codificados). Claro que tiene sus desventajas, pero más abajo en el ciclo de desarrollo de un sistema basado en datos, estoy seguro de que se muestran sus desventajas. Creo que su diseño básico de OOP sigue siendo una solución válida en esto y si quiere editar sobre la marcha los valores predeterminados, puede implementarse en la parte superior de un sistema de jerarquía con la misma facilidad.
Dalin Seivewright
66
No todo tiene que estar basado en datos, depende de la escala del juego. Probablemente sea un poco arrogante pensar que mi respuesta es "incorrecta", pero gracias por su honestidad. Creo que esto es solo un choque de estilos entre lo que funciona para mí, hacer juegos Flash todos los días, y tu modelo de desarrollo más tradicional. Puedo decirle que mi enfoque es mucho más rápido de implementar y que tiene una mejor verificación en tiempo de compilación. Tu comentario re. Lua supone que el autor de la pregunta está trabajando en una plataforma que lo respalde.
Iain
2
Al ser un juego de rol, probablemente no sea práctico implementar cada elemento como ese.
Vaughan Hilts
1

Soy realmente nuevo en esto, pero la forma en que lo haría es crear una clase de ataque genérico.

Cuando una instancia de personaje quiere atacar a otra instancia de personaje, crearía una instancia de la clase de ataque, llena de los datos requeridos y la ID del personaje que la creó. Los ajustes del equipo se aplicarían al objeto de ataque, utilizando datos que podrían ingresarse en un documento xml o similar.

Esta instancia de clase se envolvería dentro de otra clase, para proporcionar enlaces para que el entorno determine el rango o similar. Si el ataque es válido, la instancia de ataque se pasaría al personaje que está siendo atacado, quien aplicaría los efectos.

Espero que tenga sentido.

Dave
fuente