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?
Use uma estrutura como esta para representar uma árvore em um banco de dados:
#Talent
id parent description
10Tackle21Kick31Punch43FirePunch
E outra tabela para representar os talentos adquiridos por usuário
#UserTalent
id user talent
141243344
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
1Tackle2Kick3Punch4FirePunch5Immolation#Depedency
id parent child
101205312413534654
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
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.
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).
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:
UserTalent
tabela não precisa de uma coluna de autokey.user
etalent
podem ser as únicas duas colunas e uma chave composta: elas nunca serão duplicadas e você nunca fará consultasid
.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
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.
fonte
ptr_vector
pode ser ainda melhor.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).
fonte
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 é
É a relação N: N, o que implica que você precisa do "intermediário" uma nova relação entre os dois talentos:
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á:
Portanto, no exemplo do "mundo real", você pode ter:
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:
É uma relação 1: N:
gostar:
fonte