Как спроектировать класс атаки в RPG-игре?

37

Я нахожусь в стадии планирования маленькой игры в стиле RPG.

У персонажа будет набор атрибутов, таких как сила, ловкость и т. Д., Которые представлены в виде целых чисел. У персонажа также будет набор атак, представленный как класс атаки.

При каждой атаке я хочу, чтобы она наносила урон в зависимости от атрибутов персонажа, например: атака «удар мечом» будет наносить 10 урона + значение силы персонажа.

Я думал об этом, чтобы иметь абстрактный класс атаки, который имеет абстрактный метод Attack, и для каждой атаки я создаю один класс, который реализует метод Attack.

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

Я вижу, что это станет кошмаром для поддержания.

Кто-нибудь имеет представление о том, как я могу сделать это лучше?

Я думаю, что основная проблема заключается в том, как правильно ввести атрибут, основываясь на атаке.

eflles
источник

Ответы:

34

Вы, вероятно, должны пойти на управляемый данными дизайн здесь.

Создайте общий класс Attack, который содержит параметры, с которыми вы хотите работать - базовый урон, статистика, влияющая на урон, набор потенциальных эффектов статуса ... и тому подобное:

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

Затем поместите ваши атаки в файл, например, в файл XML, и загрузите данные оттуда:

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

Вы можете даже расширить это, чтобы получить значения из нескольких характеристик, скажем, Огненного шара, где урон рассчитывается как от интеллекта, так и от Огня:

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

Если вы не хотите использовать одну и ту же формулу базового урона для всего (например, рассчитывать магический урон иначе, чем физический урон), создайте подклассы Attack для каждой необходимой вам формулы, переопределите Attack и укажите, какой тип вы хотите использовать в своем XML-файле.

Майкл Мэдсен
источник
1
+1, но я бы даже заменил GetStatValue какой-нибудь таблицей поиска, чтобы избежать поддержки этого оператора switch.
1
Проблема этого метода заключается в том, что вы можете проводить только общие атаки, основанные на данных - у вас не может быть ничего, использующего специальную логику. В итоге вы получите очень общий набор предметов (как вы получаете в Warcraft
Iain
2
@Iain: это очень легко решить, просто добавив больше данных, чтобы позволить это. Например, у вас может быть подкласс SpecialAttack, который делает больше вещей или рассчитывает урон совершенно другим способом. Это просто вопрос определения нужного вам поведения, а затем его выражения в виде данных.
Майкл Мэдсен
2
@Iain: В дополнение к простому добавлению дополнительных полей, вы также можете решить это с помощью некоторых полей данных, являющихся выражениями или кодовыми блоками, например, в Lua. Хорошее использование ортогональных компонентов также дает более интересные результаты.
1
+1 за общую идею быть управляемым данными. Я не согласен с предложением XML. Есть лучшие форматы - yaml, json или простой файл .lua, если вы встраиваете Lua.
egarcia
2

У меня был бы класс оружия, у которого есть метод атаки, который вы переопределяете на поведение, которое хотите. Затем вы также можете управлять тем, как оружие выглядит в игре, в инвентаре, за сколько оно продается и т. Д. В том же классе.

Iain
источник
6
-1, не только это не обусловлено данными, это глубокая иерархия, а не управляемая компонентами. Это худшее из возможных решений.
4
Тот факт, что этот конкретный метод не управляется данными, не делает его плохим выбором, и иерархия в любом случае не будет такой глубокой. Это просто, но все же мощно (UnrealEngine является прекрасным примером этого), если все сделано правильно (т.е. без жестко закодированных значений). Конечно, у этого есть свои недостатки, но дальше в цикле разработки управляемой данными системы я уверен, что его недостатки проявляются. Я думаю, что ваш базовый дизайн ООП все еще является правильным решением, и если он хочет на лету редактировать значения по умолчанию, он может быть реализован поверх иерархической системы так же легко.
Далин Сейврайт
6
Не все должно управляться данными - это зависит от масштаба игры. Вероятно, немного высокомерно думать, что мой ответ «неправильный», но спасибо за вашу честность. Я думаю, что это всего лишь столкновение стилей между тем, что работает для меня, делать Flash-игры каждый день, и вашей более традиционной моделью развития. Я могу сказать вам, что мой подход гораздо быстрее внедряется, и вы лучше проверяете время компиляции. Ваш комментарий повторно. Луа предполагает, что спрашивающий работает над платформой, которая бы это поддерживала.
Iain
2
Будучи RPG-игрой, возможно, практически невозможно реализовать каждый подобный предмет.
Вон Хилтс
1

Я действительно новичок в этом, но я бы создал общий класс атаки.

Когда один экземпляр персонажа хочет атаковать другой экземпляр персонажа, он создает экземпляр класса атаки, заполненный требуемыми данными и идентификатором персонажа, который его создал. Корректировки от экипировки будут затем применяться к объекту атаки, используя данные, которые могут быть введены в XML-документ или аналогичный.

Этот экземпляр класса затем будет обернут внутри другого класса, чтобы обеспечить хуки для среды для определения диапазона или подобного. Если атака действительна, экземпляр атаки будет передан атакующему персонажу, который будет применять эффекты.

Надеюсь, что это имело смысл.

Дейв
источник