Quelle structure de données dois-je utiliser pour un arbre de talents de style Diablo / WoW?
23
J'envisage d'implémenter un système d'arborescence de talents pour un RPG en ligne, similaire à celui de World of Warcraft, où l'acquisition d'une compétence déverrouille le "niveau" suivant en dessous dans l'arborescence.
Quelqu'un connaît-il la meilleure façon de mettre cela en œuvre structurellement dans la base de données / le code?
Utilisez une structure comme celle-ci pour représenter un arbre dans une base de données:
#Talent
id parent description
10Tackle21Kick31Punch43FirePunch
Et une autre table pour représenter les talents acquis par utilisateur
#UserTalent
id user talent
141243344
Vous pouvez vérifier les dépendances des talents par programmation en interrogeant la table complète des talents et en créant une arborescence liée. Vous pouvez également le faire avec SQL mais cela nécessitera soit des sous-sélections récursives, soit de nombreuses requêtes. Mieux vaut le faire dans votre code.
S'il y a plusieurs dépendances, comme par exemple Fire Punchdépend de PunchET Immolationutilisez deux tables pour représenter le graphique de dépendance:
#Talent
id description
1Tackle2Kick3Punch4FirePunch5Immolation#Depedency
id parent child
101205312413534654
Votre UserTalenttable n'a pas besoin d'une colonne autokey. useret talentpeut être les deux seules colonnes et une clé composite: ce ne seront jamais des doublons et vous ne demanderez jamais de idtoute façon.
doppelgreener
Je ne suis pas un concepteur de base de données et je serais intéressé d'entendre son opinion à ce sujet: si chaque talent avait un nom unique, ne pourriez-vous pas également supprimer tous les autres champs d'identification numérique dans cette conception de table et utiliser des noms comme clés (avec des modifications en cascade)? Y aurait-il des coûts ou des avantages importants à le faire?
doppelgreener
3
@Jonathan Hobbs: Un identifiant principal d'auto-incrémentation est toujours agréable pour les opérations de suppression / mise à jour. Ce n'est jamais plus lent mais souvent plus rapide. La taille des lignes n'est pas non plus un problème ici. Il en va de même pour le cas des noms de talents uniques. Pour de bonnes performances, vous souhaiterez joindre vos tables uniquement sur des entiers uniques. Voir en.wikipedia.org/wiki/Database_normalization etc.
Jonas Bötel
Merci. Un concepteur de base de données que je connaissais a déclaré une fois que les autokeys étaient mauvais et devaient être évités, mais je n'ai jamais été clair sur le cas ou sur la raison. Je suppose que non.
doppelgreener
Il n'y a aucune raison réelle d'utiliser une base de données pour stocker ces données, sauf si vous avez besoin d'une base de données pour les concepteurs, car vous prenez en charge l'édition multi-utilisateurs ou quelque chose. Sinon, cela ne fera qu'empêcher. (Je n'utiliserais jamais non plus de clé d'auto-incrémentation principale pour cela, car vous voulez presque certainement vous associer à des noms logiques décidés par un concepteur plutôt qu'à une clé fournie par la base de données.)
5
Je recommanderais d'utiliser un arbre où chaque nœud représente un talent / compétence spécifique. Selon que le joueur a gagné ou non un talent, ses talents d'enfant peuvent être gagnés. Par exemple, la structure de données suivante
Pour déterminer les talents d'un joueur, vous prenez le talent racine et parcourez le graphique jusqu'à ce que vous atteigniez les nœuds de talent où il est faux. Cela révèlera également quels talents sont disponibles pour l'obtention: le premier talent dans chaque branche en dessous du talent racine où il est gagné est faux.
Vous avez un pointeur vers un tableau natif et une taille? Échec: utilisez un pointeur à dimensionnement automatique.
DeadMG
Oups ... Mélange C / C ++ et une erreur. J'ai mis à jour ma réponse. Merci pour l'information.
fantôme
@DeadMG: qu'entendez-vous exactement par «auto-dimensionnement auto-propriétaire»? Faites-vous référence à quelque chose comme le vecteur ci-dessus, ou pensiez-vous à autre chose?
Kylotan
Un coup de pouce ptr_vector pourrait être encore mieux.
Zan Lynx
5
La structure arborescente doit être entièrement distincte de savoir si le joueur l'a gagnée, la première est des données statiques faites par les concepteurs et la seconde est des données par joueur stockées dans une sauvegarde ou une base de données.
1
Dans mon jeu, je le fais comme ceci:
Base de données:
reference_talent : contient un identifiant unique, un nom, un effet, etc.
talent : id, playerid <- contient tous les talents que les joueurs ont "appris".
Ingame: (sur le serveur)
Je charge tous les reference_talents dans une std :: map 'statique' (en lecture seule) afin que je puisse y accéder facilement par leur identifiant.
Lorsqu'un client vérifie un joueur, j'obtiens tous les talents de la base de données et les stocke dans un vecteur std :: afin que lorsque j'ai besoin de calculer des caractéristiques, etc., je les ai dans la RAM. J'envoie également les talents au client.
C'est à peu près tout (sauf sauver de nouveaux talents bien sûr qui n'est qu'un 'INSERT' dans le tableau 'talent' + un message au client).
Vous le décrivez comme une relation entre les déverrouilleurs et déverrouillés similaires comme dans ce tutoriel . Je suggère d'en savoir plus sur l'algèbre relationnelle et les bases de données. Ils sont une bonne façon de modéliser les données. Si vous apprenez à interroger les informations de la base de données, vous pouvez modéliser les données assez facilement.
Je ne sais pas ce que vous savez sur la modélisation des relations. Ce didacticiel devrait vous y aider.
Une solution
Je suppose que WoW fonctionne comme dans la réalité (ehm), qu'il est
le talent débloque plusieurs (autres) talents
le talent est débloqué par plusieurs (autres) talents.
C'est la relation N: N, ce qui implique que vous avez besoin de "l'homme du milieu" une nouvelle relation entre les deux talents:
(talent who unlocks id, talent who is unlocked)
De cette façon, vous pouvez avoir le talent A déverrouillant B, C et D ((A, B), (A, C), (A, D)) et le talent Y déverrouillé par X, Z et W ((X, Y), ( Z, Y), (W, Y)). Dans un langage impératif / procédural / orienté objet, vous le feriez en tant que liste / tableau de paires comme ici:
var unlocks_unlocked =[[A, B],[A,C],[A,D],[X,Y],[Z,Y],[W,Y]];
Donc, pour l'exemple "du monde réel" Vous pouvez avoir:
UserTalent
table n'a pas besoin d'une colonne autokey.user
ettalent
peut être les deux seules colonnes et une clé composite: ce ne seront jamais des doublons et vous ne demanderez jamais deid
toute façon.Je recommanderais d'utiliser un arbre où chaque nœud représente un talent / compétence spécifique. Selon que le joueur a gagné ou non un talent, ses talents d'enfant peuvent être gagnés. Par exemple, la structure de données suivante
Pour déterminer les talents d'un joueur, vous prenez le talent racine et parcourez le graphique jusqu'à ce que vous atteigniez les nœuds de talent où il est faux. Cela révèlera également quels talents sont disponibles pour l'obtention: le premier talent dans chaque branche en dessous du talent racine où il est gagné est faux.
la source
ptr_vector
pourrait être encore mieux.Dans mon jeu, je le fais comme ceci:
Base de données:
reference_talent : contient un identifiant unique, un nom, un effet, etc.
talent : id, playerid <- contient tous les talents que les joueurs ont "appris".
Ingame: (sur le serveur)
Je charge tous les reference_talents dans une std :: map 'statique' (en lecture seule) afin que je puisse y accéder facilement par leur identifiant.
Lorsqu'un client vérifie un joueur, j'obtiens tous les talents de la base de données et les stocke dans un vecteur std :: afin que lorsque j'ai besoin de calculer des caractéristiques, etc., je les ai dans la RAM. J'envoie également les talents au client.
C'est à peu près tout (sauf sauver de nouveaux talents bien sûr qui n'est qu'un 'INSERT' dans le tableau 'talent' + un message au client).
la source
Approche relationnelle
Vous le décrivez comme une relation entre les déverrouilleurs et déverrouillés similaires comme dans ce tutoriel . Je suggère d'en savoir plus sur l'algèbre relationnelle et les bases de données. Ils sont une bonne façon de modéliser les données. Si vous apprenez à interroger les informations de la base de données, vous pouvez modéliser les données assez facilement.
Je ne sais pas ce que vous savez sur la modélisation des relations. Ce didacticiel devrait vous y aider.
Une solution
Je suppose que WoW fonctionne comme dans la réalité (ehm), qu'il est
C'est la relation N: N, ce qui implique que vous avez besoin de "l'homme du milieu" une nouvelle relation entre les deux talents:
De cette façon, vous pouvez avoir le talent A déverrouillant B, C et D ((A, B), (A, C), (A, D)) et le talent Y déverrouillé par X, Z et W ((X, Y), ( Z, Y), (W, Y)). Dans un langage impératif / procédural / orienté objet, vous le feriez en tant que liste / tableau de paires comme ici:
Donc, pour l'exemple "du monde réel" Vous pouvez avoir:
et cela signifie que "sauter très haut" est obtenu après que vous ayez des talents de "courir vite" et "d'enfant d'antigravité".
Autre solution
Je n'ai pas joué à Diablo récemment mais il se peut qu'il n'ait que:
C'est une relation 1: N:
comme:
la source