Привет, Пикабу!
Я тут обещал какое-то время назад серию туториалов для геймдева, ну в общем вот первый пост)
Требования для урока:
1)Мозг
2)Умение читать ОЧЕНЬ ОЧЕНЬ ОЧЕНЬ много текста
3)Умение читать доки
4)c#
5)Json
6)Примеры будут на Unity, т.к. мой проект на нём, но про альтернативу для Unreal расскажу
StaticData. Что это? Зачем оно нужно?
В любом проекте чуть больше "Hello world" появляются объекты которые неплохо бы кастомизировать. Будь то параметры юнитов, оружия, да даже просто ящики разной массы для шутерков.
Если вы составляете карту руками, то вам ещё допустимо создать несколько шаблонов с захардкоженными параметрами и расставить их на сцене. (но всё равно не надо) А вот если вы захотите чуть более сложную архитектуру, или процедурную генерацию, то тут без подгрузки данных из кода не обойтись.
Первым порывом будет написать что-то такое:
\\код не мой, я просто разместил объяву
Код взят из проекта одного из школьников, у которых я веду проекты. По ушам за той код уже отхвачено)
obj1 = new Class();
obj.a = 1;
obj.b = 2;
obj2 = new Class();
obj2.a = obj1.a * 1.05;
obj2.b = obj1.b * 4;
Ну вы поняли...
Это пример того как делать НЕ надо. В приличном обществе любую константу которая влияет на геймплей (а особенно на геймдизайновую его часть) надо бы хранить снаружи кода, чтобы просто изменив поле можно было бы подправить баланс игры.
Опционально, если при инициализации ваш клиент пытается скачать таблицу из облака и обновить баланс игры. Т.е. для обновления баланса игроку надо будет выкачать пару МБ, а не новый билд весом пару сотен метров (некоторые движки не позволяют патчить части себя, а только полностью менять билд).
Так что такое StaticData? Это эта самая таблица, которая иницалзирует сама себя и хранит все значения которые не зависят от действий игрока. А главное, к ней можно обращаться в любой момент.
Ну а теперь ОДНА ИЗ ВОЗМОЖНЫХ реализаций этого.
Unreal engine - Класс Data Table. Идите гуглите) Таблички можно создавать прямо в редакторе, а можно подгружать из csv. Очень удобно и всё такое. И мануалы простые легко гуглятся.
Unity - Тут я собственно на примере буду рассказывать как оно устроено и работает. На примере своего проекта.
Сначала немного о базовых механиках построения таблиц:
KeyName - наше основное значение. Это id. Уникальная строковая переменая, по которой всегда можно найти в StaticData объект.
Каждый лист таблицы занимает или список классов (строка - экземпляр\шаблон объекта), Либо один цельный объект. Примером второго является например Settings. Не настройки игрока, а базовые параметры игры. Для кода сверху, это были бы масса и радиус земли.
Имена переменных должны совпдать с аналогичными переменными в вашем коде.
Итак, как же у меня в игре устроен ОТРЯД СОЛДАТ, а вот так:
Лист называется SquadArchtype
keyName - ключевое имя отряда (по нему например более глобальный класс Company (армия) тащит свои составляющие. Не буду показывать, чтобы не перегружать вас) Дальше идут типы отряда, 6 юнитов, флаг может ли этот отряд быть использован игроком и сила для расчёта мощи армии противника.
Давайте внимательнее посмотрим на юнитов (лист UnitArchtype)
Всё ещё куча ключевых слов и никаких параметров. Заметьте по ключевым словам можно догадаться о чём тут вообще идёт речь! Тут можно заметить поля правой и левой руки, доспеха и активируемого предмета. baseUnit это класс базовых характеристик (а-ля раса, но не совсем). Взглянем например на оружие. (Weapon)
Ого чиселки! Но урона у оружия нет) Вы же не думали что всё так просто? В моей архтектуре удар оружием не отличается от фаербола. Это всё активные способности, некоторые могут иметь или не иметь урон. Глубже в таблицу уходить не будем, думаю смысл понятен)
НО:
Тут заметим интересную вещь. Изменилсь цвета. Зелёный - вотчина геймдизайнера (в данном случае меня) это баланс. Синяя - вотчина художника. Вот например в sprite записаны имена спрайтов которые подгружаются в соответсвующее оружие. О том как и зачем - в следующих урока, но поверьте, удобно)
Аналогичная архитектура записанная в коде заняла бы сотни строк, а меня баланс стало бы вообще нереально.
Самые внимательные могли заметить, что табличка хранится в гуглдоке. Итак, как же нам её оттуда достать.
Можно написать свою хорошую систему (так например у меня на работе, очень мощная штука, но такую систему можно и саму по себе продавать, зачем вам тогда игры). Дома я пользуюсь беслпатным плагином
https://assetstore.unity.com/packages/tools/utilities/google...
Что он делает - выкачивает гуглдок в Json и сохраняет в папке Resurces (для тех кто не шарит, в юнити это такая папка специальная, файлы откуда всегда уодят в билд, даже если на ни нет явных ссылок). Каждый листик сохраняет отдельно. Тут есть свои плюсы и минусы, но в большинстве случаев нам пофигу.
Качаем, ставим, читаем доки по заполнению таблиц, пользуемся.
Прочитали? Ну и славно, едем дальше.
Есть два варианта - простой и сложный (внезапно)
Сложный - создаём класс с namespace которое всем доступно, инициализируем и тягаем оттуда инфу.
Простой - создаём GameObject на сцене, вешаем на него скрипт StaticData, он при запуске делает тоже самое. Если объекту нужны данные он его пинает и тащит данные.
Чтобы объект загружался из Json, он должен быть серриализуем.
Вот примерно так выглядит класс Weapon (табличка сверху).
Теперь как же его собственно выцепить из таблички? Ну вот примерно так:
Тут сейчас будет немного магии, специально для юнити. Кому не интересно, листают до следующего перерыва на кофе.
Json - в данном случае просто строковая переменная.
LoadResourceTextFile - вспомогательная функция для выкачки текста. вот она:
Странное добавление по бокам - Json встроенный в юньку малось туповат, ему надо явно указывать что это список объектов, а не цельный объект.
Weapons - вспомогательный класс для серриализации. Требуется из-за того-же несовершенства Json. Вот он:
weapons - список оружий с которым позже мы будем уже работать. (точнее сам список в Weapons.list, но не суть).
Итак, мы почти у конца! Что же с этим делать? Ну для начала надо бы написать инициализатор который подтащит по ключевым именам (строкам) уже готовые и ранее серрилизованные объекты.
Легчайше!
Ну а вот собственно например инициализатор оружия:
Собсно что тут делать - дело ваше. У меня например только подтаскиваются пассивные и активные убилки из той же самой StaticData.
Итоги:
Мы получили МОЩНЕЙУЮ систему для хранения и доступа к данным. Которую из-за гуглдока также сложно потерять (ну если вы вдруг не умеете пользоваться гитом).
Пусть это не самый эффективный и аккуратный вариант реализации, но даже он сэкономит вам ТОННЫ времени) Удачи, до встречи в следующем туториале!
P.S. Да, наконец то! Думал у меня пальцы отвалятся пока пишу! Фуууух)