Buon design per la ricreazione di pokemon

2

Attualmente sto lavorando a un progetto di gruppo per ricreare la versione originale di Pokemon Yellow in Java. Abbiamo appena iniziato a pianificarlo, ma il modo in cui abbiamo disegnato il design adesso è avere una classe Pokemon astratta e avere 151 classi (Conte delle Pokemon originali) che la estendono, essendo ognuno un Pokemon diverso. Ogni classe sarà in grado di memorizzare dati come un ID, il suo nome, il tipo di Pokemon che è (cioè: roccia / acqua / fuoco / ecc.) E le mosse che può usare e imparare. Sembra un po 'troppo creare 151 classi per i Pokemon ma sembra anche un buon modo per limitare l'accoppiamento. Per quanto riguarda il design, questo è un buon modo per farlo, se non quali sono i metodi migliori per farlo?

    
posta Jake 17.11.2013 - 09:34
fonte

5 risposte

6

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,
            ...
        };
    }       
}
    
risposta data 17.11.2013 - 12:10
fonte
2

fare pokemon differenti dovrebbe esporre API diverse nel tuo codice? Dovresti prima analizzare questo.

Loro ID, nome e amp; il tipo può essere memorizzato nei membri. Ora potresti dire che hanno diverse abilità. Quindi ogni abilità dovrebbe essere un metodo. Ma avresti torto. Ciò impedirebbe di scrivere codice semplice durante la gestione del combattimento.

Dovresti astrarre un'abilità in una classe separata. Può essere definito dal suo costo e amp; effetto. Quindi ogni creatura ha una lista di abilità. I tuoi 151 pokemons sono definiti in un metodo di servizio o in un file di configurazione. Durante la scrittura di caratteristiche, il codice non dovrebbe mai importare di quale tipo di pokemon viene passato.

La classe 151 per modellare qualcosa è un enorme costo di complessità. Molto probabilmente, dovresti usare la riflessione per ispezionare i dati relativi a una particolare classe. Questo sarebbe un uso improprio del sistema di classe java.

    
risposta data 17.11.2013 - 10:46
fonte
1

Credo che se si dispone di un tipo di pokemon di base, potrebbe essere più semplice ricavare solo i tipi di fuoco, acqua, elettricità dalla classe base per limitare il numero di classi diverse necessarie. Da ciò, è possibile impostare le relazioni tra i tipi di pokemon senza troppi problemi, ad es. Il fuoco batte acqua ed erba, debole a elettrico ecc.

Da lì probabilmente puoi avere un database o un file JSON / XML che memorizza tutte le statistiche di ogni Pokemon, ID, nome e da quale evoluzione proviene. Questo formato potrebbe sicuramente aiutare con il raggruppamento e la classificazione dei dati senza molto sovraccarico. I dati possono quindi essere tirati da ogni classe di tipo pokemon una volta che il programma si inizializza leggendo il file JSON / XML in sequenza. Un sacco di quel processo può essere automatizzato una volta che hai impostato tutte le statistiche nel negozio di file. Da lì, l'accesso a ciascun Pokemon dovrebbe essere semplice!

    
risposta data 17.11.2013 - 10:01
fonte
0

Non sono sicuro del motivo per cui avresti bisogno di 151 classi separate per archiviare i dati per ciascun Pokémon.

Se leggo correttamente il tuo intento, vuoi avere 151 classi, una per memorizzare i dati di base per ogni specie di Pokémon (apparentemente come dati statici per la classe). Ma questo è irrimediabilmente inelegante. Se hai solo bisogno di una struttura per memorizzare i dati di base per ciascun Pokémon, perché non avere qualcosa come una classe PokemonBaseData ?

Potresti strutturarlo in questo modo (perdonami se la sintassi non è corretta, il mio Java è un po 'arrugginito):

public class PokemonBaseData {

    public int ID;
    public int type1, type2;
    public int height_cm, weight_hg;
    public int base_HP, base_AT, base_DF, base_SA, base_SD, base_SP;
    public Vector<Integer> usable_moves; // or move IDs
    // other properties as you desire them here

}

E fare in modo che ogni Pokémon di un certo ID di specie si riferisca alla classe PokemonBaseData con un ID corrispondente per i dati inerenti a quella specie.

    
risposta data 17.11.2013 - 11:24
fonte
0

Hai considerato il schema dei pesi volanti ? Ciò consentirebbe di evitare di creare le 151 classi e di avere ancora la funzionalità richiesta.

    
risposta data 17.11.2013 - 13:20
fonte

Leggi altre domande sui tag