Jak zaprojektować klasę ataku w grze RPG?

37

Jestem w fazie planowania małej gry RPG.

Postać będzie miała zestaw atrybutów, takich jak siła, zwinność itp., Które są reprezentowane jako liczby całkowite. Postać będzie miała również zestaw ataków reprezentowanych jako klasa ataku.

Przy każdym ataku chcę, aby zadawał obrażenia na podstawie atrybutów postaci, np .: atak „cięcie mieczem” spowoduje 10 dmg + wartość siły postaci.

Myślałem o tym, aby mieć abstrakcyjną klasę ataku, która ma abstrakcyjną metodę ataku, i dla każdego ataku tworzę jedną klasę, która implementuje metodę ataku.

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

Widzę, że będzie to koszmar do utrzymania.

Czy ktoś ma pomysł, w jaki sposób mogę to osiągnąć w lepszy sposób?

Myślę, że głównym problemem jest to, jak wprowadzić poprawny atrybut na podstawie ataku.

eflles
źródło

Odpowiedzi:

34

Prawdopodobnie powinieneś wybrać projekt oparty na danych.

Stwórz ogólną klasę Ataku, która zawiera parametry, z którymi chcesz pracować - podstawowe obrażenia, których statystyki wpływają na obrażenia, zestaw potencjalnych efektów statusu ... takie rzeczy:

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

Następnie umieść swoje ataki w pliku, np. Pliku XML, i załaduj stamtąd dane:

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

Możesz nawet rozszerzyć to, aby rysować wartości z wielu statystyk, powiedzmy, Kuli Ognistej, w której obrażenia są obliczane zarówno na podstawie statystyk Intelektu, jak i Ognia:

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

Jeśli nie chcesz używać tej samej podstawowej formuły obrażeń do wszystkiego (np. Obliczaj obrażenia magiczne inaczej niż obrażenia fizyczne), utwórz podklasy Ataku dla każdej potrzebnej formuły i przesłoń Atak i określ, jaki typ chcesz w pliku XML.

Michael Madsen
źródło
1
+1, ale nawet zastąpiłbym GetStatValue tablicą wyszukiwania, aby uniknąć utrzymywania tej instrukcji switch.
1
Problem z tą metodą polega na tym, że możesz mieć tylko ogólne ataki oparte na danych - nie możesz mieć niczego, co używa specjalnej logiki. Skończysz z bardzo ogólnym zestawem przedmiotów (jak dostajesz w Warcraft
Iain
2
@Iain: Można to bardzo łatwo rozwiązać, dodając do tego więcej danych. Np. Możesz mieć podklasę SpecialAttack, która robi więcej rzeczy lub oblicza obrażenia w zupełnie inny sposób. To tylko kwestia zidentyfikowania potrzebnego zachowania, a następnie wyrażenie tego jako danych.
Michael Madsen
2
@Iain: Oprócz dodawania kolejnych pól, możesz również rozwiązać to przez niektóre pola danych będące wyrażeniami lub blokami kodu np. Lua. Dobre wykorzystanie komponentów ortogonalnych daje również bardziej interesujące wyniki.
1
+1 za ogólną ideę opartą na danych. Nie zgadzam się z sugerowaniem xml. Istnieją lepsze formaty - yaml, json lub zwykły plik .lua, jeśli osadzasz Luę.
egarcia
2

Miałbym klasę broni, która ma metodę ataku, którą zastępujesz pożądanym zachowaniem. Następnie możesz poradzić sobie z tym, jak broń wygląda w grze, w ekwipunku, ile sprzedaje za itp. W tej samej klasie.

Iain
źródło
6
-1, nie tylko nie jest to oparte na danych, ale ma głęboką hierarchię, a nie komponenty. To najgorsze możliwe rozwiązanie.
4
Tylko dlatego, że ta konkretna metoda nie jest oparta na danych, nie czyni jej złym wyborem, a hierarchia i tak nie byłaby tak głęboka. Jest prosty, ale wciąż potężny (UnrealEngine jest tego doskonałym przykładem), jeśli jest wykonywany poprawnie (tzn. Nie ma na stałe wartości) Pewnie, że ma to swoje wady, ale na dalszym etapie rozwoju systemu opartego na danych jestem pewien, że jego wady są widoczne. Myślę, że twój podstawowy projekt OOP jest nadal poprawnym rozwiązaniem i jeśli chce on na bieżąco edytować wartości domyślne, może być równie łatwo zaimplementowany w systemie hierarchicznym.
Dalin Seivewright
6
Nie wszystko musi opierać się na danych - zależy to od skali gry. Prawdopodobnie trochę arogancko jest myśleć, że moja odpowiedź jest „zła”, ale dziękuję za twoją uczciwość. Myślę, że to tylko zderzenie stylów między tym, co działa dla mnie, tworzeniem gier Flash na co dzień, a twoim bardziej tradycyjnym modelem rozwoju. Mogę powiedzieć, że moje podejście jest znacznie szybsze do wdrożenia, a Ty masz lepsze sprawdzanie czasu kompilacji. Twój komentarz dotyczy Lua zakłada, że ​​pytający pracuje na platformie, która by to obsługiwała.
Iain
2
Będąc grą RPG, prawdopodobnie niepraktyczne jest wdrożenie każdego takiego przedmiotu.
Vaughan Hilts,
1

Jestem naprawdę nowy, ale sposób, w jaki to zrobię, to stworzenie ogólnej klasy ataku.

Gdy jedna instancja postaci chce zaatakować inną instancję postaci, utworzy instancję klasy ataku, wypełnioną wymaganymi danymi i identyfikatorem postaci, która ją utworzyła. Korekty ze sprzętu zostaną następnie zastosowane do obiektu ataku, przy użyciu danych, które można wprowadzić w dokumencie XML lub podobnym.

Ta instancja klasy zostałaby następnie zapakowana w inną klasę, aby zapewnić haczyki dla środowiska w celu ustalenia zasięgu lub podobnego. Jeśli atak jest prawidłowy, instancja ataku zostanie przekazana atakowanej postaci, która zastosuje efekty.

Mam nadzieję, że to miało sens.

Dave
źródło