В Интернете очень мало информации об архитектуре игр, много узкоспециализированной информации, подходов и закономерностей, но не хватает общего взгляда сверху. Этот доклад предназначен как для начинающих программистов, не знающих с чего начать, так и для опытных программистов, желающих сравнить свои решения с другими.
How NOT to do showcase events: Behind the scenes of Midnight Show / Andrew Ko...
Архитектура для мобильных игр - с чего начать и популярные решения / Евгений Дубовик (Kefir)
1. АРХИТЕКТУРА ДЛЯ МОБИЛЬНЫХ ИГР –
с чего начать и популярные решения.
Докладчик: Евгений Дубовик, Lead developer(Kefir studio)
2. О ЧЕМ ЭТОТ ДОКЛАД?
ПОЧЕМУ ОН МОЖЕТ БЫТЬ ИНТЕРЕСЕН?
В интернете очень мало информации про то, как подойти к построению
архитектуры игрового приложения, очень много информации о критичных
кусочках, но нет общего виденья, нет начального импульса, все книжки по
архитектуре очень стары и довольно сложные, их лучше понимаешь, когда у
тебя уже есть некий опыт за плечами. Плюс даже опытные специалисты часто
принимают неверные и неоптимальные решения.
Этот доклад может быть интересен как и новичкам, которые пробуют «в
архитектуру», так и более опытным специалистам, для которых некоторые
пункты могут интересны в силу того, что на архитектуру можно и нужно смотреть
не только глазами разработчика.
3. ЧЕМ ИГРОВАЯ АРХИТЕКТУРА ОТЛИЧАЕТСЯ
ОТ АРХИТЕКТУР ДРУГИХ ПРИЛОЖЕНИЙ
Очень много изменений - от прототипа до софт лонча вводные
данные могут сильно поменяться, из архитектуры могут пропадать
целые блоки. Например в одном из проектов мета + мач3 был
функционал строительства зданий. Размещение, апгрейды и так
далее. В итоге от строительства полностью отказались, от прямых
апгрейдов тоже, в итоге мета сместилась исключительно в
сюжетную историю с небольшой кастомизацией объектов.
4. О ЧЕМ БУДЕМ ГОВОРИТЬ
1. Почему на большинстве проектов свои уникальные архитектурные решения,
и зачем вообще разбираться в архитектуре приложения
2. Что такое архитектура приложения
3. Заинтересованные лица
4. Объективные требования к архитектуре
5. С чего начать - описание ключевых сущностей/функционала, из чего состоит игра?
6. Как не переинженерить?
7. Связи, объекты, данные, что делать? Популярные подходы к построению архитектуры:
Service locator, Abstract service locator,
MVC family + IoC DI, ECS, Components and etc.
8. Бывают ли проекты с хорошей архитектурой?
5. ЧТО ПОЧИТАТЬ НА ТЕМУ
КНИГИ:
• Domain-Driven Design Eric Evans
• Clean Architecture Robert C. Martin
• Code Complete Steve McConnell
• Design Patterns: Elements of Reusable Object-Oriented Software (GOF)
• https://martinfowler.com/articles/injection.html
• https://martinfowler.com/architecture/
• https://metanit.com/sharp/patterns/1.1.php
6. ПОЧЕМУ НА БОЛЬШИНСТВЕ ПРОЕКТОВ СВОИ
УНИКАЛЬНЫЕ АРХИТЕКТУРНЫЕ РЕШЕНИЯ
1) В Unity есть проблема с восстановлением состояния игры из данных, GameObjects на
которых куча компонентов – это сложно сохранить, и еще сложнее восстановить, всё равно
придётся писать модели, которые описывают состояние объектов/игры, фабрики/кастомные
решения.
2) Компоненты в Unity - это и системы/сервисы, и данные, и представление.
Сложно разделить функционал, вычленить общий, предоставлять доступ различным
сущностям.
3) В Unity нет дефолтного решения для инъекции зависимостей, большинство доступных
решений относятся к bad practice.
4) Большинство программистов имеют .NET бэкграунд и привыкли решать вопросы в рамках
MVVM, MVP, MVC
7. ЗАЧЕМ ВООБЩЕ РАЗБИРАТЬСЯ
В АРХИТЕКТУРЕ ПРИЛОЖЕНИЯ
Ответ очень простой – чем лучше вы понимаете текущую
архитектуру, тем быстрее вы погружаетесь в проект, тем
качественнее вы принимаете решения, связанные с функционалом.
8. ЧТО ТАКОЕ АРХИТЕКТУРА ПРИЛОЖЕНИЯ
Архитектура - это базовая организация системы,
воплощенная в ее компонентах, их отношениях между
собой и с окружением, а также принципы,
определяющие проектирование и развитие системы.
[IEEE 1471] • В этом стандарте также определяются
следующие термины. связанные с данным
определением:
Система - это набор компонентов, объединенных для
выполнения определенной функции или набора
функций. Термин "система" охватывает отдельные
приложения, системы в традиционном смысле,
подсистемы, системы систем, линейки продуктов,
семейства продуктов, целые корпорации и другие
агрегации, имеющие отношение к данной теме.
Система существует для выполнения одной или более
миссий в своем окружении. [IEEE 1471]
Окружение, или контекст, определяет ход и
обстоятельства экономических, эксплуатационных,
политических и других влияний на систему. [IEEE 1471]
Миссия - это применение или действие, для которого
одно или несколько заинтересованных лиц планируют
использовать систему в соответствии с некоторым
набором условий. [IEEE 1471]
Заинтересованное лицо - это физическое лицо, группа
или организация (или ее категории), которые
заинтересованы в системе или имеют связанные с ней
задачи. [IEEE 1471]
http://www.iso-architecture.org/ieee-1471/docs/all-about-ieee-1471.pdf
10. ОБЪЕКТИВНЫЕ ТРЕБОВАНИЯ
К АРХИТЕКТУРЕ
• Расширяемость/изменяемость (это ключевой пункт)
• Наличие необходимых модулей и понятных связей
• Удобство и понятность для всех участников
• Минимум бойлерплейта (дешевая «развертываемость» кода)
• Отсутствие очевидных недостатков (большой стек необходимых
технологий или много нетривиальных знаний, необходимых для
проекта (например в одном проекте нужно было прописывать
классы в 4х файлах, чтобы они заработали как надо)).
11. ОБЪЕКТИВНЫЕ ТРЕБОВАНИЯ
К АРХИТЕКТУРЕ
• Минимальная сложность.
В силу только что описанных причин главной целью проектирования должна быть
минимизация сложности. Избегайте создания «хитроумных» проектов: как правило, их
трудно понять. Вместо этого создавайте «простые» и «понятные» проекты. Если при работе
над отдельным фрагментом программы проект не позволяет безопасно игнорировать
большинство остальных фрагментов, он неудачен.
• Простота сопровождения.
Проектируя приложение, не забывайте о программистах, которые будут его сопровождать.
Постоянно представляйте себе вопросы, которые будут возникать у них при взгляде на
создаваемый вами код. Думайте о таких программистах как о своей аудитории и
проектируйте систему так, чтобы ее работа была очевидной.
12. ОБЪЕКТИВНЫЕ ТРЕБОВАНИЯ
К АРХИТЕКТУРЕ
• Слабое сопряжение.
Слабое сопряжение (loose coupling) предполагает сведение к минимуму числа соединений
между разными частями программы. Для проектирования классов с минимальным числом
взаимосвязей используйте принципы адекватной абстракции интерфейсов, инкапсуляцию и
сокрытие информации. Это позволит максимально облегчить интеграцию, тестирование и
сопровождение программы.
• Расширяемость.
Расширяемостью системы называют свойство, позволяющее улучшать систему, не нарушая
ее основной структуры. Изменение одного фрагмента системы не должно влиять на ее
другие фрагменты. Внесение наиболее вероятных изменений должно требовать наименьших
усилий.
13. СОВЕТ 1 – От общего к частному
Прокрутите в голове, что вам нужно для проекта, подумайте о
самых сложных моментах/узких местах. Какие технологии в целом
будут использоваться, будет ли сетевая часть, откуда будут
грузиться данные. Если нет понимания, то просто выпишете
название функционала, который вам нужен - персонажи, спаун
персонажей и тд.
14. Функции/сущности, которые есть почти в
каждом мобильном проекте
• Game Controller/Core/Boot
• Player
• Characters/Scene actors
• Input
• Scenes controller
• UI
• Sound
• Shop
• Resources
• Abilities
• Inventory
• Video advertising
• Statistics
• Tutorial
• Quests/Scenarios
• Save
• Configs/Descriptions/
Repositories
• Localization
17. СЕРВИСЫ
Composition over inheritance
Когда мы начинаем детализировать функционал игры, мы
сталкиваемся с проблематикой большой ответственности, когда
одна сущность умеет слишком много всего, а данные, с которыми
оперирует сущность, слишком сложные или имеют размытые
признаки. Любая сущность в игре может начать обрастать
функционалом.
Ответ – композиция и сервисы. Делегируйте часть функционала
отдельным сущностям, которые решают/обслуживают конкретный
функционал с конкретными данными.
Также советую присмотреться к паттерну Proxy
19. ОБОБЩЕНИЕ
интерфейсы и дженерики, вот наш ответ
Хорошая практика – описывать функционал в интерфейсе. На
каждый функционал, лучше держать свой отдельный интерфейс,
это принцип interface segregation principle, из всем известного SOLID.
Если ваша сущность содержит в себе признаки разного
функционала – реализуйте несколько интерфейсов, например,
золото - это может быть и айтем в инвентаре игрока, и представлять
ресурс. Что может уметь ресурс? Изменять значение (начисляться
например), иметь тип, количество, содержать какие-то
специфичные операции для проекта.
20. ПОДХОД – ДЕТАЛИЗАЦИЯ «СНИЗУ»
Часто бывает такой момент, когда ты прописал весь функционал, но не
получается соотнести конкретную реализацию/сущность к текущей
схеме/иерархии, например персонаж. У персонажа есть данные -
здоровье, скорость, имя. Он как-то должен появляться на сцене в виде
какого-то отображения/представления, в какой-то панели должна
рисоваться иконка данного персонажа, на головой хп бар и имя. На
персонаж должны как-то воздействовать объекты сцены, а также игрок
посредством инпута/UI. Персонажа можно достать из сейва.
21. ПОДХОД – ДЕТАЛИЗАЦИЯ «СНИЗУ»
Главное задавать правильные вопросы – как UI узнает, что за иконка
у персонажа? В каком виде она хранится (как спрайт, как айди
спрайта из репозитория)? Как иконка в целом появляется у
персонажа? Где заполняют эти данные?
Можно и нужно детализировать весь функционал нижней сущности,
например, добавить функционала атака, и тогда у нас появляется
связь с другим объектом Character, который может получать урон. И
соответственно мы дополняем, что у нас помимо атаки появляется
еще и понятие - урон.
22. ПОДХОД – УДОБНАЯ РЕАЛИЗАЦИЯ
Решите для себя, как и насколько удобно было бы пользоваться
например спауном персонажей. Пропишите удобный способ
взаимодействия с этим функционалом. Все необходимые
вычисления спрячьте под капотом.
23. КАК НЕ ПЕРЕИНЖЕНЕРИТЬ?
Очень часто можно услышать мнение - это оверинжиниринг, или -
это оверхэд. Обычно под этим подразумевают избыточное
решение, которое или очень сложно решает текущие задачи (этим
сложно пользоваться), или решает будущую проблематику с
которой программист планирует столкнуться. А может и не
столкнуться. Решая еще не возникшие проблемы программист
тратит больше времени, чем предусмотренно на задачу, в том
числе создаёт сложные решения, которые предусматривают
несколько вариантов развития событий. И всё равно всё
предусмотреть невозможно, эти решения корректируются и
рефакторятся так же, как если бы они писались с нуля.
24. СОВЕТ 2 – закладывайте решения иначе
Решайте задачу непосредственно стоящую перед вами, если вы видите
текущие сайд эффекты/проблемы, решайте их сразу, если вы видите
проблематику расширения/дополнения/изменения функционала, решайте это
ментально, продумывайте, как вы это будете решать в будущем и как это будет
согласовываться с текущим функционалом, опишите примерные пути решения
в комментариях к классу, чтобы когда вы столкнетесь с этими проблемами, у
вас уже было готовое решение. Например вам кажется что нужен будет
функционал спауна рандомного монстра, вы не бросаетесь писать сразу этот
код, а пишите комментарий, что если будет нужен рандомный монстр, то сюда
мы допишем перегрузку метода SpawnCharacter. А в базе данных напишем
метод, который отдаст рандомную модель, возможно с каким то диапазоном.
25. СВЯЗИ, ОБЪЕКТЫ, ДАННЫЕ,
ЧТО ДЕЛАТЬ В ИТОГЕ?
Когда вы в целом всё продумали, всё равно остается большое белое
пятно – как это всё связать, и какой парадигмы/паттерна
придерживаться в итоге. От парадигмы очень сильно зависит
реализация или компромиссные решения для конкретной
реализации.
Давайте просто перечислим самые известные из них без деталей.
26. SERVICE LOCATOR
Если вам близко ООП, у вас небольшой проект, вы не хотите
заморачиваться с DI фреймворками, то ваш вариант – сервис локатор, что
это такое? Это некий объект, который даёт доступ к другим
объектам/сервисам. Реализаций сервис локаторов тьма, в целом это
считается анти паттерном, но тем не менее многие пользуются, я бы
присмотрелся к сервис локатору, который описывает Martin Fowler.
Также есть реализация, где доступ к сервис локатору даётся только
потомкам определенного класса. Некая попытка ограничения
видимости/доступа к сервисам.
27. MVC, MVVM, MVP, Zenject
Большинство фанатов ООП и MVC family, преподчитают Zenject.
Это довольно старое надежное решение. И позволяет из коробки
прокинуть зависимости как в духе синглтона, так и более сложные
истории – фабрики, которые могут сразу связать модель, контролер
и представление. Материалов на эту тему предостаточно.
28. ECS
Мне в целом нравится этот подход. С появлением ECS решения от Unity и
после использования ECS в Overwatch, этот подход начал набирать
популярность в геймдеве. Но хороших практик для него мало. Не все
моменты в архитектуре хорошо ложатся на ECS. При работе с ECS я бы
рекомендовал сразу подразумевать некие гибридные/компромиссные
решения. На какие фреймворки можно посмотреть – Entitas (один из
самых старых фреймворков, для него есть множество проектов), Morpeh
(гибридный ECS фреймворк, хорошо заточен под Unity), LeoECS (быстрый
минималистичный фреймворк). Есть также ME.ECS, который заточен под
сетевые истории.
29. БЫВАЮТ ЛИ ПРОЕКТЫ
С ХОРОШЕЙ АРХИТЕКТУРОЙ?
Если коротко – то да, бывают. Если длинно, то в каждом проекте есть места. за
которые стыдно, часто приходится идти на компромисс ввиду сроков и брать первое
решение, что попало под руку, без оглядки на архитектуру. Также в случае, когда
целый блок приложения закрывает один человек, может порождаться нетривиальный
код, в котором только он и разбирается. И слабое место любых архитектур - когда
проект разрабатывается очень долго, то в нем становится настолько много всего, что в
этом сложно разобраться и это сложно поддерживать. В этом случае следует
прибегать к документированию кода и тестам. Тесты же, в свою очеред,ь довольно
требовательны к коду, если ваш продукт планируется поддерживать более года после
запуска, то необходимо учесть это при разработке архитектуры.
30. СОВЕТ 3 – ДЕЛАЙТЕ БОЛЬШЕ ПРОТОТИПОВ
Финальный совет, чтобы понять и прочувствовать подходы, делайте
больше прототипов в разных жанрах, клонируйте проекты, шутеры, ртс,
пошаговые стратегии, пошаговые батлеры, диаблоиды, тайкуны. Очень
сильно возрастает понимание качественных решений, когда вы их
пробуете в различных жанрах.
И микросовет - https://t.me/unity_architecture присоединяйтесь к чату
который посвящен архитектуре.
А если вам интересен ECS, то вам сюда - https://t.me/ecschat