Come progettare la classe di attacco in un gioco di ruolo?


37

Sono nella fase di pianificazione di un piccolo gioco in stile RPG.

Il personaggio avrà una serie di attributi, come forza, agilità, ecc. Che sono rappresentati come numeri interi. Il personaggio avrà anche una serie di attacchi rappresentati come una classe di attacco.

Ad ogni attacco voglio che faccia danni in base agli attributi dei personaggi, ad esempio: l'attacco "barra della spada" farà 10 dmg + il valore della forza dei personaggi.

Il modo in cui stavo pensando di fare questo è avere una classe di attacco astratta, che ha un metodo di attacco astratto, e per ogni attacco creo una classe che implementa il metodo di attacco.

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

Vedo che questo lo renderà un incubo da mantenere.

Qualcuno ha un'idea di come posso farlo in un modo migliore?

Quello che penso sia il problema principale è come inserire l'attributo corretto, in base all'attacco.

Risposte:


34

Probabilmente dovresti scegliere un design basato sui dati qui.

Crea una classe di attacco generica che contenga i parametri con cui vuoi lavorare - danno base, quali statistiche influenzano il danno, una serie di potenziali effetti sullo stato ... cose del genere:

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

Quindi, posiziona i tuoi attacchi in un file, ad esempio un file XML, e carica i dati da lì:

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

Potresti anche estenderlo per trarre valori da più statistiche, diciamo, una palla di fuoco in cui il danno viene calcolato da una statistica di Intelletto e di Fuoco:

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

Se non vuoi usare la stessa formula di danno base per tutto (ad es. Calcolare il danno magico in modo diverso dal danno fisico), crea sottoclassi di Attacco per ogni formula di cui hai bisogno e sovrascrivi Attacco, e specifica quale tipo vuoi nel tuo file XML.


1
+1, ma vorrei persino sostituire GetStatValue con una tabella di ricerca di qualche tipo per evitare di mantenere quell'istruzione switch.

1
Il problema con questo metodo è che puoi avere solo attacchi generici basati sui dati - non puoi avere nulla che usi una logica speciale. Ti ritroverai con un set di oggetti molto generico (man mano che entri in warcraft
Iain,

2
@Iain: questo è molto facile da risolvere semplicemente aggiungendo più dati per consentirlo. Ad esempio, potresti avere una sottoclasse SpecialAttack che fa più cose o calcola il danno in un modo completamente diverso. Si tratta solo di identificare il comportamento necessario e quindi di esprimerlo come dati.
Michael Madsen,

2
@Iain: Oltre ad aggiungere solo altri campi, puoi anche risolverlo con alcuni dei campi dati che sono espressioni o blocchi di codice, ad esempio Lua. Un buon uso dei componenti ortogonali rende anche risultati più interessanti.

1
+1 per l'idea generale di essere guidato dai dati. Non sono d'accordo con il suggerire XML. Ci sono formati migliori là fuori - yaml, json o un semplice file .lua se stai incorporando Lua.
egarcia,


2

Avrei una classe di armi che ha un metodo di attacco che prevale sul comportamento che desideri. Puoi anche gestire l'aspetto dell'arma nel gioco, nell'inventario, quanto vende per ecc. Nella stessa classe.


6
-1, non solo non è basato sui dati, ma è una gerarchia profonda piuttosto che basata sui componenti. È la peggior soluzione possibile.

4
Solo perché questo particolare metodo non è basato sui dati non lo rende una scelta sbagliata e la gerarchia non sarebbe comunque così profonda. È semplice ma comunque potente (UnrealEngine ne è un perfetto esempio) se eseguito correttamente (ovvero senza valori hardcoded). Certo ha i suoi lati negativi, ma più in basso nel ciclo di sviluppo di un sistema basato sui dati sono sicuro che i suoi lati negativi sono mostrati. Penso che il tuo design OOP di base sia ancora una soluzione valida in questo e se vuole modificare al volo i valori predefiniti, può essere implementato su un sistema gerarchico altrettanto facilmente.
Dalin Seivewright,

6
Non tutto deve essere basato sui dati - dipende dalle dimensioni del gioco. Probabilmente è un po 'arrogante pensare che la mia risposta sia "sbagliata", ma grazie per la tua onestà. Penso che questo sia solo uno scontro di stili tra ciò che funziona per me, creare giochi Flash ogni giorno e il tuo modello di sviluppo più tradizionale. Posso dirti che il mio approccio è molto più veloce da implementare e hai un miglior controllo in fase di compilazione. Il tuo commento riguarda Lua presume che il richiedente stia lavorando su una piattaforma che lo sosterrebbe.
Iain,

2
Essendo un gioco di ruolo, è probabilmente poco pratico implementare ogni oggetto del genere.
Vaughan Hilts,

1

Sono davvero nuovo a questo, ma il modo in cui lo farei è creare una classe di attacco generica.

Quando un'istanza di personaggio vuole attaccare un'altra istanza di personaggio, crea un'istanza della classe di attacco, riempita con i dati richiesti e l'ID del personaggio che l'ha creata. Le regolazioni dall'ingranaggio verrebbero quindi applicate all'oggetto dell'attacco, utilizzando i dati che potrebbero essere inseriti in un documento XML o simile.

Questa istanza di classe verrebbe quindi inserita in un'altra classe, per fornire hook all'ambiente per determinare l'intervallo o simili. Se l'attacco è valido, l'istanza di attacco verrebbe trasmessa al personaggio che viene attaccato, il quale applicherebbe gli effetti.

Spero che abbia senso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.