Как посадить дерево: часть 2

Как посадить дерево: часть 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'ом, что достаточно сильно влияло на производительность.

Решение:

  • Сделать дерево из одного спрайта.
  • Анимировать его с помощью шейдера, который помог создать ИИ. Теперь крона дерева красиво покачивается, как от ветра.
  • Этот же шейдер помогает правильно отображать деревья по глубине: те, что находятся ниже по экрану, выглядят "ближе" к камере. Это дает эффект сортировки без дополнительных нагрузок.


Как теперь все работает ?

  1. Создание карты: Я создаю специальную сцену, где расставляем деревья с помощью компонента-метки. После расстановки данные сохраняются в JSON-файл.
  2. Запуск: При старте игры ForestView и ForestSystem запускаются вместе асинхронно, а затем ForestViewSystem.
  3. ForestSystem: Загружает модели деревьев из файла и запускает свой асинхронный UniTask "апдейт", который проверяет, какие деревья попали в область видимости камеры, и заполняет словарь.
  4. ForestView: Загружает префабы деревьев и создает для каждого типа пул из 10 объектов (всего 80 вместо 1000). Дальше она просто ждет команды от ForestViewSystem
  5. ForestViewSystem: Подписывается на изменения в ForestSystem и сообщает ForestView, какие деревья нужно отобразить.
обертки не влезли


Результаты моего подхода:

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

БЫЛО / СТАЛО

Вот видео работы в редакторе:

На карте около 1000 объектов.


Вот так это выглядело в старом исходнике


Выводы:

Я доволен тем, что смог сам продумать прототип системы, особенно учитывая, что у меня немного опыта с MV* паттернами. Это показывает, как я вырос в знаниях и умениях. Создавая Forest System, я писал код более 20 часов, ни разу не запустив PlayMode! И после того, как все было написано и настроено, на запуск ушло меньше часа. Это доказывает, что использование правильных подходов и паттернов приводит к понятному и предсказуемому результату!



p.s. в итоге я "посадил" дерево спустя 2 недели !

немного приукрашено с фпс: корректно сравнивать 75 fps и 250 fps , 500+ при развернутой вкладке game view. MVVM конечно с оговорками, ForestViewSystem знает про View, но художник тут я и я так вижу 👨‍🎨


Report Page