Я собираюсь мягко не согласиться со всеми и сказать, что реляционный подход здесь разумен. Здесь интересно то, что предметы могут иметь несколько ролей. Основная проблема заключается в том, что отображение между этим реляционным макетом и компоновкой OO в коде не будет казаться «естественным», но я думаю, что на стороне базы данных несколько ролей можно выразить чисто (без странных кодировок или избыточности, просто объединяет) ,
Первое, что нужно решить, это то, какая часть данных относится к конкретному элементу и какая часть используется всеми элементами данного типа.
Вот что я бы сделал, если бы все данные относились к конкретному элементу:
// ITEMS table: attributes common to all items
item_id | name | owner | location | sprite_id | ...
1 | Light Saber | 14 (Tchalvek) | 381 (Tchalvek house) | 5663 | ...
// WEAPONS table: attributes for items that are weapons
item_id | damage | damage_type | durability | ...
1 | 5 | sharp | 13 | ...
// LIGHTING table: attributes for items that serve as lights
item_id | radius | brightness | duration | ...
1 | 3 meters | 50 | 8 hours | ...
В этом дизайне каждый элемент находится в таблице Предметов вместе с атрибутами, которые есть у всех (или большинства) предметов. Каждая дополнительная роль, которую может играть элемент, представляет собой отдельный стол.
Если вы хотите использовать его в качестве оружия, вы должны найти его в таблице оружия. Если он там, то его можно использовать как оружие. Если его там нет, его нельзя использовать в качестве оружия. Наличие записи говорит вам, является ли это оружием. И если он там, все его специфичные для оружия атрибуты хранятся там. Поскольку эти атрибуты хранятся непосредственно, а не в какой-то закодированной форме, вы сможете выполнять с ними запросы / фильтры. (Например, для страницы показателей вашей игры вы можете объединить игроков по типу урона от оружия, и вы сможете сделать это с некоторыми объединениями и типом группового повреждения.)
Элемент может иметь несколько ролей и находиться в нескольких таблицах для конкретных ролей (в этом примере - как оружие, так и освещение).
Если это просто логическое значение типа «это удерживаемо», я бы положил его в таблицу «Предметы». Возможно, стоит кешировать «это оружие» и т. Д. Там, чтобы вам не приходилось искать оружие и другие таблицы ролей. Тем не менее, это добавляет избыточность, поэтому вы должны быть осторожны, чтобы синхронизировать его.
Рекомендация Ари о наличии дополнительной таблицы для каждого типа также может быть использована с этим подходом, если некоторые данные не изменятся для каждого элемента. Например, если урон от оружия не меняется для каждого предмета, но роли по-прежнему различаются для каждого предмета, вы можете выделить общие атрибуты оружия в таблицу:
// WEAPONS table: attributes for items that are weapons
item_id | durability | weapon_type
1 | 13 | light_saber
// WEAPONTYPES table: attributes for classes of weapons
weapon_type_id | damage | damage_type
light_saber | 5 | energy
Другой подход заключается в том, что роли, выполняемые предметами, не различаются по предметам, а только по типам предметов. В этом случае вы поместите item_type в таблицу Items и сможете хранить свойства, такие как «Является ли это оружием» и «Держится ли оно» и «Является ли это светом» в таблице ItemTypes. В этом примере я также делаю имена элементов не меняющимися для каждого элемента:
// ITEMS table: attributes per item
item_id | item_type | owner | location
1 | light_saber | 14 (Tchalvek) | 381 (Tchalvek house)
// ITEMTYPES table: attributes shared by all items of a type
item_type | name | sprite_id | is_holdable | is_weapon | is_light
light_saber | Light Saber | 5663 | true | true | true
// WEAPONTYPES table: attributes for item types that are also weapons
item_type | damage | damage_type
light_saber | 5 | energy
Вероятно, что типы предметов и типы оружия не меняются во время игры, так что вы можете просто загрузить эти таблицы в память и посмотреть эти атрибуты в хеш-таблице, а не в соединении с базой данных.
К сожалению, в подобных ситуациях реляционные базы данных (например, SQL) не хватает, а нереляционные базы данных (например, MongoDB ) превосходны. При этом невозможно моделировать данные в реляционной базе данных, и, поскольку кажется, что ваша кодовая база уже зависит от SQL, вот модель, с которой я бы пошел:
Вместо создания элемента и использования таблицы создайте таблицу и справочную таблицу «[item] _type» для каждого типа элемента.
Вот несколько примеров:
Это решение дает вам долгосрочную гибкость и масштабируемость, оно уменьшает (если не устраняет) потерянное пространство и самодокументируется (в отличие от "item_use_data"). Это требует немного больше настроек со стороны разработчика, но, на мой взгляд, это наиболее элегантное решение, доступное для ситуаций, когда вам нужно использовать реляционную базу данных для хранения ваших данных. Вообще говоря, нереляционные базы данных гораздо лучше для разработки игр, поскольку они более гибки в том, как они моделируют данные, и при этом более производительны, чем базы данных на основе SQL, что делает их «беспроигрышным» выбором.
Изменить 1: исправлена ошибка с полем potion_type_id
Редактировать 2: Добавлено больше подробностей о нереляционных и реляционных базах данных, чтобы обеспечить дополнительную перспективу
источник
Прежде всего, избавьтесь от подхода объектно-ориентированного наследования и перейдите к системе на основе компонентов .
Как только вы это сделаете, макет SQL внезапно станет намного проще. У вас есть одна таблица для каждого типа компонента с общим идентификационным номером. Если вам нужен элемент № 17, вы можете посмотреть «идентификатор элемента 17» в каждой таблице. Любая таблица, имеющая ключ, добавляет свой компонент.
Ваша таблица предметов содержит все необходимые данные для предметов в целом (имя, цена продажи, вес, размер, все остальное, что распределяется между всеми предметами.) Ваша таблица оружия содержит все соответствующие данные для оружия, ваша таблица зелий содержит все соответствующие данные для зелий ваша таблица брони содержит все необходимые данные для брони. Хотите нагрудник, это запись в Item и запись в Armor. Хочешь меч-шлем, который ты можешь пить, ты просто вставляешь запись в каждый стол, и бац, ты готов.
Имейте в виду, что этот же шаблон не особенно специфичен для каждого предмета - вы можете использовать его для существ, зон и всего, что вам захочется. Это удивительно универсально.
источник
Использование SQL было вашей серьезной ошибкой. Это абсолютно НЕ подходит для хранения статических данных игрового дизайна.
Если вы не можете отойти от SQL, я бы посоветовал хранить элементы в сериализованном виде. Т.е.
Конечно, это уродливо и выбрасывает все «тонкости» SQL из окна, но они вам действительно нужны ? Скорее всего, вы все равно читаете все данные о ваших предметах в начале игры, и
SELECT
ничем иным, кроме какitem_id
.источник
В зависимости от того, сколько черт вам понадобится, вы можете использовать простую битовую маску для объектов с разными битами, соответствующими разным чертам:
Затем вы можете выполнить простые битовые тесты, чтобы увидеть, можно ли использовать объект для определенной функции.
Таким образом, «стеклянная бутылка» может иметь значение 101111, что означает, что она пригодна для хранения, может использоваться в качестве оружия, легко разбивается, вы можете бросить ее и содержать жидкости.
Любой редактор, который вы создаете для элементов, может затем иметь простой набор флажков для включения / отключения признаков на объекте.
источник
В нашем проекте у нас есть item_attributes для различных «дополнительных данных», которые может иметь элемент. Выложено что-то вроде этого:
Тогда у нас есть таблица атрибутов, которая выглядит так:
Ари Патрик прав, хотя в конечном итоге реляционные базы данных не созданы для этого. Недостатком является то, что у нас есть довольно сложные процедуры для генерации новых предметов (это делается с помощью внешнего инструмента - который я настоятельно рекомендую, не пытайтесь добавлять их вручную, вы только запутаете себя)
Другой вариант - использовать язык сценариев для создания шаблонов элементов, после чего вы можете легко их проанализировать и использовать для создания новых элементов. Конечно, вам все еще нужно сохранять данные об элементах в базе данных, но в этот момент вам не нужно беспокоиться о специфике создания новых элементов, вы можете просто скопировать старый файл сценария, изменить некоторую информацию, и вы в порядке. идти.
Честно говоря, если бы нам пришлось заново делать то, как мы создаем новые статические элементы, мы бы, вероятно, пошли бы на гораздо более простой подход с использованием шаблонов элементов сценариев.
источник
Это ваши типичные отношения «многие ко многим», не слишком эзотерические для любой способной реляционной базы данных. У вас есть много черт для любых объектов, и любая черта может использоваться одним или несколькими различными типами объектов. Смоделируйте три отношения (таблицы), причем одно из них - отношение ассоциации, и все готово. Правильная индексация обеспечит вам быстрое чтение данных.
Поместите ORM в ваш код, и у вас должно быть очень мало проблем, возникающих между БД и промежуточным программным обеспечением. Многие ORM тоже могут автоматически генерировать классы и становятся еще более «невидимыми».
Что касается баз данных NoSQL, нет никаких причин, по которым вы не можете сделать это с ними. В настоящее время модно поддерживать эту технологию в торговых лоскутах и блогах, но у них есть множество собственных проблем: относительно незрелые платформы, отлично подходящие для простых не часто изменяемых операций чтения (например, одно-многим в профиле), но плохой для сложных динамических чтений или обновлений, плохой вспомогательный инструментарий, избыточные данные и сопутствующие проблемы целостности и т. д. Однако, они предлагают привлекательность лучшей масштабируемости, потому что они избегают в различной степени транзакционных возможностей и их издержек, а также более простых моделей распределения / репликации ,
Обычный хобгоблин реляционных баз данных против баз данных NoSQL - производительность. Различные RDMBS имеют разные степени накладных расходов, что делает их менее предпочтительными для масштабирования до уровней Facebook или Twitter. Однако вряд ли вы столкнетесь с этими проблемами. Даже тогда простые серверные системы на основе SSD могут сделать споры о производительности бесполезными.
Давайте проясним: большинство баз данных NoSQL являются фундаментально распределенными хеш-таблицами и будут ограничивать вас так же, как и хеш-таблица в вашем коде, т.е. не все данные хорошо вписываются в эту модель. Реляционная модель гораздо более эффективна для моделирования отношений между данными. (Смешивающим фактором является то, что большинство СУБД являются устаревшими системами, которые плохо настроены на требования популярного 0,0001% Интернета, а именно Facebook и др.)
источник
Здесь я считаю, что более современные средства сопоставления OR действительно полезны, например, Entity Framework 4 и его (CTP) функция «сначала код» . Вы просто пишете классы и их отношения в обычном коде, и даже без необходимости их украшать или запускать какие-либо инструменты вручную, EF сгенерирует резервное хранилище в формате SQL для вас, с необходимыми таблицами ссылок и всем ... это действительно развивает творческий потенциал. ^^
источник
Вот что я сейчас рассматриваю:
Поскольку каждая «черта» в любом случае требует изменений в коде, поэтому я решил просто сохранить черты (и любые необходимые им данные по умолчанию) в самом коде (по крайней мере, на данный момент).
Например
$traits = array('holdable'=>1, 'weapon'=>1, 'sword'=>array('min_dam'=>1, 'max_dam'=>500));
Затем элементы получают поле «trait_data» в базе данных, которое будет использовать
json_encode()
функцию для сохранения в формате JSON.Планируется, что элементы будут наследовать все характеристики по умолчанию от своих родительских черт, и будут иметь только черты переопределения, которые указывают отличия от тех черт, которые установлены как значения по умолчанию.
Недостатком поля черт является то, что хотя я мог бы редактировать часть json вручную ... ... было бы не очень легко и безопасно сделать это с данными, которые находятся в базе данных.
источник
Это немного глупо, и я не даю никаких гарантий, что это хороший дизайн БД; Мои классы БД были некоторое время назад, и они быстро не приходят на ум. Но если у предметов гарантированно будет, скажем, менее 10 предметов, вы можете присвоить каждому предмету поле attribute1, attribute2 и т. Д. Вплоть до attribute10. Это избавит вас от необходимости использовать таблицу атрибутов «многие ко многим» за счет ограничения количества атрибутов.
Оглядываясь назад, я почти уверен, что это ужасный дизайн, но это значит, что вы можете использовать удобную реляционную базу данных и не переходить на неизведанную территорию. Вам решать, стоит ли компромисс.
источник
Nevermind дал хороший ответ, но мне интересно, вам вообще нужна база данных для этого? Хранение всех данных в виде простого файла и загрузка их в программу при запуске кажется самым разумным способом сделать это.
Редактировать:
Правильно, в среде, управляемой запросами без сохранения состояния, вам лучше хранить данные в базе данных. Запишите свои данные в файл и напишите фрагмент кода, чтобы превратить его в базу данных типа, предложенного Nevermind.
С другой стороны, если число объектов не слишком велико, объявление лота буквально в файле кода может быть самым быстрым способом.
источник