Как стать автором
Обновить

Комментарии 4

Интересно узнавать о таких решениях, но для себя я не могу оправдать переход к подобным архитектурам, поскольку они в некоторой мере противостоят идее локальности систем и провоцируют писать связный код который потом трудно будет превратить, например, в независимый пекедж, работающий в новой среде. Важное преимущество работы в Unity - возможность конструировать логику игры из модулей в самой сцене или в префабе без необходимости перекомпиляции кода путем лишь добавления новых компонентов и взаимных локальных ссылок. Можно менять интерфейс и игровые механики налету, подгружать новые уровни без обновления приложения, через addressables например. В этом мне помогает Unity Atoms, например. И я пока предпочитаю именно такую архитектуру которая эксплуатирует это преимущество и не провоцирует изобретению параллельной логики которую еще и непросто бывает понять со стороны. Но DI системы тоже по-своему соблазнительны, конечно.

Согласен, думаю будет интересно порассуждать на эту тему в какой-нибудь из следующих статей, спасибо за идею)

Строго рекомендуете использовать в качестве Event-ов struct-ы, а при вызове GEventPool.SendMessage - упаковываете её в объект. Ну и в чем тогда смысл?

Далее, вы утверждаете что вот это DI:

private readonly PlayerHealthbarEmitter _healthbarEmitter = GDataPool.Get<PlayerHealthbarEmitter>();

По факту это сервис локатор, что не является DI. Вот [SerializeField] - это DI. Вы не знаете как, кто (и при определенной сноровке что) просунет вам в переменную. В вашем же случае объект сам просит конкретную реализацию объекта из конкретного места.

Чтобы сделать инъекцию зависимости без контейнера зависимостей, просто передавайте зависимости в конструктор, либо в поле, либо в метод.

Например:

public class PlayerHealthbarSystem : IStartSystem {

private int _health;

private readonly IHealthEmitter _healthEmitter;

public PlayerHealthbarSystem(IHealthEmmiter healthEmmiter)

_healthEmmiter = healthEmmiter;

}

...

}

Вот теперь мы не знаем кто, как и "что конкретно" передаст нам в качестве зависимости. Ну и инъекция при помощи контейнера для бедных:

_system.Add(new PlayerHealthbarSystem(playerHealthbarEmitter);

Чем дольше смотрю на все это, тем страшнее становится за тех кто будет с этим работать. Как то от чего следует отталкиваться вам лично в вашем развитии - неплохой проект, через пару месяцев вы от него либо откажетесь, либо перепишете полностью.

Как то что рекомендовать кому-то к реализации в своих проектах - плохая идея. Во-первых продукт сырой, во-вторых решает всего пару проблем (организация очереди вычислений, передача сообщений, единая организация кода), при этом недостаточно правильным образом.

Несмотря на то что утверждаете что используете DI - используете ServiceLocator. Это чревато тем, что когда захотите дёрнуть какую-нибудь систему из одного проекта в другой, вам придется, помимо явных зависимостей, тащить за собой весь ваш фреймворк, либо организовывать заглушки для SL.

В шину событий рекомендуете посылать структуры, но сразу же их упаковываете в объект. Сама по себе шина событий достаточно неприятная штука. Я бы не рекомендовал пользоваться ей на широкую ногу, закапаетесь в лапшу из вызовов событий. Шаг в сторону типизированной шины - правильный, но сама по себе шина источник кодовой запутанности.

Несколько явных Singletone-ов - отказаться от такой архитектуры в дальнейшем будет очень затруднительно, придется клещами потом выдирать эти куски кода из проекта. Синглтоны - плохо, уже столько статей про это написано, а вы в своей архитектуре их сразу же наплодили кучку.

Попробуйте Zenject - в нем уже все эти вопросы решены. Даже шина событий есть, только, я её не рекомендую использовать. И даже синглтон есть, но это если поискать :). Это хороший DI контейнер, поможет вам понять что это и как с этим жить, научит архитектуре получше. Есть множество других, но Zenject наиболее взрослый.

Попробуйте Entitas - он стал бесплатным, а лучше попробуйте EntitasRedux - у него все проще с настройкой проекта и правильное именование компонентов сущности. ECS - это отличное архитектурное решение, признанное мировым сообществом разработки игр, Entitas - один из самых простых для осваивания фреймворков. Есть еще для Unity - Leo ECS, Svelto ECS и многие другие. Сам использую Entitas, и вообще приверженец кодогенерации.

В заключение, как я уже говорил, ваш фреймворк неплохое начало для осознания того, какой должна быть архитектура вашего проекта. Вы уже начали осознавать что двигаться путем который предлагали разработчики Unity в разработке игр - гиблое дело, но не нашли то как можно делать по другому. Собственно попробуйте сделать проект с минимальным количеством MonoBehaviour, используйте конструкторы (и методы, где нет возможности их использовать) для инъекции зависимостей, используйте больше интерфейсов, попробуйте TDD подход для решения какой либо задачи (без использования MonoBehaviour). Разберитесь что такое struct и чем его едят. Попробуйте Data Driven подход к разработке, попробуйте какой-нибудь фреймворк ECS помимо юнитивского (ибо он архисложный, ещё по этому же не рекомендую Svelto).

Мне показалось интересным рассказать про этот проект, т.к. пришлось работать с ним на проектах. Я всë ещë в поисках оптимального решения. Думаю, когда изучу достаточно вариантов, напишу об этом. Спасибо за фидбэк

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории