Нека бъдем честни:всички обичаме да играем игри, особено на нашите компютри. Докато Интернет стана широко разпространен, повечето от нас играеха сами компютърни игри, обикновено срещу опоненти на AI. Беше забавно, но веднага щом разбрахте как работи механиката на играта, играта загуби по-голямата част от магията си.
Развитието на Интернет премести игрите онлайн. Сега можем да играем срещу човешки опоненти и да тестваме уменията си срещу техните. Няма повече наизуст геймплей!
Тогава се появиха масови мултиплейър онлайн (MMO) игри и промениха всичко. Хиляди играчи се озоваха в едни и същи игрови вселени, като се състезаваха за ресурси, преговаряха, търгуваха и се биеха. За да направи подобни игри възможни, беше необходима структура на база данни, която може да съхранява цялата необходима информация.
В тази статия ще проектираме модел, който включва най-често срещаните елементи, намиращи се в MMO игрите. Ще обсъдим как да го използваме, неговите ограничения и възможните подобрения.
Въведение в моделите на данни за MMO игри
Днес има много много популярни MMO игри и те включват всякакви сценарии. Тук ще се съсредоточа върху стратегически игри като Ogame , Травиан , Спарта :Войната на империите и Imperia Online . Тези игри са повече за планиране, изграждане и стратегизиране и по-малко за директни действия.
MMO игрите са поставени в различни вселени, визуално са различни и използват повече или по-малко различни опции за игра. Все пак някои идеи са едни и същи. Играчите се състезават за локации, бият се за тях и създават съюз с (и срещу) други играчи. Те изграждат структури, събират ресурси и изследователски технологии. Те изграждат единици (като воини, танкове, търговци и т.н.) и ги използват за търговия със съюзници или за битка с противници. Всичко това трябва да се поддържа в нашата база данни.
Можем да мислим за тези игри като онлайн настолни игри с много индексирани квадратчета. Всеки квадрат може да има много различни действия, свързани с него; някои действия ще включват множество квадратчета – напр. когато преместваме единици или ресурси от едно място на друго.
Базата данни е разделена на пет основни области:
Players / Users
Alliances
Locations and Structures
Research and Resources
Units
Останалите седем негрупирани таблици са свързани с единици и описват позицията на единиците и движенията в играта. Ще разгледаме всяка една от тези области много по-подробно, като започнем с Играчи и съюзи .
Играчи и съюзи
Без съмнение играчите са най-важната част от всяка игра.
player
таблицата съдържа списък на всички регистрирани играчи, участващи в дадена игра. Ще съхраняваме потребителските имена, паролите и екранните имена на играчите. Те ще се съхраняват в user_name
, password
и nickname
атрибути съответно.
Новите потребители ще трябва да предоставят имейл адрес по време на регистрацията. Ще им бъде генериран и изпратен код за потвърждение, на който те ще отговорят. Ще актуализираме confirmation_date
атрибут, когато потребителят потвърди своя имейл адрес. И така, тази таблица има три уникални ключа:user_name
, nickname
и email
.
Всеки път, когато потребител влезе, нов запис се добавя в login_history
маса. Всички атрибути в тази таблица се обясняват сами. logout_time
е специфично. Може да бъде NULL, когато текущата сесия на потребителя е активна или когато потребителите напуснат играта (без да излизат) поради технически проблеми. В login_data
атрибут, ние ще съхраняваме данни за вход като географско местоположение на играч, IP адрес и устройството и браузъра, които използват.
Повечето MMO игри ни позволяват да си сътрудничим с други играчи. Една от стандартните форми на сътрудничество с играчите е съюзът. Играчите споделят своите „частни данни“ в играта (онлайн статус, планове, местоположение на техните градове и колонии и т.н.) с други, за да се възползват от съюзни действия и за чисто забавление.
alliance
таблицата съхранява основна информация за съюзите в играта. Всеки от тях има уникален alliance_name
които ще съхраняваме. Ще имаме и поле date_founded
, който се съхранява при основаването на алианса. Ако съюзът бъде разпуснат, ние ще съхраняваме тази информация в date_disbanded
атрибут.
alliance_member
таблицата свързва играчите с съюзи. Играчите могат да се присъединят и да напуснат един и същ съюз повече от веднъж. Поради това player_id
– alliance_id
двойката не е уникален ключ. Ще запазим информация относно това кога даден играч се присъединява към алианса и кога (ако) напуска в date_from
и date_to
полета. membership_type_id
атрибутът е препратка към membership_type
речник; той съхранява текущото ниво на правата на играчите в алианса.
Правата на играчите в алианса могат да се променят с течение на времето. membership_actions
, membership_type
и actions_allowed
таблиците заедно определят всички възможни права за членовете на алианса. Този модел не позволява на играчите да дефинират собствените си нива на права в алианс, но това може да бъде постигнато достатъчно лесно чрез добавяне на нови записи в membership_type
речник и съхраняване на информация за кои съюзи са свързани.
За да обобщим:стойностите, съхранени в тези таблици, са дефинирани от нас по време на първоначалната настройка; те ще се променят само ако въведем нови опции.
membership_history
таблицата съхранява всички данни относно ролите или правата на играчите в рамките на алианса, включително диапазона, когато тези права са били валидни. (Например той може да има разрешения за „начинаещ“ за един месец и след това „пълно членство“ от този момент нататък.) date_to
атрибутът е NULL, защото активните в момента права все още не са приключили.
membership_actions
речникът съдържа списък на всички действия, които играчите могат да направят в съюз. Всяко действие има свой собствен action_name
и логиката на играта е изградена около тези имена. Можем да очакваме стойности като „преглед на списъка с членове“ , „преглед на статусите на членовете“ и „изпращане на съобщение“ тук.
membership_type
речникът съдържа уникалните имена на групите за действие, използвани в играта. actions_allowed
таблицата присвоява действия на типовете членство. Всяко действие може да бъде присвоено на тип само веднъж. Следователно, membership_action
- membership_type
двойка формира уникалния ключ за тази таблица.
Местоположения и структури
Игровите локации са области, където играчите събират ресурси и изграждат структури и единици. Някои игри имат предварително дефиниран набор от възможни местоположения, докато други могат да позволят на потребителите да дефинират свои собствени местоположения.
В 3D пространство местоположенията могат да бъдат дефинирани с [x:y:z] координати. Ако една игра има предварително дефиниран обхват, тя може да не позволи на играчите да използват никое място извън диапазона [0:1000] за трите оси, така че сме ограничени до пространство 1000 * 1000 * 1000.
От друга страна, може би искаме да позволим на играчите да въвеждат точните координати на новото си местоположение – напр. [1001:2073:4] – и искаме играта да го обработи вместо тях.
Ще запазим списък с всички местоположения, използвани в екземпляр на нашата игра в location
маса. Всяко място има собствено име, но имената не са уникални. От друга страна, coordinates
атрибутът трябва да съдържа само уникални стойности. Координатите на местоположението се съхраняват като текстови стойности, така че можем да съхраняваме координати за 3D игри като [112:72:235]. Координатите за 2D игри могат да се съхраняват като <1102:98>.
В някои игри локациите ще имат определен брой квадрати, които се използват за настаняване на структури или единици. Ще запазим тази информация в dimension
атрибут, който е текстово поле. Измерението може да бъде просто брой квадрати в 2D или 3D мрежа. player_id
атрибутът съхранява информация за текущия собственик на това местоположение. Може да бъде NULL, когато локациите са предварително определени и играчите се състезават да ги заемат.
structure
таблицата съдържа списък на всички структури, които можем да изградим на различни места за игра. Структурите представляват подобрения, които ни позволяват да произвеждаме по-добри единици, да извършваме нови видове изследвания, да произвеждаме повече ресурси и т.н. Всяка структура, използвана в играта, има свой собствен уникален structure_name
. Някои възможни structure_name
стойностите са „ферма“, „рудна мина“, „слънчева централа“ и „изследователски център“.
Можем да очакваме всяка структура да бъде надграждана няколко пъти, така че ще съхраняваме и информация за текущото й ниво. Всяка надстройка подобрява изхода на структурите, така че произвежда повече ресурси или ни позволява да използваме нови функции в играта. Не можем да знаем предварително максималното ниво на надстройка, така че ще дефинираме всички неща, свързани с нивата (разходи, време за надграждане и производство) с формули. Всички формули, съхранявани в базата данни, са ядрото на механиката на играта и тяхното регулиране е от решаващо значение за баланса на играта и играта като цяло.
Такъв е и случаят с upgrade_time_formula
атрибут. Примерна стойност за това поле е “<ниво> * 30 минути” , където
В повечето случаи има изисквания, които трябва да бъдат изпълнени, преди играчите да предприемат определени действия. Може би трябва да завършим определено количество изследвания, преди да можем да изградим нови структури или обратно. Ще съхраняваме нивото на изследване, необходимо за изграждане на структури в prerequisite_research
маса. Взаимоотношенията и нивото на структура, необходими за започване на различни изследвания, се съхраняват в prerequisite_structure
маса. И в двете таблици външните ключове research_id
и structure_id
са сдвоени, за да образуват уникален ключ. level_required
атрибутът е единствената стойност.
Тези две таблици, prerequisite_research
и prerequisite_structure
, също формира ядрото на играта.
За всяка структура ще дефинираме списък с предпоставки:други структури и техните минимални нива, които играчите трябва да имат, за да започнат да строят. Ще съхраняваме тези данни в structure_required
маса. Тук structure_id
представлява структурата, която искаме да изградим; structure_required_id
е препратка към задължителната(ите) структура(и) и level
е необходимото ниво.
structure_built
таблицата съхранява информация за текущите нива на структура на дадено местоположение. upgrade_ongoing
атрибутът ще бъде зададен само ако надстройката е в ход, докато upgrade_end_time
атрибутът ще съдържа времева марка, след като надстройката приключи.
structure_formula
таблицата свързва структури и ресурси. Двойката външни ключове към тази таблица формира нейния уникален ключ. Тази таблица също има два текстови атрибута, съдържащи формули с <ниво> като параметър. Ще дефинираме тези формули, едната за разходи, а другата за генериране на ресурси, в базата данни. Те ще бъдат подобни на upgrade_time_formula
. Нуждаем се от тях, защото трябва да определим ресурсите, изразходвани за изграждането на всяка структура. Също така трябва да дефинираме производството на ресурси след надграждане, ако структурата генерира някакви ресурси (т.е. рудната мина ще произведе
Изследвания и ресурси
Изследванията (или технологиите) в игрите обикновено са необходими за създаването на други функции. Без определени нива на изследване не могат да бъдат построени нови структури или типове единици. Изследванията също могат да имат свои собствени изисквания. Едно от най-често срещаните е нивото на дадена структура, обикновено наричана „изследователска лаборатория“. Или може би играчите трябва да завършат определено ниво на изследване, преди да могат да започнат нови изследвания. Всички тези изисквания ще бъдат разгледани в този раздел. По-долу можем да намерим модела на данни за изследвания и ресурси:
research
таблицата съдържа списък на всички възможни изследователски действия в нашата игра. Той използва същата логика като structure
маса. research_name
атрибутът е уникалният ключ на таблицата, докато upgrade_time_formula
полето съдържа текстово представяне на формулата за изискванията за време за изследване с <ниво> като негов параметър. Всички ресурси, необходими за надстройки, са дефинирани в upgrade_formula
съхранени в research_formula
таблица.
Както при структурите, ние ще дефинираме списъка с всички други изследвания и техните нива, които трябва да бъдат завършени, преди да можем да започнем друг вид изследване. Ще съхраняваме тези данни в research_required
таблица, където research_id
представлява желаното изследване; research_required_id
е препратка към необходимото изследване и level
е необходимото ниво.
Изследването е свързано с отделни играчи, а за всеки играч – повторно проучване ch двойка трябва да съхраняваме текущото ниво на изследване на играча и всички текущи състояния на надграждане. Ще съхраняваме тази информация с помощта на research_level
таблица по същия начин, по който използвахме structure_built
таблица.
Ресурси като дърво, руда, скъпоценни камъни и енергия се добиват или събират и използват по-късно за изграждане на структури и други подобрения. Ще съхраняваме списък с всички ресурси в играта в resource
речник. Единственият атрибут тук е resource_name
поле и също така е уникалният ключ на таблицата.
За да следим текущото количество ресурси на всяко местоположение, ще използваме resources_on_location
маса. Отново двойка външни ключове (resource_id
и location_id
) формира уникалния ключ на таблицата, докато number
атрибутът съхранява текущите стойности на ресурсите.
Единици и движения
Ресурсите се използват за производство на единици. Единиците могат да се използват за транспортиране на ресурси, атака на други играчи или за общо ограбване и изгаряне.
Списъкът с видовете единици, използвани в нашата игра, се съхранява в unit
речник само с една стойност, unit_name
; този атрибут е уникалният ключ на тази таблица. Някои често срещани игрови единици са „мечоносец“, „боен крайцер“, „грифон“, „реактивен изтребител“, „танк“ и т.н.
Трябва да опишем всяка единица със специфични характеристики. Списък с всички възможни характеристики се съхранява в characteristic
речник. characteristic_name
полето съдържа уникална стойност. Стойностите в това поле могат да включват:„атака“, „отбрана“ и „хит точки“. Ще присвоим характеристики на единици с помощта на unit_characteristic
отношение. Двойката външни ключове на unit_id
и characteristic_id
формират уникалния ключ на масата. Ще използваме само един атрибут, value
, за да съхраните желаната стойност.
research_unit
таблицата съдържа списък на всички изследователски дейности, които трябва да бъдат завършени, преди да можем да започнем производството на даден тип единица. unit_cost
таблицата определя ресурсите, необходими за производството на една единица. И двете таблици имат уникални ключове, съставени от двойката външни ключове (research_id
или resources_id
комбиниран с unit_id
) и едно поле за стойност (cost
). и level_required
).
И сега, забавната част. Производството е забавно, но преместването на единици и предприемането на действия е още по-добро. Вече представихме unit
таблица, но ще я запазим тук, защото е свързана с други таблици.
Или единици са разположени на място, или се движат между локации. Добавяне на player_id
полето определя кой притежава местоположението или групата, която се движи между местоположенията.
Ако единиците просто са разположени на даденото място, ние ще съхраняваме това местоположение и броя на единиците, разположени там. За целта ще използваме units_on_location
таблица.
Когато единиците не са разположени, те се движат наоколо. Ще трябва да съхраним тяхната отправна точка и дестинация. Освен това трябва да дефинираме възможни действия по време на движения. Всички подобни действия се съхраняват в movement_type
речник. type_name
атрибутът е уникален, докато allows_wait
атрибут определя дали дадено действие позволява изчакване в точката на местоназначение.
Можем да преместим един тип единица, но в почти всеки случай ще преместим много единици от няколко различни типа единици. Тази група ще споделя общи данни и ние ще ги съхраняваме в group_movement
маса. В тази таблица ще дефинираме следните елементи:
- играчът, който инициира това действие
- типът на действие
- начална точка
- точката на дестинация
arrival_time
на дестинациятаreturn_time
до началната точкаwait_time
на дестинацията
return_time
атрибутът може да бъде NULL, ако това е еднопосочно пътуване, и wait_time
се определя от играча. Единиците, принадлежащи към група, се дефинират от стойности, съхранени в units_in_group
маса. Двойката външни ключове units_id
и group_moving_id
формира уникалния ключ на таблицата. Броят на единиците от един и същи тип в рамките на групата се определя в number
атрибут.
Всяко движение може да транспортира ресурси от едно място на друго. Следователно ще дефинираме връзка много към много между group_movement
и resources
маси. Освен първичния и външния ключ, resources_in_group
таблицата съдържа само number
атрибут. Това поле съхранява количеството ресурси, които играчите преместват от началната точка до тяхната дестинация.
В повечето случаи играчите могат да се обадят на други да се присъединят към тяхното приключение. За да подкрепим това, ще използваме две таблици:allied_movement
и allied_groups
. Един играч ще започне съвместно действие и това ще създаде нов рекорд в allied_movement
маса. Всички групи от единици, които участват в съюзни действия, се дефинират от стойности, съхранявани в allied_groups
маса. Всяка група може да бъде присвоена на свързано действие само веднъж, така че външните ключове формират уникалния ключ на тази таблица.
Този модел ни дава основната структура, необходима за изграждане на MMO стратегическа игра. Той съдържа най-важните характеристики на играта:локации, структури, ресурси, изследвания и единици. Освен това ги свързва, позволява ни да дефинираме предпоставките в базата данни и също така съхранява по-голямата част от логиката на играта в базата данни.
След като тези таблици бъдат попълнени, по-голямата част от логиката на играта е дефинирана и не бихме очаквали да бъдат добавени нови стойности. Почти всяка таблица има уникална стойност на ключа, или име на функция, или двойка чужди ключове. Промяната на характеристиките на единиците и формулите за производство/разходи ще ни позволи да променим баланса на играта в слоя на базата данни.
Как бихте променили този модел? Какво харесвате и какво бихте направили по различен начин? Кажете ни в секцията за коментари!