Как посадить дерево: часть 2
EVALLИ так, минимальную инфраструктуру системных сервисов в игре я организовал в первой части. Сделал перемещение камеры и добавил прототип системы ввода. Помучался со вводом, но только потому, что сказал нейросети "Сделай систему ввода" и в итоге понятия не имел, как она работает (а точнее — почему не работает).
🌳 Пришло время сажать деревья! 🌳
В этот раз я подошел к задаче иначе. Вместо того, чтобы полагаться только на ИИ, я сначала сам подумал, как должна быть устроена фича "Лес", задавая нейросети уточняющие вопросы: "А что если сделать так или вот так?". Через пару часов в голове сложилась простая картина, но с одной ошибкой: изначально я допустил, что ForestSystem будет хранить ссылки на "вьюхи" (визуальные объекты) и модели. Это привело к тому, что ForestSystem зависела от ForestObjectView и второе — это 1000 моделей и 1000 вьюшек! Я осознал это в процессе создания системы и переделал архитектуру. На создание самой системы ушло еще несколько часов. Я ни разу не запустил плеймод!
Архитектура новой системы (MVVM* на уровне фичи):
ForestSystem (Модель):
- Это главный "мозг" системы лесов, который хранит все модели лесных объектов.
ForestSystemсодержитObservableDictionary из R3с моделями объектов, которые сейчас видны в камеру.- В
ForestSystemесть свойUniTask"апдейт", который срабатывает раз в 10 кадров для оптимизации. - В этом "апдейте" он проходит по всем моделям и добавляет те, чьи позиции попадают в область видимости камеры, в
ObservableDictionary. - Все модели загружаются из JSON-файла, который я создаю на отдельной редакторской сцене.
ForestViewSystem (ViewModel для View):
- Это "вью-модель" системы, которая подписана на изменения
ObservableDictionaryвForestSystem. - Ее задача — передавать позицию, тип, id (не "модель"!) из
ForestSystemвForestViewи обрабатыватьR3команды отView
ForestView (View):
- Это "вьюшка" системы, я бы сказал, даже "вьющище" 😃.
- Она загружает "префабы" через
IAddressableProviderи создает для каждого типа деревьев расширяемые пулы. - Когда
ForestViewSystemсообщаетForestViewо новой видимой модели,ForestViewдостает из пула нужную "вьюшку" и отображает ее. При этом самаForestViewне знает ничего о самой модели объекта; она получает только его id, позицию и тип, вForestObjectViewсамая "тупая" в списке, получает на вход команды и их выполняет - Когда
ForestViewSystemсообщаетForestViewо том, что модель объекта больше не в зоне видимости камеры,ForestViewпрячет "вьюшку" обратно в пул!
Таким образом, для системы отображения 1000 лесных объектов 8 типов, нужна 1001 модель (с учетом ForestSystem), 1 вью-модель (ForestViewSystem) и 81 "вьюшка" (вместе с ForestView) 😎.
Анимация деревьев
В старой версии игры каждое дерево состояло из трех спрайтов и анимировалось Animator'ом, что достаточно сильно влияло на производительность.
Решение:
- Сделать дерево из одного спрайта.
- Анимировать его с помощью шейдера, который помог создать ИИ. Теперь крона дерева красиво покачивается, как от ветра.
- Этот же шейдер помогает правильно отображать деревья по глубине: те, что находятся ниже по экрану, выглядят "ближе" к камере. Это дает эффект сортировки без дополнительных нагрузок.
Как теперь все работает ?
- Создание карты: Я создаю специальную сцену, где расставляем деревья с помощью компонента-метки. После расстановки данные сохраняются в JSON-файл.
- Запуск: При старте игры
ForestViewиForestSystemзапускаются вместе асинхронно, а затемForestViewSystem. ForestSystem: Загружает модели деревьев из файла и запускает свой асинхронныйUniTask"апдейт", который проверяет, какие деревья попали в область видимости камеры, и заполняет словарь.ForestView: Загружает префабы деревьев и создает для каждого типа пул из 10 объектов (всего 80 вместо 1000). Дальше она просто ждет команды отForestViewSystemForestViewSystem: Подписывается на изменения вForestSystemи сообщаетForestView, какие деревья нужно отобразить.

Результаты моего подхода:
Так как все анимируется шейдером, и все объекты используют один и тот же материал, я добился отличного результата:

Вот видео работы в редакторе:
Выводы:
Я доволен тем, что смог сам продумать прототип системы, особенно учитывая, что у меня немного опыта с MV* паттернами. Это показывает, как я вырос в знаниях и умениях. Создавая Forest System, я писал код более 20 часов, ни разу не запустив PlayMode! И после того, как все было написано и настроено, на запуск ушло меньше часа. Это доказывает, что использование правильных подходов и паттернов приводит к понятному и предсказуемому результату!
p.s. в итоге я "посадил" дерево спустя 2 недели !
немного приукрашено с фпс: корректно сравнивать 75 fps и 250 fps , 500+ при развернутой вкладке game view. MVVM конечно с оговорками, ForestViewSystem знает про View, но художник тут я и я так вижу 👨🎨