Non spiega davvero perché il tuo gruppo ha pensato che sarebbe una buona idea generare (sperabilmente) 151 classi, dato che "per ridurre l'accoppiamento" non ha davvero senso, visto che non hai design o codice e quindi nessun accoppiamento.
Each class will be able to store data such as an ID, its name, the type of Pokemon it is (ie: rock/water/fire/etc), and the moves it can use and learn.
Cambia la 'classe' in 'istanza' in quella frase e ottieni il motivo per cui devi solo creare una one classe Pokemon: condividono tutte le stesse proprietà. Una classe derivata dovrebbe aggiungere o implementare proprietà (e / o metodi) univoche per quella derivazione.
Se definisci le proprietà di ElementType
, Move
e PokemonBase
come tali:
enum ElementType
{
Fire = 1,
Water = 2,
Grass = 4,
Rock = 8,
}
class Move
{
int ID;
string Name;
ElementType ElementType;
int BaseDamage;
}
class PokemonBase
{
int ID;
string Name;
ElementType ElementTypes;
List<Move> Moves;
decimal HitPointsPerLevel;
decimal AttackPointsPerLevel;
}
Quindi le varie istanze differiscono solo in quelle che sono in . La tua classe e il tuo codice non dovrebbero preoccuparsene. Un Pokemon che ha il tipo Fire può essere immagazzinato esattamente nella stessa classe di un Pokemon di tipo Acqua: hanno solo un valore diverso della loro proprietà ElementTypes
.
Ora puoi compilare un elenco di istanze di Pokemon con le loro proprietà e mosse, ad esempio caricando un file di testo o leggendo da un database, in un formato che ti piace.
Puoi risolvere tutti questi problemi durante il caricamento del Pokemon. Nell'origine dati è possibile memorizzare proprietà aggiuntive, che nel caso di "le mosse che può utilizzare e imparare" possono essere una tabella relazionale (o equivalente di testo piatto) a cui si aggiunge Pokemon.ID
, Move.ID
e Level
tra loro (se la memoria mi serve correttamente, imparano una nuova mossa al raggiungimento dei livelli preimpostati), memorizzandoli in una lista o proprietà del dizionario nella tua classe Pokemon.
O forse durante la progettazione pensavi di aver bisogno di una classe diversa per implementare il sistema di combattimento in modo diverso per ogni Pokémon. Non è necessario, poiché combinando le varie proprietà è possibile assegnare a ciascuna istanza le sue proprietà uniche.
Il problema inizia naturalmente quando ti rendi conto che in effetti hai due tipi di Pokemon: un "progetto" per tutti i Pokemon che possono verificarsi nel gioco e un Pokemon reale che un giocatore porta , che ha un Livello, HitPoints e così via, tutte le proprietà dipendenti o calcolate attraverso il Livello o basate sul fatto che l'integrità è "nel gioco". È possibile implementare tali proprietà in una classe derivata:
class Pokemon : PokemonBase
{
int Level;
int MaxHitPoints;
int HitPoints;
// Stats, for example
int Attack { get { return Level * base.AttackPointsPerLevel } };
int Defense;
// This method directly applies the attack results to the incoming Pokemon, by reference.
int Attack(Pokemon other, Move attack)
{
int damageDone = (this.Attack * attack.BaseDamage) - defender.Defense;
// TODO: http://bulbapedia.bulbagarden.net/wiki/Type_chart
decimal modifier = CalculateEffectiveness(other, attack);
damageDone *= modifier;
other.HitPoints -= damageDone;
return damageDone;
}
}
E tutte le istanze di Pokemon
possono usarlo, senza dover ricavare nulla. La chiave è modellare la tua classe e il metodo in modo che le azioni che vuoi intraprendere su ciascuna di esse possano essere applicate a tutte le combinazioni di tipi. Puoi anche per esempio aggiungere un List<DamageOverTimeAttack>
a un Pokemon
per implementare gli attacchi che dovrebbero rimanere attivi per alcuni turni, gestendoli nel metodo Attack()
.
Ora, quando un giocatore incontra un nuovo Pokemon, potresti crearlo da una Fabbrica:
class PokemonFactory
{
List<PokemonBase> _allPokemon;
Pokemon GetPokemon(id, level)
{
blueprint = _allPokemon.Find(id);
return new Pokemon
{
ID = blueprint.ID,
Name = blueprint.Name,
...
Level = level,
...
};
}
}