Que estrutura de dados devo usar para uma árvore de talentos no estilo Diablo / WoW?

23

Estou pensando em implementar um sistema de árvore de talentos para um RPG online, semelhante ao visto no World of Warcraft, onde a aquisição de uma habilidade desbloqueia o próximo "nível" abaixo dele na árvore.

Alguém sabe a melhor maneira de implementar isso estruturalmente no banco de dados / código?

RSH1
fonte

Respostas:

13

Use uma estrutura como esta para representar uma árvore em um banco de dados:

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

E outra tabela para representar os talentos adquiridos por usuário

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

Você pode verificar dependências de talentos programaticamente consultando a tabela de talentos completa e construindo uma árvore vinculada. Você também pode fazer isso com o SQL, mas isso exigirá subselecionamentos recursivos ou muitas consultas. Melhor fazer isso no seu código.

Se houver várias dependências, como por exemplo, Fire Punchdepende de PunchAND Immolationuse duas tabelas para representar o gráfico de dependência:

#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
Jonas Bötel
fonte
Sua UserTalenttabela não precisa de uma coluna de autokey. usere talentpodem ser as únicas duas colunas e uma chave composta: elas nunca serão duplicadas e você nunca fará consultas id.
Doppelgreener
Eu não sou um designer de banco de dados e gostaria de ouvir a opinião de alguém sobre isso: se todo talento tivesse um nome exclusivo, você também não poderia eliminar todos os outros campos de ID numérico neste design de tabela e usar nomes como chaves (com alguma edição em cascata)? Haveria custos ou benefícios significativos ao fazê-lo?
Doppelgreener
3
@ Jonathan Hobbs: Um ID primário de incremento automático é sempre bom para operações de exclusão / atualização. Nunca é mais lento, mas geralmente mais rápido. Também o tamanho da linha não é motivo de preocupação aqui. O mesmo vale para nomes de talentos únicos. Para um bom desempenho, você desejará associar suas tabelas apenas a números inteiros exclusivos. Veja en.wikipedia.org/wiki/Database_normalization etc.
Jonas Bötel
Obrigado. Um designer de DB que eu conhecia afirmou uma vez que as teclas automáticas eram más e deveriam ser evitadas, mas nunca fui claro se é esse o caso ou por quê. Suponho que não.
Doppelgreener
Não há motivo real para usar um banco de dados para armazenar esses dados, a menos que você precise de um banco de dados para designers, porque você suporta edição multiusuário ou algo assim. Caso contrário, apenas atrapalhará. (Eu também nunca usar uma chave autoincrement primária para isso, porque você quase certamente quer se juntar em nomes lógicos decididos por um designer, em vez de uma chave DB-fornecido.)
5

Eu recomendaria usar uma árvore em que cada nó represente um talento / habilidade específica. Com base no fato de o jogador ganhar ou não um talento, seus talentos infantis podem ser conquistados. Por exemplo, a seguinte estrutura de dados

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

Para determinar quais talentos um jogador possui, você pega o talento raiz e segue o gráfico até chegar aos nós dos talentos em que o ganho é falso. Isso também revelará quais talentos estão disponíveis para obtenção: o primeiro talento em cada ramo, descendo do talento raiz onde o ganho é falso.

fantasma
fonte
Você tem um ponteiro para uma matriz nativa e um tamanho? Falha - use um ponteiro de dimensionamento independente.
DeadMG
Opa ... Mistura de C / C ++ e um erro. Eu atualizei minha resposta. Obrigado pelo aviso.
fantasma
@DeadMG: o que exatamente você quer dizer com 'auto-dimensionamento e auto-dimensionamento'? Você está se referindo a algo como o vetor acima ou estava pensando em outra coisa?
Kylotan
Um impulso ptr_vectorpode ser ainda melhor.
Zan Lynx
5
A estrutura da árvore deve ser totalmente separada se o jogador ganhou, o primeiro são dados estáticos criados por designers e o segundo são dados por jogador armazenados em um jogo salvo ou banco de dados.
1

No meu jogo eu faço assim:

Base de dados:

reference_talent : contém um ID, nome, efeito, etc. exclusivos

talent : id, playerid <- contém todos os talentos que os jogadores "aprenderam".

Jogo: (no servidor)

Carrego todos os reference_talents em um std :: map 'estático' (somente leitura) para que eu possa acessá-los facilmente por seu ID.

Quando um cliente faz check-out de um jogador, eu obtenho todos os talentos do banco de dados e os armazeno em um vetor std :: para que, quando eu precise calcular características etc., eu os tenha na RAM. Também envio os talentos para o cliente.

É isso (exceto salvar novos talentos, é claro, que é apenas um 'INSERIR' na tabela 'talento' + uma mensagem para o cliente).

Valmond
fonte
0

Abordagem relacional

Você o descreve como relação entre desbloqueadores e desbloqueados similares como neste tutorial . Sugiro aprender mais sobre álgebra relacional e bancos de dados. Eles são uma boa maneira de modelar dados. Se você aprender a consultar as informações do banco de dados, poderá modelar dados com bastante facilidade.

Não sei o quanto você sabe sobre modelar relações. Esse tutorial deve ajudá-lo com isso.

Uma solução

Eu suponho que o WoW funcione como na realidade (ehm), que é

  • talento desbloqueia vários (outros) talentos
  • talento é desbloqueado por vários (outros) talentos.

É a relação N: N, o que implica que você precisa do "intermediário" uma nova relação entre os dois talentos:

(talent who unlocks id, talent who is unlocked)

Dessa forma, você pode ter o talento A desbloqueando B, C e D ((A, B), (A, C), (A, D)) e o talento Y desbloqueado por X, Z e W ((X, Y), ( Z, Y), (W, Y)). Em linguagem imperativa / procedural / orientada a objetos, você faria isso como lista / matriz de pares como lá:

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

Portanto, no exemplo do "mundo real", você pode ter:

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

e significa que "pular muito alto" é obtido depois que você tem talentos "rápidos" e "filhos da antigravidade".

Outra solução

Não joguei Diablo recentemente, mas pode ser que ele tivesse apenas:

  • talento desbloqueia vários outros talentos
  • talento é desbloqueado apenas por um talento.

É uma relação 1: N:

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

gostar:

 var Talent[8] = { "name": "superpower", "unlocked by": "being Clark Kent"};
user712092
fonte