Избягване на тенденцията да се разчита единствено на готвени данни за управлявани от данни елементи на играта.

Когато работех върху Starhawk, имахме критична функция в играта, която позволяваше внедряването на „актуални корекции“ за актуализации на данни (общо взето корекции на играта/балансирането), без да се изисква основна корекция, която би да преминете през едноседмичния (най-малко) процес на корекция и проверка на качеството на Sony. Това беше първият ми опит с актуализации на игри, които не изискваха пълна двоична актуализация.

Малко след това работих върху мобилни игри в продължение на няколко години и, както съм сигурен, че много хора знаят, всяка възможност за заобикаляне на процеса на преглед на iOS App Store е прекрасно - е, необходимо - нещо, което трябва да направите. И така, за нашия екип, ние обработвахме всички данни за играта чрез обширно количество JSON данни за дефиниции на нива, профили на играчи, настройки, данни за играта и балансиране, задействане на специални събития и сделки и така нататък и така нататък . Вярвам, че също така съхранявахме данни за играчи на защитен сървър/база данни като JSON данни, но това не беше и все още не е моята област. За щастие.

Цели за данни за играта и операции на живо

Обичам да съхранявам възможно най-много данни за играта в текстови файлове с данни (по-специално JSON файлове). И когато се позовавам на данни за играта, имам предвид неща като механични данни (които до голяма степен са просто списък с препратки към други файлове с данни и пътища на активи на играта), шаблони на механични части, които се използват за процедурно генериране на елементи в играта, игра световни параметри, профили и настройки на играчи и т.н. Същите тези формати се използват и за съхраняване на данни, които се създават в играта; въпреки че даден елемент може да бъде генериран от един или повече шаблони за данни, той в крайна сметка трябва да бъде записан и съхранен някъде. Тези файлове всъщност никога не се докосват извън това извън запазването/зареждането.

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

Тъй като това са всички основни текстови файлове, до които имам достъп, мога лесно да ги променя и просто да ги опреснявам в играта. Възможността за лесно модифициране на данните за играта в редактора и навън с просто опресняване на игри е просто прекрасна, но също така е била в основата на разработването и дизайна на игрите от векове (наречени геймплей/съдържание, управлявано от данни). Unreal Engine 4 позволява целия този работен процес, но в един момент съдържанието на играта трябва да бъде пакетирано и, доколкото ми е известно, отвъд това те се съдържат в двоични пакети. И едно нещо, което харесвам в моите данни за играта е, че винаги е лесно да се стигне до тях, да се променят, зареждат и т.н. по време на разработката, независимо дали е свободна компилация или пакетирана компилация. Нещо, с което също свикнах след няколко години в мобилните игри, е да не се налага да разчитам на пълна двоична актуализация/корекция на игра, за да направя промени, особено ако всичко това е малко повече от пропуск за настройка или актуална корекция за недвоична корекция. Бих предпочел играчите просто да заредят играта, да имат период от десет-двадесет секунди за актуализиране и просто да имат всички актуализирани настройки. Целият този процес е и сърцевината на всяка настройка за „операции на живо“ след стартиране, с която съм работил: актуализиране на някои файлове в доверен CDN, играчите ги изтеглят, когато влизат онлайн, и сега имате 24-часово специално събитие с уникални елементи.

И тъй като започвам тази статия, наистина се надявам, че първият коментар някъде не е „чакайте, вие не сте използвали просто ‹x›?“, разкривайки критичен и напълно уместен набор от функции това би било невероятно полезно. Но не мисля, че това е така в това, което предстои.

Изненадващо осъзнаване

Когато за първи път започнах да работя с Unreal, правех всичките си прототипи в чертежи. Както отбелязах преди: това не се получи добре въобще. Бях на предположението, че чертежите са предназначени да бъдат хубав интерфейс над, по същество, скриптове. И че тези чертежи могат лесно да бъдат променени/актуализирани динамично след изграждането на проект.

След като написах това, осъзнах, че трябва да отбележа: това беше много в началото на времето ми с UE4 (и никога не бях използвал предишна версия на Unreal Engine).

Както и да е, да, така че: не. Това изобщо не е начинът, по който чертежите работят; всъщност е точно обратното: при готвене на съдържанието на проект чертежите всъщност се вграждат в C++ код – потенциално най-ниското стъпало на стълбата на лесно актуализираните данни за играта. И така, наистина тръгна в различна посока, отколкото очаквах.

Имаше доста дълъг период от време след Blueprintpocalypse 2017, който трябваше да прекарам, за да създам най-основната кодова база, необходима, за да започна сериозно работа по действителната игра. И след това установяване на основите на критичните актьори/компоненти/и т.н. И точно след този първоначален етап на разработка започнах да търся суров (несготвен. разбрахте. защото… добре… съдържанието се готви? мълча.) начин за поддържане на данни за играта, конфигурации, локални профили и други подобни неща, които не Не изисква готвенето да се използва от времето за изпълнение на играта.

Въпреки желанието ми просто да премина към JSON за данни за играта, исках да видя какви са конвенционалните/препоръчителните практики за UE4 за дизайн и разработка, управлявани от данни. Склонността ми беше да използвам таблици с данни, като се има предвид, че те са обхванати в документация, която е буквално озаглавена „„Елементи на играта, управлявани от данни““. И звучеше, добре, включваше Excel, така че не звучеше страхотно, но беше нещо. И тогава го разгледах и открих, че можете да манипулирате данните външно, но в крайна сметка ще трябва да бъдат импортирани в UE4, за да бъдат използвани. Можете да го експортирате по-късно, ако е необходимо, но в крайна сметка трябва да се импортира отново. И накрая сготвени.

Така че, да. Увиеееее.

Натиснете X за „JSON!“

да Поне веднъж на ден, когато вътрешно мисля за JSON, мигновено чувам ДЖЕЙСЪН! JAAAASON! ДЖЕЙСЪН! в главата ми. Както и да е, да, хареса ми да работя с JSON файлове поради тяхната простота или просто навик, така че след това се заех да измислям как да направя това да работи. За щастие открих, че UE4 има Json и JsonUtilities модули!

И така, проверих документацията след бегъл поглед към изходните файлове. А документацията за Json и JsonUtilities беше... Е. Беше това, което виждате. И в случай, че някой прочете това след година или нещо подобно и то се промени, позволете ми да ви информирам за бъдещите поколения: няма много за гледане.

Това каза, че източникът не беше сложен, за да обгърна главата си. Прилагането му на практика обаче беше друга история. Първият ми тест на функционалността на модулите беше да сериализирам екземпляр на моя механичен актьор. И успях да го накарам да работи доста бързо и лесно! И ако очаквате „но…“ да последва това твърдение… … … Да, има но:

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

След малко ровене — и доста голямо количество опити и грешки — в крайна сметка стигнах до точката, в която, докато се придържах към структури, състоящи се единствено от доста прости типове данни, можех да използвам помощните програми за сериализиране на UE4, за да лесно сериализира и десериализира данните на структурата.

Използването на тази структура от данни в детайлите на останалата част от кода на играта обаче не е толкова просто. C++ с UE4 не е изцяло стандартен C++. Структура, за да бъде разпозната от Unreal Header Tool (и Unreal Build Tool), трябва да бъде обозначена с макроса USTRUCT. И за разлика от стандартния C++, USTRUCT struct не е "основно" същото като клас. Предназначено е (и стриктно се прилага) да бъде структура от основни данни, които не е необходимо да бъдат внимателно управлявани от събирача на отпадъци на двигателя. Ставам малко размит относно спецификата, тъй като не съм работил по тези неща от известно време, а също и работата върху всички области на играта има тенденция да замъглява спецификата на работата, извършена преди седмица или две; преди месец е просто много твърде далеч назад, за да го обмисляте.

Накратко: за да мога наистина да използвам данните, които се сериализират/десериализират чрез USTRUCT, реших по същество да създам почти въглеродно копие UCLASS (с някои трансформации/настройки, възникващи по време на прехвърлянето в някои случаи). И след като този UCLASS е пълен с възхитителни данни, той може да се използва навсякъде по предназначение.

Аз подхвърлих същност (вижда се и по-долу) на по-стара версия на моята структура от данни на мех част от най-високо ниво, която съществува в моята кодова база (когато слизате в дървото, тя бързо става повече плътен). Тази същност също използва моите абсолютни любими, макар и напълно грозни, макро набори, които някога съм създавал: „генераторите на макроси за достъп“. Това не е нищо повече от пряк път за генериране на основни инструменти за достъп до UCLASS на структура от данни (така че не изцяло за разлика от свойствата на C#), но беше удобен начин за намаляване на дефиницията и премахнете колкото е възможно повече място за грешки при внедряването. Тази частична структура от данни на високо ниво служи по същество като пра-пра-прародител на по-специфична частна логика, но всяко дете е отговорно само за управлението на собствените си данни; всеки родител на това дете ще се грижи за неговите данни и родителят на този родител ще се грижи за неговите данни и т.н.

Както и да е, да, така че това е същността - на много основно ниво - за това как в крайна сметка се справих с базиран на текст дизайн/разработка, управлявана от данни. Може да не е (и всъщност се надявам, че не е) най-доброто или най-елегантното решение, но постига това, което искам: външни файлове с данни, които не изискват готвене, за да бъдат използвани от играта; въпреки това трябва да се уверите, че всички файлове с данни, които са необходими за готов проект за игра, са включени в получените компилации на проекта. Освен ако не искате просто да запазите всичко на сървър и да го изтеглите при стартиране, което мога да направя и аз, но не искам да принуждавам играчите, които влизат за първи път, да се налага да влизат онлайн, за да влязат дори в играта, така че „ начален набор” от данни е включен в компилациите.

Освен това не мога да хвърля целия си модул за сериализиране на JSON, но включих много, много проста (но супер полезна) обвивка за основни операции: JoySerializationManager.h и JoySerializationManager.cpp.

ЗАБЕЛЕЖКА: Пренебрегвам много сложности, които съществуват като част от цялата тази система и настройка; отчасти защото това не е най-секси темата за писане и не знам дали някой изобщо ще види тази бележка. Но също така и защото беше наистина досадно и донякъде отнема много време за сортиране, така че не съм 100% уверен, че решението, което имам, е правилното. Не обичам да разпространявам лъжи. Добре. В този момент в този контекст.

Допълнителни функции и бъдеща работа

Функции за лесна употреба („Качество на живот“).

Обикновено държа цялата си JSON файлова библиотека отворена във VS Code през цялото време, тъй като това е най-любимият ми редактор за работа, която не се извършва в C/C++/C#. Ако трябва да променя настройките на играта или да настроя балансирането на механично оръжие или краката му (понякога променям краката), просто alt+tab във VS кода, правя промяната и се връщам на работа.

Това, което веднага беше очевидно да добавя към моята кодова база след ден-два правене на това, е възможността редакторът да гледа (определени директории на) JSON файлове и при промяна автоматично да презарежда файла.

И аз казвам определени директории, тъй като има някои промени във файловете, които не искам просто да се презареждат волю или неволю. Ако съм в сесия, направете промяна в зареждането на механизъм, не искам да влизам отново с alt+tab и да ми вземат краката, защото съм написал нещо грешно и след това се срива и тогава вероятно ще плача много . И така: повечето директории. Възможността за презареждане на механично зареждане по средата на сесията обаче е удобна, затова добавих конзолна команда за обновяване на текущия конфигурационен файл или зареждане на различна конфигурация. Механизмът е изцяло пресъздаден в код, но поради излишък от итерации и раздразнение, не знам дали някога съм създавал по-грациозно отказващ и възстановяващ се клас в живота си. Механичният код е просто машина. да Pun’d.

Сървъри и сигурност

Както споменах, възможността за изпращане/получаване на JSON данни към/от сървър е изключително важна; възможността да актуализирате файлове с данни от страна на сървъра и след това да разчитате на клиента на играта да прави заявки и да извлича актуализациите при стартиране/онлайн връзка, в крайна сметка е цялата цел на начинанието.

Има въпрос за сигурността на тези файлове, което, разбира се, не е област, в която съм експерт или дори начинаещ, но няколко „членове на екипа“ на Joy Machine (няма пари да платя на никого и затова никой работи активно — с изключение на моя главен оперативен директор и финансов директор, но те имат допълнителни предимства — но все още помагат при планирането/мозъчната атака/чудесни са) започнаха да проучват шепа възможности. Ще пиша за това, когато ми го кажат. Може би. Може да е криптирана статия.

Краят на играта

Моята мечта от мечти, извън операции на живо и горещи корекции и други подобни, е да управлявам „библиотеката с активи“ на играта чрез прости актуализации на JSON файлове. И не, нямам предвид магическо прехвърляне на мрежи, текстури и карти и така нататък, и така нататък. Това би било глупаво. Искам да кажа, че мога да поддържам библиотека с активи от идентификатори на активи („кратки имена“) към мрежи и текстури и други подобни, и този идентификатор е картографиран към път към актива, който краткото име представлява (така че е по-скоро регистър). Записите в библиотеката с активи могат да се добавят и изтриват и всичко това, но те могат също така — ако желаете — да актуализират актива, към който се отнася краткото име, в случай че един актив е премахнат, но краткото име все още е приложимо за нещо, което взема своето място. Нищо от това не изисква промяна на друго място, просто ще работи.

И също така си струва да се отбележи: това е страхотно на практика, но също така е важно да не правите глупости и да не оставяте библиотека с активи с куп препратки към един актив, който съществува завинаги. Идеята е, че за всяка действителна актуализация/корекция библиотеката се почиства, възстановява и преразпределя – и като част от този процес на изграждане, тя актуализира всеки файл с данни, който използва идентификатор, който скоро ще бъде остарял, ако е необходимо. И, не, възстановяването не е най-бързият процес в света, но не е ръчно, така че ми харесва.

Отново: мечта за мечти, но наистина очаквам с нетърпение да видя дали в крайна сметка мога лесно да добавя напълно „ново съдържание“ към играта с добавянето на няколко нови конфигурации на части, състоящи се единствено от предварително съществуващи активи, но сглобени с помощта на различен набор от правила (даден част е изградена от подмножество мрежи/материали, за да се формира действителната „част“) за различни цели, без потребителите дори да осъзнават, че е настъпила промяна. Въпреки това, не ми харесва идеята за невидими промени, така че бих включил постоянен „дневник на промените“ на видно място в потока на потребителския интерфейс, за да могат играчите да претърсят, ако желаят.

В заключителната

Както казах в началото, едновременно се надявам и не се надявам, че някой веднага ще каже „ХЕЙ, ТИ НЕ ЗНАЕШ ЗА ‹X›?“ и съсипва нощта ми, но независимо от това системите на място в момента вече работят чудесно, така че не мога да се оплаквам много. И, за разлика от Blueprintpocalypse, вероятността промяна на кода да доведе до срив на JSON файл VS Code всеки път, когато бъде отворен, е... Ниска.

Но всичко това се прави, за да се доближим все повече и повече до целите за системите, които искам да завърша както за Steel Hunters, така и за бъдещи проекти; Почти непрекъснато оценявам работния процес, ефективността и използваемостта за ВСИЧКИ НЕЩА (също така правя възможно най-много, за да намаля човешката грешка при работа с голямо количество данни в даден момент или много, много дълга нощ) и този манталитет всъщност вече дава някои наистина страхотни неща. Дори понякога това да означава още един рефакторинг на нещо. Това не се случва толкова често, колкото вероятно го казах. Не толкова често. Случва се. И: плач.

Както и да е, ето екранна снимка от една от поредицата „скици“ на високо ниво на оформление, които направих преди седмица или две: