Яку структуру даних я повинен використовувати для дерева талантів у стилі Diablo / WoW?


23

Я розглядаю можливість впровадження системи дерева талантів для онлайн-RPG, подібної до тієї, що спостерігається у World of Warcraft, де набуття навички відкриває наступний "ярус" під ним у дереві.

Хтось знає про найкращий спосіб їх структурної реалізації в базі даних / коді?

Відповіді:


13

Використовуйте подібну структуру для представлення дерева в базі даних:

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

І ще одна таблиця для представлення набутих талантів на кожного користувача

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

Ви можете перевірити наявність залежностей від талантів програмно, запитуючи повну таблицю талантів та будуючи пов’язане дерево. Ви також можете зробити це за допомогою SQL, але це вимагатиме або рекурсивних підселектів, або безлічі запитів. Краще зробіть це у своєму коді.

Якщо є декілька залежностей, наприклад, наприклад, Fire Punchзалежить від PunchAND, Immolationвикористовуйте дві таблиці для представлення графіка залежності:

#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

У вашій UserTalentтаблиці немає потреби в стовпці автоматичного ключа. userі це talentможуть бути лише два стовпчики та складений ключ: вони ніколи не будуть копіями, і ви ніколи не idзапитаєте.
doppelgreener

Я не дизайнер бази даних, і мені було б цікаво сказати про це: Якби кожен талант мав унікальне ім'я, чи не могли б ви також не усунути всі інші числові поля ідентифікаторів у цій таблиці таблиці та використовувати імена як ключі (з будь-які зміни каскадували)? Чи будуть якісь значні витрати або вигоди при цьому?
doppelgreener

3
@Jonathan Hobbs: Первинний ідентифікатор автоматичного збільшення завжди приємний для операцій видалення / оновлення. Ніколи не повільніше, але часто швидше. Також розмір рядка тут не викликає занепокоєння. Те саме стосується і унікальних імен талантів. Для гарної продуктивності вам потрібно буде приєднатись до своїх таблиць лише з унікальними цілими числами. Дивіться en.wikipedia.org/wiki/Database_normalization тощо
Jonas Bötel

Спасибі. Дизайнер БД, якого я знав, одного разу заявив, що автокейс - це зло і його слід уникати, але мені ніколи не було зрозуміло, чи так це, чи чому. Я думаю, це не так.
doppelgreener

Немає реальної причини використовувати базу даних для зберігання цих даних, якщо вам не потрібна база даних для дизайнерів, оскільки ви підтримуєте багатокористувацьке редагування або щось подібне. Інакше це просто перешкодить. (Я б також ніколи не використовував для цього первинний ключ самовдосконалення, тому що ви майже напевно хочете приєднатись до логічних імен, вирішених дизайнером, а не ключами, наданими БД.)

5

Я б рекомендував використовувати дерево, де кожен вузол представляє певний талант / вміння. Виходячи з того, заробив гравець талант чи ні, його дитячі таланти можна заробити. Наприклад, наступна структура даних

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

Щоб визначити, які таланти має гравець, ви берете корінний талант і спускаєтесь по графіку, поки не досягнете вузлів талантів, де зароблений неправдивий. Це також виявить, які таланти доступні для отримання: перший талант у кожній гілці вниз від кореневого таланту, де зароблений помилковий.


У вас є вказівник на власний масив і розмір? Fail - використовувати самовластивий покажчик розміру.
DeadMG

На жаль ... C / C ++ змішування та помилка. Я оновив свою відповідь. Дякую за голову.
привид

@DeadMG: що саме ти маєш на увазі під «власноруч власником розміру»? Ви маєте на увазі щось на кшталт вектора вище, чи думали про щось інше?
Килотан

Підвищення ptr_vectorможе бути навіть краще.
Зан Лінкс

5
Структура дерева повинна бути повністю окремою від того, чи заробив гравець, перший - це статичні дані, зроблені дизайнерами, а другий - дані про гравця, що зберігаються в грі збереження або БД.

1

У своїй грі я роблю це так:

База даних:

reference_talent : містить унікальний ідентифікатор, ім'я, ефект тощо

талант : id, playerid <- містить усі таланти, яких гравці "засвоїли".

Ingame: (на сервері)

Я завантажую всі reference_talents у "статичну" (тільки для читання) std :: карту, щоб я міг легко отримати доступ до них за своїм ідентифікатором.

Коли клієнт перевіряє гравця, я отримую всі таланти з бази даних і зберігаю їх у std :: vector, щоб, коли мені потрібно обчислити характеристики тощо, я маю їх в оперативній пам'яті. Я також розсилаю таланти клієнту.

Це про це (за винятком заощадження нових талантів, звичайно, це просто "ВСТАВКА" в таблиці "талант" + повідомлення клієнту).


0

Реляційний підхід

Ви описуєте це як відношення між розблокувальними і розблокованими аналогічно, як у цьому підручнику . Я пропоную дізнатися більше про реляційну алгебру та бази даних. Вони є гарним способом моделювання даних. Якщо ви навчитеся запитувати інформацію з бази даних, ви можете легко моделювати дані.

Я не знаю, скільки ви знаєте про моделювання відносин. Цей підручник повинен вам у цьому допомогти.

Одне рішення

Я припускаю, що WoW працює як насправді (ем), що це так

  • талант розкриває кілька (інших) талантів
  • талант розблоковується кількома (іншими) талантами.

Саме відношення N: N означає, що вам потрібно "середня людина", нове відношення між двома талантами:

(talent who unlocks id, talent who is unlocked)

Таким чином, ви можете мати талант A, який розмикає B, C і D ((A, B), (A, C), (A, D)) і талант Y, розблокований X, Z і W ((X, Y), ( Z, Y), (W, Y)). Імперативною / процедурною / об'єктно-орієнтованою мовою ви зробите це як список / масив пар, як там:

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

Отже, для прикладу "реального світу" Ви можете мати:

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

і це означає, що "стрибки надвисокої" отримуються після того, як у вас є таланти "швидкого бігу" і "антигравітації дитини".

Інше рішення

Я не грав у Diablo останнім часом, але, можливо, у нього було тільки:

  • талант розкриває кілька інших талантів
  • талант розблоковується лише одним талантом.

Це відношення 1: N:

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

подібно до:

 var Talent[8] = { "name": "superpower", "unlocked by": "being Clark Kent"};
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.