Quale struttura di dati dovrei usare per un albero dei talenti in stile Diablo / WoW?


23

Sto prendendo in considerazione l'implementazione di un sistema di alberi dei talenti per un gioco di ruolo online, simile a quello visto in World of Warcraft, in cui l'acquisizione di un'abilità sblocca il successivo "livello" sotto di esso nell'albero.

Qualcuno conosce il modo migliore per implementarlo strutturalmente nel database / codice?

Risposte:


13

Utilizzare una struttura come questa per rappresentare un albero in un database:

#Talent
id  parent  description
1   0       Tackle
2   1       Kick
3   1       Punch
4   3       Fire Punch

E un'altra tabella per rappresentare i talenti acquisiti per utente

#UserTalent
id  user  talent
1   4     1
2   4     3
3   4     4

È possibile verificare le dipendenze dei talenti in modo programmatico eseguendo una query sulla tabella dei talenti completa e creando un albero collegato. Puoi farlo anche con SQL ma richiederà sottoselezioni ricorsive o molte query. Meglio farlo nel tuo codice.

Se ci sono più dipendenze, come ad esempio Fire Punchdipende da PunchAND Immolationusa due tabelle per rappresentare il grafico delle dipendenze:

#Talent
id  description
1   Tackle
2   Kick
3   Punch
4   Fire Punch
5   Immolation

#Depedency
id  parent  child
1   0       1
2   0       5
3   1       2
4   1       3
5   3       4
6   5       4

La tua UserTalenttabella non ha bisogno di una colonna autokey. usere talentpossono essere le uniche due colonne e una chiave composita: non saranno mai duplicati e non eseguirai mai query id.
doppelgreener,

Non sono un progettista di database e sarei interessato a sentire la propria opinione su questo: se ogni talento avesse un nome univoco, non potresti anche eliminare ogni altro campo ID numerico in questo disegno di tabella e usare i nomi come chiavi (con eventuali modifiche in cascata)? Ci sarebbero costi o benefici significativi nel farlo?
doppelgreener,

3
@Jonathan Hobbs: un ID primario di autoincremento è sempre utile per le operazioni di eliminazione / aggiornamento. Non è mai più lento ma spesso più veloce. Anche le dimensioni della riga non destano preoccupazione qui. Lo stesso vale anche per i nomi di talenti unici. Per una buona prestazione ti consigliamo di unire i tuoi tavoli solo su numeri interi univoci. Vedi en.wikipedia.org/wiki/Database_normalization ecc.
Jonas Bötel,

Grazie. Un progettista di DB che conoscevo una volta dichiarò che gli autokeys erano malvagi e che dovevano essere evitati, ma non sono mai stato chiaro sul caso o sul perché. Suppongo che non lo sia.
doppelgreener,

Non esiste alcun motivo reale per utilizzare un database per archiviare questi dati a meno che non sia necessario un database per i progettisti perché si supporta la modifica multiutente o qualcosa del genere. Altrimenti si metterà di mezzo. (Non userei mai nemmeno una chiave di incremento automatico primaria per questo, perché quasi sicuramente vorresti unirti a nomi logici decisi da un progettista piuttosto che a una chiave fornita da DB.)

5

Consiglierei di usare un albero in cui ogni nodo rappresenta un talento / abilità specifici. In base al fatto che il giocatore abbia guadagnato o meno un talento, i suoi talenti figlio possono essere guadagnati. Ad esempio la seguente struttura di dati

class Talent {
    std::vector<Talent*> children;
    bool earned;
};

Per determinare quali talenti ha un giocatore, prendi il talento di root e percorri il grafico fino a raggiungere i nodi di talento in cui il guadagno è falso. Ciò rivelerà anche quali talenti sono disponibili per l'ottenimento: il primo talento in ogni ramo è discendente dal talento di base in cui il guadagno è falso.


Hai un puntatore a un array nativo e una dimensione? Non utilizzare un puntatore di auto-dimensionamento proprietario.
DeadMG,

Whoops ... C / C ++ mixup e un errore. Ho aggiornato la mia risposta. Grazie per il testa a testa.
fantasma

@DeadMG: cosa intendi esattamente per "auto-dimensionamento di sé"? Ti riferisci a qualcosa come il vettore qui sopra o stai pensando a qualcos'altro?
Kylotan,

A Boost ptr_vectorpotrebbe essere ancora meglio.
Zan Lynx,

5
La struttura ad albero dovrebbe essere completamente separata dal fatto che il giocatore l'abbia guadagnata, la prima è costituita da dati statici creati dai progettisti e la seconda da dati per giocatore memorizzati in una partita di salvataggio o DB.

1

Nel mio gioco lo faccio in questo modo:

Banca dati:

reference_talent : contiene un ID univoco, un nome, un effetto ecc

talent : id, playerid <- contiene tutti i talenti che i giocatori hanno "imparato".

In gioco: (sul server)

Carico tutte le reference_talents in una std :: map 'statica' (sola lettura) così posso accedervi facilmente con il loro ID.

Quando un cliente verifica un giocatore ottengo tutti i talenti dal database e li immagazzina in uno std :: vector in modo che quando ho bisogno di calcolare caratteristiche ecc. Li ho nella RAM. Mando anche i talenti al cliente.

Questo è tutto (tranne ovviamente il salvataggio di nuovi talenti che è solo un "INSERIMENTO" nella tabella "talento" + un messaggio al cliente).


0

Approccio relazionale

Lo descrivi come relazione tra sbloccatori e sbloccati simili come in questo tutorial . Suggerisco di saperne di più sull'algebra relazionale e sui database. Sono un ottimo modo per modellare i dati. Se si impara come eseguire query sulle informazioni dal database È possibile modellare i dati abbastanza facilmente.

Non so quanto tu sappia sulle relazioni modellistiche. Quel tutorial dovrebbe aiutarti.

Una soluzione

Suppongo che WoW funzioni come nella realtà (ehm), che lo sia

  • il talento sblocca diversi (altri) talenti
  • il talento è sbloccato da diversi (altri) talenti.

È la relazione N: N, che implica che hai bisogno di "uomo medio" una nuova relazione tra i due talenti:

(talent who unlocks id, talent who is unlocked)

In questo modo puoi avere il talento A che sblocca B, C e D ((A, B), (A, C), (A, D)) e il talento Y sbloccato da X, Z e W ((X, Y), ( Z, Y), (W, Y)). In un linguaggio imperativo / procedurale / orientato agli oggetti Lo faresti come elenco / matrice di coppie come lì:

var unlocks_unlocked = [[A, B],[A,C],[A,D],[X,Y],[Z,Y],[W,Y]];

Quindi, per esempio nel "mondo reale" puoi avere:

... ["running fast", "jumping superhigh"], ["antigravity's child", "jumping superhigh"]

e significa che il "salto in alto" si ottiene dopo che hai talento "corsa veloce" e "figlio di antigravità".

Altra soluzione

Non ho giocato a Diablo di recente, ma potrebbe essere che avesse solo:

  • il talento sblocca molti altri talenti
  • il talento è sbloccato solo da un talento.

È la relazione 1: N:

 You put "is unlocked by this talent's id" variable into talent's structure

piace:

 var Talent[8] = { "name": "superpower", "unlocked by": "being Clark Kent"};
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.