Ten-Hut. Про архитектуру кода #4
Гит проекта. Что планирую доделать и добавить. А также немного про сериализацию того, что в Юнити по умолчанию не сериализуется. В частности, сцен.
Собственно, вот гит. Предупреждаю, что задачу сделать красивый читаемый код я в данном проекте перед собой не ставил. Комментариев тоже нет. Поэтому местами тут что-то может быть довольно путано. Если руки дойдут, то потом отрефакторю, повыношу всё в методы с лаконичными названиями и т.д..
Перед началом работы над проектом я, помимо того, что успел реализовать, планировал сделать мультиплатформенность (ПК и андроид), второй язык (чтобы можно было переключать тексты между русским и английским) и лидерборды (через социальные сети).
В общем, буду постепенно это всё внедрять. Начну с языка, потом - управление под андроид. Ну и соцсети, как минимум, попробую.
И ещё вещь, которая осталась недоделанной - сериализация сцен.
Сцены в проекте загружаются аддитивно. Т.е. не как на начальных курсах по Юнити обычно рассказывают, что, мол, сцена - ну это типа один уровень в игре. Нет. Аудиоплеер лежит на своей отдельной сцене, панель здоровья - на своей отдельной сцене, панель, которая вылезает при проигрыше, - отдельная сцена. Сцены загружаются/выгружаются по необходимости, через методы вроде SceneManager.LoadSceneAsync. Штука удобная, позволяет отслеживать степень загрузки, выкидывает событие, когда загрузка закончилась, и ещё много всего полезного.
Встаёт вопрос, как задать те сцены, которые нужно загружать/выгружать в отдельных сегментах игры. На первый взгляд кажется, что всё просто. Создаём какой-нибудь GameSegmentsEnum, где перечисляем все глобальные состояния игры, т.е. TitleScreen, MainMenu, Gameplay, GameoverScreen и т.д. Делаем скриптабл-обжект с настройками загрузки сцен и кладём туда [SerializeField] Dictionary<GameSegmentsEnum, Scene[]>, где и отмечаем, какому сегменту какие сцены нужны.
Однако не тут-то было. Проблема А - Dictionary в Юнити по умолчанию не сериализуется. Проблема Б - сцены в редакторе и в билде загружаются по-разному. При попытке сбилдить проект, в котором вы через [SerializeField] положили куда-либо тип Scene, вы можете словить ошибку вида "Простите, но Юнити в душе не знает, что это за Scene такой, и вообще видит его впервые, так что хрен вам с маслом, а не билд". А чтобы всё заработало и сцена загрузилась, методу SceneManager.LoadSceneAsync нужно передать либо номер сцены в билде из Build Settings, либо string с путём к файлу сцены в папке.
Решается это всё, как обычно, либо собственными руками, либо поиском сторонних ассетов.
Для тренировки мне хочется закодить это собственноручно. Тем более что с Editor-кодом у меня всё довольно плохо, ну вот как раз и повод подучиться.
Итого задача номер раз - сделать Scriptable Object с сериализуемым Dictionary. Задача номер два - сделать так, чтобы соответствующий скриптабл-обжект-ассет выглядел в редакторе нормально. Задача номер три - сделать так, чтобы в этот Dictionary можно было в редакторе закинуть ассет сцены, и при этом чтобы в билде всё правильно определилось и работало.
Но пока решена только задача номер раз, т.е. готов Scriptable Object, выстраивающий Dictionary из двух массивов с SerializeField, и основную часть кода я для этого просто взял с сайта документации Юнити. Причём он написан так, что в процессе заполнения полей может выдавать ошибки, поэтому и его тоже стоит поправить:
Для решения задачи номер два нужно покопаться во всяких CustomPropertyDrawer-ах и т.п. А для решения задачи номер три нужно сделать так, чтобы во время сериализации-десериализации ассета типа Scene в скриптабл-обжект-ассете там сцена сохранялась не в виде того же ассета Scene, а в виде string с путём к сцене и её названием, т.е. тем, что потребуется в итоге в билде.
Пока же в проекте сцены в Dictionary обозначаются просто как их индексы из списка сцен в Build Settings.
Ну... на самом деле это всё, о чём я хотел рассказать. Заходите в гит, смотрите проект, кому интересно. Я открыт для отзывов, предложений и советов. А так - наверно всем пока, до следующего фестиваля.