Привет Хабр
Всегда интересовался программной архитектурой. Читал много статей и примеров. Подходов много, и лучшего конечно же нету.
Данная статья будет показывает мой взгляд на проектирование архитектуры в Unity в компонентно-ориентированном подходе (КОП). Кода в статье не будет!
Статья будет может быть полезна как начинающим так и опытным.
Какие цели я преследовал при проектировании такой архитектуры:
Лёгкая замена и удаление компонентов.
Лёгкость создания прототипов.
Быстрый вход в контекст. Чтобы понять, как работает та или иная механика, нужно время. Поэтому хотелось бы, чтобы это время не превышало несколько минут.
Как выглядит архитектура
Создается скрипт для каждой узкой задачи. Например, движение, прыжок, поворот, определение находится ли игрок на земле. Выглядит это вот так.
![](https://habrastorage.org/getpro/habr/upload_files/9c4/001/540/9c400154082afd35a1661ec1e9f7e855.png)
И тут по началу возникает проблема связанности этих компонентов. Flip скорее всего будет зависеть от того, куда движется игрок или на какую клавишу мы нажали. А Jump будет завесить от Ground, который определяет находимся ли мы на земле.
Можно было бы сделать ссылки одного компонента на другой. Или создать класс прослойку. Тогда компонентно-ориентированным подходом это не назвать.
Для меня решением было отделить данные от компонентов. А компоненты могут легко ссылаться на эти переменные. Получилось вот так.
![](https://habrastorage.org/getpro/habr/upload_files/d52/569/d37/d52569d37f2049caad9f0d33a9270714.png)
Поначалу я делал их ScriptableObject который хранит данные. В последствии сделал еще и Monobehavior переменные и сделал абстракцию, чтобы они могли быть заменяемыми.
![](https://habrastorage.org/getpro/habr/upload_files/a2e/a08/00c/a2ea0800cfeb736c41a61a0ebe53c347.png)
Смотрел много статей про КОП, MVC, ООП и в большинстве случаев, даже если отделяли данные от логики, эти данные лежали в скриптах по типу PlayerModel, EnemyModel и т.д.
Мне такой подход не понравился, поэтому я сделал каждую переменную отдельно. И благодаря этому могу легко подставлять их куда угодно.
Расширяемость
Если речь идет о простой логике по типу прыжка, движения, поворота, то она легко заменяется другой. Если говорить о чём-то посложнее, например, механики стрельбы. То она может быть очень разной.
Выстрел может содержать просто уменьшение текущего количества патрон и звук выстрела. А может содержать огромный список:
Эффект выстрела;
создание префаба патрон;
уменьшение прочности оружия;
и т д.
Причем для разных игр нужны разные наборы.
Тут я делаю одно из двух:
Первое, если механика сильно отличается от шаблона, я создаю новый скрипт стрельбы;
Второе, если же механика очень похожа, но меняется один два пункта. В одном случае, например, нужно создать патрон, в другом нет. Или в одном случае нужна механика уменьшения прочности брони, в другом нет. Для такого я создал расширение возможности скрипта без изменения самого этого скрипта. В этом случае, я могу добавить абсолютно любую механику, или удалить её.
![](https://habrastorage.org/getpro/habr/upload_files/2c1/2c6/e29/2c12c6e29a09e68033c41c315e7fb1be.png)
Плюсы:
Очень удобно использовать для создания прототипов игр.
Лёгкая взаимозаменяемость логики.
Лёгкость исправления багов. Так как один класс отвечает за одну задачу.
Слабосвязанная архитектура. Все классы соединяются через абстракции.
Узкоспециализированные скрипты. Плюс в том, что каждый скрипт (компонент отвечает за одну задачу). Он небольшой и легко читается.
Многие компоненты можно использовать повторно в других проектах.
Минусы
Сложность входа в контекст спустя время. Так как скрипты снаружи просто накиданы на Gameobjects. И даже если открыть скрипт он нарушает принципы единой ответственности.
Сложность исправления багов. Если в одном случае, исправить баг можно очень легко, из-за того, что он находится в одном классе, то в другом может сломать всю логику, где он используется. Характерно для больших проектов и сложных механик.
Механики по типу инвентаря, квестов, событий, нанесения урона сделать в КОП стиле очень сложно. Проще использовать другие подходы.
Куча ссылок в самой Unity. Так как я не связываю классы через код, я начал связывать их через Unity.
Большая кодовая база из небольших скриптов. Минус в том, что будет огромное количество скриптов. Например, 5 разных компонентов движения. С другой стороны, и ООП и другие парадигмы так же имеют большую кодовую базу. Так что считать это минусом или нет решайте сами.
Большое количество скриптов (компонентов) в редакторе Unity. Из-за того, что все скрипты узкоспециализированные, их очень много и почти все должны вешаться как компонент, получается очень большой список компонентов.
Нет возможности написания тестов. Так как все скрипты - MonoBehavior.
О командной разработке можно забыть. С большой вероятностью могут слететь ссылки. Слияние проекта в git сделать не получится.
Итог
Если задумываетесь о чём то подобном, то лучше такую идею оставить.
Цели данного подхода были создать необходимый набор из компонентов и далее просто играться ими в редакторе. Для программистов это крайне не удобно, как и для геймдизайнеров. Визуальное программирование в этом случае куда лучше.
Данный подход идеально подходит для простых действий, которые не требуют отображения интерфейса игроку и изменения. Самый простой пример: Скрипт поворота игрока, объекта. Тем более это можно сделать без отделения каких то переменных.
При этом больше чем для прототипа такой подход не подойдёт.
Спасибо за прочтение статьи.