#абстракции #чистый_код #полиморфизм
Абстракции продолжение 👇
Подход, описанный в этой статье, предлагает альтернативный способ достижения полиморфизма и абстракции в Unity и C# без использования интерфейсов.
Он также включает использование аспектов реактивного программирования для создания динамичных и отзывчивых систем.
Данный подход требует переосмысления традиционных паттернов и классических практик, результат применения подхода - чистый, более гибкий и управляемый код.
Благодарим за внимание!
Хороших выходных 😉
Абстракции продолжение 👇
Подход, описанный в этой статье, предлагает альтернативный способ достижения полиморфизма и абстракции в Unity и C# без использования интерфейсов.
Он также включает использование аспектов реактивного программирования для создания динамичных и отзывчивых систем.
Данный подход требует переосмысления традиционных паттернов и классических практик, результат применения подхода - чистый, более гибкий и управляемый код.
Благодарим за внимание!
Хороших выходных 😉
Приветствую, друзья! Хотим изменить структуру опроса. Важно ваше мнение! Суть - сделать опрос-дискуссию. Мы задаем вопрос с вариантами, например: не знаю/отвечу в комментариях! Выбравший “отвечу в комментариях” пишет свой ответ. Как вам идея? Пробуем?
Anonymous Poll
73%
Да 👍
25%
Нет 👎
2%
Своя идея в комментариях ☝
#опрос #async #gamedev
Итак, друзья )
Тестируем наш первый опрос в новом формате (спасибо за идею механики Алексею 😊)
Есть код, эммулирующий загрузку данных из сети 👇
❓Все ли в порядке с кодом? Или код требует улучшения❓
ГОЛОСОВАТЬ >>>
❗Внимание ❗Обсуждаем код и ведем дискуссию здесь, а в следующем посте Вы только голосуете и расписываете ответ в комментариях, если считаете, что код требует улучшений
Итак, друзья )
Тестируем наш первый опрос в новом формате (спасибо за идею механики Алексею 😊)
Есть код, эммулирующий загрузку данных из сети 👇
TimeSpan workDuration = TimeSpan.FromSeconds(10);
DateTime endDateTime = DateTime.Now.Add(workDuration);
while (DateTime.Now < endDateTime)
{
// some fast network operation, receive data from socket, speed 200 Mbps
Task receiveDataTask = Task.Delay(1);
//
await receiveDataTask;
}
❓Все ли в порядке с кодом? Или код требует улучшения❓
ГОЛОСОВАТЬ >>>
❗Внимание ❗Обсуждаем код и ведем дискуссию здесь, а в следующем посте Вы только голосуете и расписываете ответ в комментариях, если считаете, что код требует улучшений
Требует ли улучшений код выше 👆. ❗Если вы считаете, что код отработает некорректно, опишите риски здесь в комментариях. Если уже есть мнение, совпадающее с вашим, лайкнете его 👍
Final Results
64%
не знаю/затрудняюсь с ответом
15%
код отработает корректно
21%
вижу риски (напишу в комментариях)
#unity #асинхронность #производительность
Приветствую, друзья 👋
Подведем итоги по проблеме с кодом, который разбирали в недавнем опросе 👇
Пример 1.
Проблема кода, приведенного выше, будет заключаться в производительности.
Получение данных из сокета происходит в отдельном треде (Task.Delay(1)).
Так, как операция выполняется быстро, то await на каждой итерации необходимо будет ждать, пока главный поток освободится.
Следовательно, в данном случае узкое горлышко - главный поток.
Предлагаю рассмотреть разницу между кодом из опроса (Пример 1) и приведенным ниже 👇
Пример 2.
❗Пример 1 и Пример 2 будут сильно отличаться по количеству итераций.
Бóльшее количество итераций будет в примере 2.
Всё зависит от того, как долго у нас занят главный поток на каждой своей итерации. Если время получения данных из сокета на каждой итерации (t1) в нашем цикле меньше времени одной итерации главного потока (t2), то мы при await receiveDataTask упрёмся во время t2 и будем ожидать ~ t2.
Таким образом код из Пример 1 демонстрирует ограничения, с которыми мы можем столкнуться в реальной разработке.
❗Пример 2 показывает, как можно избежать просадки производительности, используя ConfigureAwait(false) для receiveDataTask. В таком случае продолжение будет выполнено вне главного потока и ожидания не будет.
Думаю, что об асинхронности стоит позже написать отдельный пост и поговорить о контексте синхронизации в Unity.
Хорошей всем недели 💪.
Приветствую, друзья 👋
Подведем итоги по проблеме с кодом, который разбирали в недавнем опросе 👇
Пример 1.
TimeSpan workDuration = TimeSpan.FromSeconds(10);
DateTime endDateTime = DateTime.Now.Add(workDuration);
int iterationsCount = 0;
while (DateTime.Now < endDateTime)
{
// some fast network operation, receive data from socket, speed 200 Mbps
Task receiveDataTask = Task.Delay(1);
await receiveDataTask;
iterationsCount++;
}
Debug.Log($"Iterations count: {iterationsCount}");
Проблема кода, приведенного выше, будет заключаться в производительности.
Получение данных из сокета происходит в отдельном треде (Task.Delay(1)).
Так, как операция выполняется быстро, то await на каждой итерации необходимо будет ждать, пока главный поток освободится.
Следовательно, в данном случае узкое горлышко - главный поток.
Предлагаю рассмотреть разницу между кодом из опроса (Пример 1) и приведенным ниже 👇
Пример 2.
TimeSpan workDuration = TimeSpan.FromSeconds(10);
DateTime endDateTime = DateTime.Now.Add(workDuration);
int iterationsCount = 0;
while (DateTime.Now < endDateTime)
{
// some fast network operation, receive data from socket, speed 200 Mbps
Task receiveDataTask = Task.Delay(1);
await receiveDataTask.ConfigureAwait(false);
iterationsCount++;
}
Debug.Log($"Iterations count: {iterationsCount}");
❗Пример 1 и Пример 2 будут сильно отличаться по количеству итераций.
Бóльшее количество итераций будет в примере 2.
Всё зависит от того, как долго у нас занят главный поток на каждой своей итерации. Если время получения данных из сокета на каждой итерации (t1) в нашем цикле меньше времени одной итерации главного потока (t2), то мы при await receiveDataTask упрёмся во время t2 и будем ожидать ~ t2.
Таким образом код из Пример 1 демонстрирует ограничения, с которыми мы можем столкнуться в реальной разработке.
❗Пример 2 показывает, как можно избежать просадки производительности, используя ConfigureAwait(false) для receiveDataTask. В таком случае продолжение будет выполнено вне главного потока и ожидания не будет.
Думаю, что об асинхронности стоит позже написать отдельный пост и поговорить о контексте синхронизации в Unity.
Хорошей всем недели 💪.
#архитектура #связи
Приветствую, друзья 👋
Сегодня поговорим про связи в проекте.
Публикацию разобью на две части:
- Часть 1 Общее представление о связях и их реализации
- Часть 2 Мой подход к организации связей.
Итак, поехали 🚀
Выстраивание слоя связей - один из важнейших аспектов игровой разработки.
В реальном мире для обеспечения взаимодействия устройств и систем мы используем провода или другие интерфейсы. Соединение может быть оптимальным и не очень. Так и в программной архитектуре грамотно реализованный слой связей обеспечит эффективное взаимодействие и расширяемость модулей системы, поможет ослабить зацепление между классами в коде.
Рассмотрим аналогию из реальной жизни на примере двух независимых систем, которые разрабатываются для управления автомобилем: педаль газа и блок управления двигателем. Аналогия позволяет наглядно представить, как различные компоненты системы могут взаимодействовать, обеспечивая ее работоспособность.
Педаль газа является входным устройством, отвечающим за управление мощностью двигателя. Блок управления двигателем обрабатывает сигналы от педали газа и регулирует работу двигателя соответствующим образом.
Правильная организация слоя связей между педалью газа и блоком управления двигателем имеет решающее значение для надежной и эффективной работы автомобиля.
Аналогично, в программной архитектуре, выстраивание слоя связей между компонентами системы позволяет достичь следующих преимуществ:
1️⃣ Модульность:
Разделить систему на отдельные компоненты (классы), каждый из которых отвечает за конкретную функциональность.
❗Упрощает понимание системы и повышает возможность повторного использования компонентов.
2️⃣ Независимость:
Обеспечивает независимость компонентов, что означает, что изменения в одном компоненте не требуют модификации других компонентов.
❗Повышает гибкость и облегчает сопровождение системы.
3️⃣ Расширяемость:
Позволяет добавлять новые компоненты или функциональность без необходимости изменения существующих компонентов.
❗Способствует легкой адаптации системы к изменяющимся требованиям.
4️⃣ Тестируемость:
Облегчает модульное тестирование компонентов системы.
❗Каждый компонент может быть протестирован независимо, что обеспечивает более надежное и эффективное тестирование системы в целом.
Слой связей относится к архитектуре и представляет собой промежуточный слой, который связывает различные модули (в нашем случае набор классов).
Он обеспечивает взаимодействие, позволяя обмениваться данными и вызывать методы друг друга.
Слой связей часто используется для разделения ответственности и уровня абстракции между различными компонентами системы.
Он служит в качестве интерфейса между компонентами, скрывая внутреннюю реализацию и детали работы каждого компонента.
В слое связей определяются различные соглашения и протоколы, по которым компоненты обмениваются информацией и взаимодействуют друг с другом и создаются объекты, посредствам которых будет происходить взаимодействие.
Слой связей часто реализуется с использованием паттернов проектирования, таких как "Наблюдатель" (Observer), "Адаптер" (Adapter) и паттерн "Фасад" (Facade).
Слой связей может быть реализован как часть общей архитектуры системы или как отдельный компонент, отвечающий за управление взаимодействием.
Продолжим завтра
Благодарю за внимание!
Вопросы в комментариях приветствуются!
Приветствую, друзья 👋
Сегодня поговорим про связи в проекте.
Публикацию разобью на две части:
- Часть 1 Общее представление о связях и их реализации
- Часть 2 Мой подход к организации связей.
Итак, поехали 🚀
Выстраивание слоя связей - один из важнейших аспектов игровой разработки.
В реальном мире для обеспечения взаимодействия устройств и систем мы используем провода или другие интерфейсы. Соединение может быть оптимальным и не очень. Так и в программной архитектуре грамотно реализованный слой связей обеспечит эффективное взаимодействие и расширяемость модулей системы, поможет ослабить зацепление между классами в коде.
Рассмотрим аналогию из реальной жизни на примере двух независимых систем, которые разрабатываются для управления автомобилем: педаль газа и блок управления двигателем. Аналогия позволяет наглядно представить, как различные компоненты системы могут взаимодействовать, обеспечивая ее работоспособность.
Педаль газа является входным устройством, отвечающим за управление мощностью двигателя. Блок управления двигателем обрабатывает сигналы от педали газа и регулирует работу двигателя соответствующим образом.
Правильная организация слоя связей между педалью газа и блоком управления двигателем имеет решающее значение для надежной и эффективной работы автомобиля.
Аналогично, в программной архитектуре, выстраивание слоя связей между компонентами системы позволяет достичь следующих преимуществ:
1️⃣ Модульность:
Разделить систему на отдельные компоненты (классы), каждый из которых отвечает за конкретную функциональность.
❗Упрощает понимание системы и повышает возможность повторного использования компонентов.
2️⃣ Независимость:
Обеспечивает независимость компонентов, что означает, что изменения в одном компоненте не требуют модификации других компонентов.
❗Повышает гибкость и облегчает сопровождение системы.
3️⃣ Расширяемость:
Позволяет добавлять новые компоненты или функциональность без необходимости изменения существующих компонентов.
❗Способствует легкой адаптации системы к изменяющимся требованиям.
4️⃣ Тестируемость:
Облегчает модульное тестирование компонентов системы.
❗Каждый компонент может быть протестирован независимо, что обеспечивает более надежное и эффективное тестирование системы в целом.
Слой связей относится к архитектуре и представляет собой промежуточный слой, который связывает различные модули (в нашем случае набор классов).
Он обеспечивает взаимодействие, позволяя обмениваться данными и вызывать методы друг друга.
Слой связей часто используется для разделения ответственности и уровня абстракции между различными компонентами системы.
Он служит в качестве интерфейса между компонентами, скрывая внутреннюю реализацию и детали работы каждого компонента.
В слое связей определяются различные соглашения и протоколы, по которым компоненты обмениваются информацией и взаимодействуют друг с другом и создаются объекты, посредствам которых будет происходить взаимодействие.
Слой связей часто реализуется с использованием паттернов проектирования, таких как "Наблюдатель" (Observer), "Адаптер" (Adapter) и паттерн "Фасад" (Facade).
Слой связей может быть реализован как часть общей архитектуры системы или как отдельный компонент, отвечающий за управление взаимодействием.
Продолжим завтра
Благодарю за внимание!
Вопросы в комментариях приветствуются!
#архитектура #связи
Приветствую, друзья 👋
Сегодня продолжаем про слой связей!
Рассмотрим мой подход к организации слоя связей, для большей наглядности и понимания организации я подготовил иллюстрацию “Связь между классами”.
Приступим 🚀
В предлагаемом мной подходе в слое связей я выделяю 3 основные роли:
1️⃣ Первая роль – инициатор действия/изменения данных.
Этот участник запускает процесс обновления данных самостоятельно либо в ответ на какое-либо событие или внешний запрос.
Он передает данные через установленные связи, что инициирует реакцию обработчика и может привести к изменениям в системе.
2️⃣ Вторая роль – точка стыковки зависимости. Участник, который создает связи и определяет структуру передачи данных.
Ответственность участника:
- задать способы соединения различных компонентов системы
- установить правила передачи данных от одного узла к другому.
3️⃣ Третья роль – обработчик действия.
Участник, который использует созданные ранее связи и подписывается на изменения данных внутри объекта.
Может быть реализован в виде обработчика, который реагирует на изменения данных, полученные через связи, и выполняет соответствующие действия.
Участник использует информацию от создателя связей для обновления состояния или выполнения определенных операций.
ℹ️ Разберем подробнее схему “Связи между классами”.
Как правило все основные связи создаются в Entity.
Связь реализуется через контексты.
В контексты передаются обычные классы или реактивные объекты: ReactiveProperty и ReactiveCommand.
PM, View, Service могут использовать, подписываться или изменять данные внутри контекста.
В узел PlayerEnity нашего Composition Tree в контексте приходит зависимость A.
Данную зависимость мы можем использовать для всех объектов, которые порождает PlayerEnity.
Примером такой зависимости может быть реактивный объект ReactiveProperty<bool> isAutopilotEnabled, который отражает состояние включен автопилот в игре или нет.
PlayerEnity создает зависимость B (приватное поле класса), например ReactiveProperty<Vector3> _lookTransform, которая отражает вектор, куда сейчас смотрит игрок.
Аналогично с остальными зависимостями.
PlayerEnity порождает PlayerView и PlayerPm.
В PlayerPm в контексте передается зависимость B, данные которой PlayerPm будет изменять.
В PlayerView в контексте также передается зависимость B, на которую PlayerView будет подписываться.
Обрабатывать подписку будет логика в приватном методе класса.
❗Связь устанавливается тогда, когда выстроена цепочка: инициатор (PlayerPm), точка стыковки (создание _lookTransform и передача _lookTransform в контекст PlayerPm, PlayerView), подписчик (подписка в PlayerView, которую обрабатывает приватный метод класса).
Подытожу:
Плюс рассмотренного подхода - выстроенный явным образом слой связей и ослабление зацепление в коде.
Минус подхода - явное дублирование нужных зависимостей внутри контекстов, если мы хотим спускать зависимость глубже в нашем Composition Tree.
Хорошего дня 👍
Приветствую, друзья 👋
Сегодня продолжаем про слой связей!
Рассмотрим мой подход к организации слоя связей, для большей наглядности и понимания организации я подготовил иллюстрацию “Связь между классами”.
Приступим 🚀
В предлагаемом мной подходе в слое связей я выделяю 3 основные роли:
1️⃣ Первая роль – инициатор действия/изменения данных.
Этот участник запускает процесс обновления данных самостоятельно либо в ответ на какое-либо событие или внешний запрос.
Он передает данные через установленные связи, что инициирует реакцию обработчика и может привести к изменениям в системе.
2️⃣ Вторая роль – точка стыковки зависимости. Участник, который создает связи и определяет структуру передачи данных.
Ответственность участника:
- задать способы соединения различных компонентов системы
- установить правила передачи данных от одного узла к другому.
3️⃣ Третья роль – обработчик действия.
Участник, который использует созданные ранее связи и подписывается на изменения данных внутри объекта.
Может быть реализован в виде обработчика, который реагирует на изменения данных, полученные через связи, и выполняет соответствующие действия.
Участник использует информацию от создателя связей для обновления состояния или выполнения определенных операций.
ℹ️ Разберем подробнее схему “Связи между классами”.
Как правило все основные связи создаются в Entity.
Связь реализуется через контексты.
В контексты передаются обычные классы или реактивные объекты: ReactiveProperty и ReactiveCommand.
PM, View, Service могут использовать, подписываться или изменять данные внутри контекста.
В узел PlayerEnity нашего Composition Tree в контексте приходит зависимость A.
Данную зависимость мы можем использовать для всех объектов, которые порождает PlayerEnity.
Примером такой зависимости может быть реактивный объект ReactiveProperty<bool> isAutopilotEnabled, который отражает состояние включен автопилот в игре или нет.
PlayerEnity создает зависимость B (приватное поле класса), например ReactiveProperty<Vector3> _lookTransform, которая отражает вектор, куда сейчас смотрит игрок.
Аналогично с остальными зависимостями.
PlayerEnity порождает PlayerView и PlayerPm.
В PlayerPm в контексте передается зависимость B, данные которой PlayerPm будет изменять.
В PlayerView в контексте также передается зависимость B, на которую PlayerView будет подписываться.
Обрабатывать подписку будет логика в приватном методе класса.
❗Связь устанавливается тогда, когда выстроена цепочка: инициатор (PlayerPm), точка стыковки (создание _lookTransform и передача _lookTransform в контекст PlayerPm, PlayerView), подписчик (подписка в PlayerView, которую обрабатывает приватный метод класса).
Подытожу:
Плюс рассмотренного подхода - выстроенный явным образом слой связей и ослабление зацепление в коде.
Минус подхода - явное дублирование нужных зависимостей внутри контекстов, если мы хотим спускать зависимость глубже в нашем Composition Tree.
Хорошего дня 👍
#опрос
Приветствую 👋
Предлагаю порассуждать и поучаствовать в опросе!
Ниже описан подход к организации общения между классами через интерфейсы 👇
Есть 2 класса: логика и представление. Один класс использует методы другого.
Чтобы ослабить зацепление, в каждом классе выделяем интерфейс и реализуем использование классов через вызовы методов интерфейсной ссылки.
Задача оценить оптимальность описанного подхода и рассказать о своем, если он отличена от приведенного выше. Если ваш подход совпадает с описанным - раскрыть, почему с вашей точки зрения данная реализация оптимальна
ГОЛОСОВАТЬ >>>
❗Внимание ❗ Обсуждаем предложенный подход и ведем дискуссию здесь, голосуем по ссылке
Приветствую 👋
Предлагаю порассуждать и поучаствовать в опросе!
Ниже описан подход к организации общения между классами через интерфейсы 👇
Есть 2 класса: логика и представление. Один класс использует методы другого.
Чтобы ослабить зацепление, в каждом классе выделяем интерфейс и реализуем использование классов через вызовы методов интерфейсной ссылки.
Задача оценить оптимальность описанного подхода и рассказать о своем, если он отличена от приведенного выше. Если ваш подход совпадает с описанным - раскрыть, почему с вашей точки зрения данная реализация оптимальна
ГОЛОСОВАТЬ >>>
❗Внимание ❗ Обсуждаем предложенный подход и ведем дискуссию здесь, голосуем по ссылке
Есть 2 класса: логика и представление. Один класс использует методы другого. Чтобы ослабить зацепление, в каждом классе выделяем интерфейс и реализуем использование классов через вызовы методов интерфейсной ссылки. Оптимален ли подход? Совпадает с вашим?
Final Results
30%
подход оптимален, использую на практике
30%
делаю иначе, более оптимально
17%
делаю иначе, менее оптимально
23%
затрудняюсь ответить
#опрос
Приветствую, друзья 👋
Сегодня подведу итоги опроса по применяемым для ослабления зацепления в коде подходам.
Первым делом хочу поблагодарить всех, принявших участие и рассказавших о своей практике 🤝
Вопрос звучал:
Есть 2 класса: логика и представление. Один класс использует методы другого. Чтобы ослабить зацепление, в каждом классе выделяем интерфейс и реализуем использование классов через вызовы методов интерфейсной ссылки. Оптимален ли подход? Совпадает с вашим?
Результаты 👇
30% применяют описанный подход
47% используют альтернативные способы ослабления зацепления в коде
23% затруднились с ответом
Итак, приступим 🚀
Что касается приведенного в опросе подхода: на мой взгляд, он оптимален там, где редко меняются бизнес процессы.
Поэтому, как правильно отметил @GlassOfDream 👌в игровой индустрии - такой подход - скорее утопичен и зависит от многих факторов: сложность и стадия проекта, количество человек в команде и т.д.
Также вы перечислили другие варианты, отражающие разнообразие подходов и методов:
- Прямая связь, если в этом месте не нужен полиморфизм. С защитой от дурака в виде автотестов с рефлексией.
- Через публичный api-интерфейс в классах представления и логики и создание третьего класса ~адаптер/контроллер, который знает о логике и представлении и связывает их.
- Через ивенты. Логика отправляет ивент, подписчики слушают и обрабатывают.
- Перенос зависимостей в аргументы метода.
- Использовать ECS.
Как правильно было подмечено в комментариях, сейчас в разработке нет единой концепции и правил, которые подходили бы для всех задач.
Контекст проекта, требования, сроки и другие факторы влияют на выбор оптимального подхода взаимодействия между классами.
В то же время широта взгляда, знание различных подходов и опыт их применения на различных проектах также помогают разработчику выбрать наиболее подходящий вариант в конкретной ситуации.
Было бы неплохо внедрить в современные учебные программы принципы разработки информационных систем, включая игры.
Это поможет будущим разработчикам получить фундаментальные знания и навыки, которые позволят принимать более обоснованные решения при проектировании и разработке программного обеспечения.
Спасибо за участие в опросе
Хорошего вечера 👍
Приветствую, друзья 👋
Сегодня подведу итоги опроса по применяемым для ослабления зацепления в коде подходам.
Первым делом хочу поблагодарить всех, принявших участие и рассказавших о своей практике 🤝
Вопрос звучал:
Есть 2 класса: логика и представление. Один класс использует методы другого. Чтобы ослабить зацепление, в каждом классе выделяем интерфейс и реализуем использование классов через вызовы методов интерфейсной ссылки. Оптимален ли подход? Совпадает с вашим?
Результаты 👇
30% применяют описанный подход
47% используют альтернативные способы ослабления зацепления в коде
23% затруднились с ответом
Итак, приступим 🚀
Что касается приведенного в опросе подхода: на мой взгляд, он оптимален там, где редко меняются бизнес процессы.
Поэтому, как правильно отметил @GlassOfDream 👌в игровой индустрии - такой подход - скорее утопичен и зависит от многих факторов: сложность и стадия проекта, количество человек в команде и т.д.
Также вы перечислили другие варианты, отражающие разнообразие подходов и методов:
- Прямая связь, если в этом месте не нужен полиморфизм. С защитой от дурака в виде автотестов с рефлексией.
- Через публичный api-интерфейс в классах представления и логики и создание третьего класса ~адаптер/контроллер, который знает о логике и представлении и связывает их.
- Через ивенты. Логика отправляет ивент, подписчики слушают и обрабатывают.
- Перенос зависимостей в аргументы метода.
- Использовать ECS.
Как правильно было подмечено в комментариях, сейчас в разработке нет единой концепции и правил, которые подходили бы для всех задач.
Контекст проекта, требования, сроки и другие факторы влияют на выбор оптимального подхода взаимодействия между классами.
В то же время широта взгляда, знание различных подходов и опыт их применения на различных проектах также помогают разработчику выбрать наиболее подходящий вариант в конкретной ситуации.
Было бы неплохо внедрить в современные учебные программы принципы разработки информационных систем, включая игры.
Это поможет будущим разработчикам получить фундаментальные знания и навыки, которые позволят принимать более обоснованные решения при проектировании и разработке программного обеспечения.
Спасибо за участие в опросе
Хорошего вечера 👍
#контент #слои_абстракции
Приветствую, друзья 👋
Сегодня говорим про контент.
Контент является неотъемлемой частью игровых проектов на Unity C#.
Представляет собой информацию, например: настройки уровней, данные о персонажах, объекты окружения и многое другое.
Контент - это отдельный слой, который представляет из себя иерархию неизменяемых классов (то есть ни одно свойство класса не меняется в runtime), базовый предок - класс Content (см. иллюстрацию Иерархия контентных классов).
❗В данном контексте контент относится к описательной части, которая не является непосредственно ресурсами игры, но может содержать ссылки на ресурсы.
Контент может храниться в разных местах в зависимости от его характера и требований проекта.
Как всегда при выборе места хранения опираемся на тип контента и требования проекта.
Рассмотрим возможные варианты хранения контента:
- встроенный в билд.
Обновление контента будет требовать пересборку проекта
- на сервере в виде статики.
Позволяет обновлять контент независимо от приложения, но требует сетевого доступа и управления скачиванием. Отдельное внимание следует уделить версионированию, так как с течением времени контент может эволюционировать и его новые версии могут не поддерживаться старыми версиями клиента
- внешние источники: сервисы или хранилища, как пример Google Таблицы.
Подход позволяет обновлять контент в реальном времени, не обновляя само приложение. Мы получаем динамический контент в режиме реального времени. Подход может потребовать дополнительной настройки и интеграции.
Также необходимо помнить про версионирование
- смешанный. Контент зашивается в проект с возможностью докачки/обновления контента.
Основное преимущество - для старта приложения не нужна загрузка по сети, т.е. приложение будет работать при отсутствии интернета.
Все поля контентных классов, как правило, публичные (речь о полях, используемых в игровой логике).
Если говорить про иерархию, контент - отдельный слой. Представляет иерархию неизменяемых классов: ни одно свойство класса не меняется в runtime. Базовый предок - класс Content (см. иллюстрацию “Иерархия контентных классов”).
Если представить иерархию в виде дерева, то для каждого из узлов дерева будут выделены типизированные коллекции с возможностью доступа по ключу. Ключ - id инстанса контента.
ℹ️ Я рекомендую применять типизированные коллекции, предоставляющие доступ к объектам контента по ключу, для избежания динамического приведения типов.
Подход обеспечивает эффективную работу с контентом, лучшую читаемость кода, повышает производительность и упрощает сопровождение проекта.
Рассмотрим на примере иллюстрации:
- Content - базовый класс контента
- Enemy - наследник Content
- GroudEnemy - наследник Enemy
- WaterEnemy - наследник Enemy.
На каждом уровне дерева типы могут содержать свой набор полей.
Приветствую, друзья 👋
Сегодня говорим про контент.
Контент является неотъемлемой частью игровых проектов на Unity C#.
Представляет собой информацию, например: настройки уровней, данные о персонажах, объекты окружения и многое другое.
Контент - это отдельный слой, который представляет из себя иерархию неизменяемых классов (то есть ни одно свойство класса не меняется в runtime), базовый предок - класс Content (см. иллюстрацию Иерархия контентных классов).
❗В данном контексте контент относится к описательной части, которая не является непосредственно ресурсами игры, но может содержать ссылки на ресурсы.
Контент может храниться в разных местах в зависимости от его характера и требований проекта.
Как всегда при выборе места хранения опираемся на тип контента и требования проекта.
Рассмотрим возможные варианты хранения контента:
- встроенный в билд.
Обновление контента будет требовать пересборку проекта
- на сервере в виде статики.
Позволяет обновлять контент независимо от приложения, но требует сетевого доступа и управления скачиванием. Отдельное внимание следует уделить версионированию, так как с течением времени контент может эволюционировать и его новые версии могут не поддерживаться старыми версиями клиента
- внешние источники: сервисы или хранилища, как пример Google Таблицы.
Подход позволяет обновлять контент в реальном времени, не обновляя само приложение. Мы получаем динамический контент в режиме реального времени. Подход может потребовать дополнительной настройки и интеграции.
Также необходимо помнить про версионирование
- смешанный. Контент зашивается в проект с возможностью докачки/обновления контента.
Основное преимущество - для старта приложения не нужна загрузка по сети, т.е. приложение будет работать при отсутствии интернета.
Все поля контентных классов, как правило, публичные (речь о полях, используемых в игровой логике).
Если говорить про иерархию, контент - отдельный слой. Представляет иерархию неизменяемых классов: ни одно свойство класса не меняется в runtime. Базовый предок - класс Content (см. иллюстрацию “Иерархия контентных классов”).
Если представить иерархию в виде дерева, то для каждого из узлов дерева будут выделены типизированные коллекции с возможностью доступа по ключу. Ключ - id инстанса контента.
ℹ️ Я рекомендую применять типизированные коллекции, предоставляющие доступ к объектам контента по ключу, для избежания динамического приведения типов.
Подход обеспечивает эффективную работу с контентом, лучшую читаемость кода, повышает производительность и упрощает сопровождение проекта.
Рассмотрим на примере иллюстрации:
- Content - базовый класс контента
- Enemy - наследник Content
- GroudEnemy - наследник Enemy
- WaterEnemy - наследник Enemy.
На каждом уровне дерева типы могут содержать свой набор полей.
Иерархия контентных классов.png
20.5 KB
Иерархия контентных классов
#контент #слои_абстракции
Контент продолжение 👇
Подобная структура позволяет разработчикам определить общие черты и функциональность для коллекций контента.
Для каждого уровня иерархии классов контента (Content, Enemy, GroundEnemy, WaterEnemy) выделяем типизированные коллекции, позволяющие обращаться к объектам по ключу.
Отдельно выделяется класс ContentCollection, который содержит все эти коллекции.
В данном случае, коллекции "contents", "enemies", "groundEnemies" и "waterEnemies" содержат соответствующие типы контента:
- contents - коллекция (тип элементов - Content), которая содержит все типы контента (классы, которые могут быть приведены к классу Content: Content, Enemy, GroundEnemy, WaterEnemy)
- enemies - коллекция (тип элементов - Enemy), которая содержит все типы контента (классы, которые могут быть приведены к классу Enemy, в данном случае - это классы Enemy, GroudEnemy, WaterEnemy)
- groudEnemies - коллекция (тип элементов - GroundEnemy), которая содержит все типы контента (классы, которые могут быть приведены к классу GroundEnemy, в данном случае - это только класс GroundEnemy)
- waterEnemies - коллекция (тип элементов - WaterEnemy), которая содержит все типы контента (классы, которые могут быть приведены к классу WaterEnemy, в данном случае - это только класс WaterEnemy).
Так, например, если нам нужен конкретный враг из groundEnemies (например с id - 17), мы можем получить его так:
Или враг, без уточнения типа, то можем получить его так:
Или если нам просто нужен контент, то так:
Такой подход обеспечивает строгую типизацию и предоставляет доступ к конкретным типам объектов без необходимости использования операторов "is" и "as", что повышает эффективность и удобство разработки.
Преимущества использования типизированных коллекций в проекте:
- Улучшенная читаемость кода: использование типизированных коллекций упрощает понимание кода и его намерений.
- Разработчикам не нужно использовать операторы "is" и "as" для проверки типов объектов или дополнительно приводить типы.
- Код становится более ясным и легко читаемым.
- Увеличение производительности: избегая динамического приведения типов, разработчики могут сократить накладные расходы на выполнение кода и повысить производительность приложения.
- Упрощение сопровождения: Типизированные коллекции делают код более поддерживаемым.
- При добавлении новых типов контента или изменении структуры иерархии классов, разработчики могут сосредоточиться на обновлении соответствующих типизированных коллекций, а не искать и изменять динамический код в разных частях проекта.
Для избежания ручного построения коллекций и классов можно применять кодогенерацию.
Она позволит автоматически генерировать типизированные коллекции и соответствующие контентные классы на основе заданной схемы (например: схема в виде json).
Это позволит более эффективно работать с контентом сократит трудозатраты на создание и поддержку коллекций и классов, особенно в случае больших проектов с большим объемом контента.
Разработчики могут выбирать соответствующие типизированные коллекции в зависимости от конкретных ситуаций, что позволяет им эффективно управлять и работать с контентом в Unity.
Благодарю за внимание!
Вопросы в комментариях приветствуются!
Контент продолжение 👇
Подобная структура позволяет разработчикам определить общие черты и функциональность для коллекций контента.
Для каждого уровня иерархии классов контента (Content, Enemy, GroundEnemy, WaterEnemy) выделяем типизированные коллекции, позволяющие обращаться к объектам по ключу.
Отдельно выделяется класс ContentCollection, который содержит все эти коллекции.
В данном случае, коллекции "contents", "enemies", "groundEnemies" и "waterEnemies" содержат соответствующие типы контента:
- contents - коллекция (тип элементов - Content), которая содержит все типы контента (классы, которые могут быть приведены к классу Content: Content, Enemy, GroundEnemy, WaterEnemy)
- enemies - коллекция (тип элементов - Enemy), которая содержит все типы контента (классы, которые могут быть приведены к классу Enemy, в данном случае - это классы Enemy, GroudEnemy, WaterEnemy)
- groudEnemies - коллекция (тип элементов - GroundEnemy), которая содержит все типы контента (классы, которые могут быть приведены к классу GroundEnemy, в данном случае - это только класс GroundEnemy)
- waterEnemies - коллекция (тип элементов - WaterEnemy), которая содержит все типы контента (классы, которые могут быть приведены к классу WaterEnemy, в данном случае - это только класс WaterEnemy).
Так, например, если нам нужен конкретный враг из groundEnemies (например с id - 17), мы можем получить его так:
contentCollection.groundEnemies[17]
Или враг, без уточнения типа, то можем получить его так:
contentCollection.enemies[17]
Или если нам просто нужен контент, то так:
contentCollection.contents[17]
Такой подход обеспечивает строгую типизацию и предоставляет доступ к конкретным типам объектов без необходимости использования операторов "is" и "as", что повышает эффективность и удобство разработки.
Преимущества использования типизированных коллекций в проекте:
- Улучшенная читаемость кода: использование типизированных коллекций упрощает понимание кода и его намерений.
- Разработчикам не нужно использовать операторы "is" и "as" для проверки типов объектов или дополнительно приводить типы.
- Код становится более ясным и легко читаемым.
- Увеличение производительности: избегая динамического приведения типов, разработчики могут сократить накладные расходы на выполнение кода и повысить производительность приложения.
- Упрощение сопровождения: Типизированные коллекции делают код более поддерживаемым.
- При добавлении новых типов контента или изменении структуры иерархии классов, разработчики могут сосредоточиться на обновлении соответствующих типизированных коллекций, а не искать и изменять динамический код в разных частях проекта.
Для избежания ручного построения коллекций и классов можно применять кодогенерацию.
Она позволит автоматически генерировать типизированные коллекции и соответствующие контентные классы на основе заданной схемы (например: схема в виде json).
Это позволит более эффективно работать с контентом сократит трудозатраты на создание и поддержку коллекций и классов, особенно в случае больших проектов с большим объемом контента.
Разработчики могут выбирать соответствующие типизированные коллекции в зависимости от конкретных ситуаций, что позволяет им эффективно управлять и работать с контентом в Unity.
Благодарю за внимание!
Вопросы в комментариях приветствуются!
#архитектура #состояния #контент #чистый_код
Приветствую, друзья 👋
Сегодня говорим про состояния игровых объектов в C# Unity и о ключевой роли управления состояниями.
Состояния представляют собой различные конфигурации и параметры, которые определяют поведение и визуальное представление объектов в игре.
Эффективное управление состояниями позволяет упростить разработку и обеспечивает легкость восстановления сохраненных данных в игровом процессе.
Зачастую разработчики не отделяют слой представления и слой данных (контента) от слоя состояний: и данные, и состояния помещаются в MonoBehaviour, что на практике не является лучшим/оптимальным решением.
Рассмотрим на примере, как определить насколько эффективно реализовано управление состояниями объектов в игре.
Предположим, мы разработали платформер, где у игрока может быть различное оружие с различными характеристиками, но не предусмотрена возможность подбирать оружие.
Есть простой тест, который покажет насколько эффективно реализовано управление состояниями объектов. Для этого необходимо проверить насколько легко выбросить оружие со всеми его текущими характеристиками и следом подобрать его же либо выпавшее у противника.
Красным флагом будет являться необходимость существенной доработки кода, для реализации возможности подбирать оружие.
Каждый инстанс контента описывается уникальным набором данных и может иметь своё состояние, которое определяет текущие параметры и свойства этого контента в игровом мире.
Контентные классы могут быть представлены как:
- объекты сцены,
- персонажи, оружие,
- предметы и т.д.
❗Состояния позволяют отделить поведение объектов от самих объектов. Это упрощает логику и облегчает поддержку кода.
Состояние может храниться в профиле игрока или профиле игрового мира.
В зависимости от взаимодействия с другими объектами или игровым процессом состояние может быть изменено в ходе игры: на стороне клиента либо сервера.
Сервер может менять состояние в случае, если он отвечает за часть игровой логики.
Остановлюсь подробнее на рассмотрении организации контентных классов с поддерживаемыми состояниями.
В контентных классах, для которых поддерживаются состояния, должен быть выделен метод CreateState.
Задача метода - создать необходимый класс с состоянием.
Данный метод потребуется игровой логике, когда будем создавать состояние первый раз.
При использовании кодогенерации информацию о том, какой именно класс состояния должен быть создан этим методом можно брать из аннотаций.
❗Состояние игровых объектов - это отдельный слой. Представляет из себя иерархию изменяемых классов, базовый предок - класс ContentState (см. иллюстрацию Иерархия классов состояний).
ContentState, как базовый предок, должен содержать поля:
- id - значение может быть создано как на клиенте, так и на сервере
- contentId - id контента, к которому относится состояние
Для производных от базового ContentState класса классов должен содержаться метод - GetНазваниеКонтентногоКласса (см. иллюстрацию).
Разберем на примере иерархию классов состояний:
Класс EnemyState - состояние врага
У данного класса должен присутствовать метод GetEnemy - получение объекта контента из контентной коллекции.
Предположим, что враги бывают разных типов с разным состоянием свойств для каждого из типов.
Класс GroundEnemyState - состояние наземных врагов.
У данного класса должен быть метод GetGroundEnemy - получение объекта контента из контентной коллекции.
Класс WaterEnemyState - состояние водных врагов. Должен содержать метод GetWaterEnemy, и т.д.
Продолжение 👇
Приветствую, друзья 👋
Сегодня говорим про состояния игровых объектов в C# Unity и о ключевой роли управления состояниями.
Состояния представляют собой различные конфигурации и параметры, которые определяют поведение и визуальное представление объектов в игре.
Эффективное управление состояниями позволяет упростить разработку и обеспечивает легкость восстановления сохраненных данных в игровом процессе.
Зачастую разработчики не отделяют слой представления и слой данных (контента) от слоя состояний: и данные, и состояния помещаются в MonoBehaviour, что на практике не является лучшим/оптимальным решением.
Рассмотрим на примере, как определить насколько эффективно реализовано управление состояниями объектов в игре.
Предположим, мы разработали платформер, где у игрока может быть различное оружие с различными характеристиками, но не предусмотрена возможность подбирать оружие.
Есть простой тест, который покажет насколько эффективно реализовано управление состояниями объектов. Для этого необходимо проверить насколько легко выбросить оружие со всеми его текущими характеристиками и следом подобрать его же либо выпавшее у противника.
Красным флагом будет являться необходимость существенной доработки кода, для реализации возможности подбирать оружие.
Каждый инстанс контента описывается уникальным набором данных и может иметь своё состояние, которое определяет текущие параметры и свойства этого контента в игровом мире.
Контентные классы могут быть представлены как:
- объекты сцены,
- персонажи, оружие,
- предметы и т.д.
❗Состояния позволяют отделить поведение объектов от самих объектов. Это упрощает логику и облегчает поддержку кода.
Состояние может храниться в профиле игрока или профиле игрового мира.
В зависимости от взаимодействия с другими объектами или игровым процессом состояние может быть изменено в ходе игры: на стороне клиента либо сервера.
Сервер может менять состояние в случае, если он отвечает за часть игровой логики.
Остановлюсь подробнее на рассмотрении организации контентных классов с поддерживаемыми состояниями.
В контентных классах, для которых поддерживаются состояния, должен быть выделен метод CreateState.
Задача метода - создать необходимый класс с состоянием.
Данный метод потребуется игровой логике, когда будем создавать состояние первый раз.
При использовании кодогенерации информацию о том, какой именно класс состояния должен быть создан этим методом можно брать из аннотаций.
❗Состояние игровых объектов - это отдельный слой. Представляет из себя иерархию изменяемых классов, базовый предок - класс ContentState (см. иллюстрацию Иерархия классов состояний).
ContentState, как базовый предок, должен содержать поля:
- id - значение может быть создано как на клиенте, так и на сервере
- contentId - id контента, к которому относится состояние
Для производных от базового ContentState класса классов должен содержаться метод - GetНазваниеКонтентногоКласса (см. иллюстрацию).
Разберем на примере иерархию классов состояний:
Класс EnemyState - состояние врага
У данного класса должен присутствовать метод GetEnemy - получение объекта контента из контентной коллекции.
Предположим, что враги бывают разных типов с разным состоянием свойств для каждого из типов.
Класс GroundEnemyState - состояние наземных врагов.
У данного класса должен быть метод GetGroundEnemy - получение объекта контента из контентной коллекции.
Класс WaterEnemyState - состояние водных врагов. Должен содержать метод GetWaterEnemy, и т.д.
Продолжение 👇
#состояния_продолжение #архитектура #состояния #контент #чистый_код
Состояние игровых объектов продолжение 👇
Не забываем, что в играх с открытым миром каждый игрок влияет на объекты мира, при этом все происходящие изменения должны быть видны другим игрокам, для реализации этого состояния всех объектов должны создаваться с возможностью последующих изменений в профиле игрового мира.
Что касается состояние самого игрока, информация о нем должна находиться в профиле игрока, здесь речь о: имени, здоровье, энергии, инвентаре, купленных предметах, и т.д.
Если говорить про реализацию классов состояний, то как правило все поля состояний - реактивные объекты (ReactiveProperty, ReactiveCollection, и т.д.).
⛔Методы с игровой логикой в классах состояний игровых объектов присутствовать не должны.
Поскольку состояния игровых объектов могут быть модифицированы вне игры (например, серверной логикой), то при изменении состояний должны сработать необходимые подписчики и все изменения отобразятся в игре.
❗При запуске игры, после загрузки профиля игрока и профиля игрового мира (или его части) соответствующие объекты состояний передаются в необходимые узлы composition tree (Entity) вспомнить структуру поможет иллюстрация.
За дальнейшую обработку состояний игровых объектов будут отвечать соответствующие Pm.
Приведем упрощенный пример реализации иерархии классов состояний для контента, о котором мы писали в предыдущей статье про контент.
Итак 👇:
Пусть у каждого врага (где враг - контентный класс Enemy, а класс состояния - EnemyState) в состоянии есть:
- health - здоровье (значение от 0 до 100)
для GroundEnemy наземных врагов:
- не будет собственных параметров.
для WaterEnemy водных врагов:
- isStormResistant - устойчивость к шторму.
Тогда реализация классов состояний для контента будет иметь вид 👇
Для сокращения рутинных операции, создание классов состояний можно вынести в зону ответственности кодогенератора.
Благодарю за внимание!
Вопросы в комментариях приветствуются!
Состояние игровых объектов продолжение 👇
Не забываем, что в играх с открытым миром каждый игрок влияет на объекты мира, при этом все происходящие изменения должны быть видны другим игрокам, для реализации этого состояния всех объектов должны создаваться с возможностью последующих изменений в профиле игрового мира.
Что касается состояние самого игрока, информация о нем должна находиться в профиле игрока, здесь речь о: имени, здоровье, энергии, инвентаре, купленных предметах, и т.д.
Если говорить про реализацию классов состояний, то как правило все поля состояний - реактивные объекты (ReactiveProperty, ReactiveCollection, и т.д.).
⛔Методы с игровой логикой в классах состояний игровых объектов присутствовать не должны.
Поскольку состояния игровых объектов могут быть модифицированы вне игры (например, серверной логикой), то при изменении состояний должны сработать необходимые подписчики и все изменения отобразятся в игре.
❗При запуске игры, после загрузки профиля игрока и профиля игрового мира (или его части) соответствующие объекты состояний передаются в необходимые узлы composition tree (Entity) вспомнить структуру поможет иллюстрация.
За дальнейшую обработку состояний игровых объектов будут отвечать соответствующие Pm.
Приведем упрощенный пример реализации иерархии классов состояний для контента, о котором мы писали в предыдущей статье про контент.
Итак 👇:
Пусть у каждого врага (где враг - контентный класс Enemy, а класс состояния - EnemyState) в состоянии есть:
- health - здоровье (значение от 0 до 100)
для GroundEnemy наземных врагов:
- не будет собственных параметров.
для WaterEnemy водных врагов:
- isStormResistant - устойчивость к шторму.
Тогда реализация классов состояний для контента будет иметь вид 👇
public class ContentState
{
public UInt32 contentId;
public readonly ReactiveProperty<UInt64> id;
protected readonly ContentCollection contentCollection;
protected ContentState(ContentCollection ownerCollection)
{
contentCollection = ownerCollection;
id = new ReactiveProperty<UInt64>();
}
}
public class EnemyState : ContentState
{
public readonly ReactiveProperty<UInt8> health;
public EnemyState(ContentCollection ownerCollection) : base(ownerCollection)
{
health = new ReactiveProperty<UInt8>();
}
public Enemy GetEnemy()
{
if (_contentCollection.enemies.TryGet(contentId, out Enemy enemy))
{
return enemy as Enemy;
}
return null;
}
}
public class GroundEnemyState : EnemyState
{
public GroundEnemy GetGroundEnemy()
{
if (_contentCollection.groundEnemies.TryGet(contentId, out GroundEnemy groundEnemy))
{
return groundEnemy as GroundEnemy;
}
return null;
}
}
public class WaterEnemyState : EnemyState
{
public readonly ReactiveProperty<bool> isStormResistant;
public WaterEnemyState(ContentCollection ownerCollection) : base(ownerCollection)
{
isStormResistant = new ReactiveProperty<bool>();
}
public WaterEnemy GetWaterEnemy()
{
if (_contentCollection.waterEnemies.TryGet(contentId, out WaterEnemy waterEnemy))
{
return waterEnemy as WaterEnemy;
}
return null;
}
}
Для сокращения рутинных операции, создание классов состояний можно вынести в зону ответственности кодогенератора.
Благодарю за внимание!
Вопросы в комментариях приветствуются!
Друзья, приветствую 👋
Мы подошли к моменту, когда по плану публикаций, которого мы придерживаемся, осталось 2 поста:
- Плагины
- Сериализация и десериализация
На текущий момент мы выбираем дальнейший вектор развития 🔝и в дополнение к нашему видению нам очень нужна обратная связь от вас 🙏.
Поделитесь своими мыслями👇:
- чего именно вам не хватает на канале?
- чего вам не хватает глобально?
- требуется ли более глубокое раскрытие ранее рассмотренных тем?
- какие темы вам были бы наиболее интересны?
Ждем ваши предложения в комментариях и заранее благодарим за активность 🤝
Хороших выходных!
Мы подошли к моменту, когда по плану публикаций, которого мы придерживаемся, осталось 2 поста:
- Плагины
- Сериализация и десериализация
На текущий момент мы выбираем дальнейший вектор развития 🔝и в дополнение к нашему видению нам очень нужна обратная связь от вас 🙏.
Поделитесь своими мыслями👇:
- чего именно вам не хватает на канале?
- чего вам не хватает глобально?
- требуется ли более глубокое раскрытие ранее рассмотренных тем?
- какие темы вам были бы наиболее интересны?
Ждем ваши предложения в комментариях и заранее благодарим за активность 🤝
Хороших выходных!
#разбор_тестового
Друзья, приветствуем 👋
Мы хотим добавить на канал разбор ваших тестовых и подготовили специальную форму для заявок 👉 https://forms.gle/kqVPv1jWT97Bkps9A
🚑 🚨 Основные показания - вы делали тестовое и, к сожаление, получили отказ без развернутой обратной связи. Либо развернутый отказ, с которым вы не согласны и хотите услышать альтернативное мнение, что не так.
ℹ️ На текущий момент частоту разборов не загадываем, начнем с одного тестового/месяц, чтобы не смещать фокус с основной линии группы.
📌 Форму запиним в описании канала. 📌
Хорошего дня 🤝
Друзья, приветствуем 👋
Мы хотим добавить на канал разбор ваших тестовых и подготовили специальную форму для заявок 👉 https://forms.gle/kqVPv1jWT97Bkps9A
🚑 🚨 Основные показания - вы делали тестовое и, к сожаление, получили отказ без развернутой обратной связи. Либо развернутый отказ, с которым вы не согласны и хотите услышать альтернативное мнение, что не так.
ℹ️ На текущий момент частоту разборов не загадываем, начнем с одного тестового/месяц, чтобы не смещать фокус с основной линии группы.
📌 Форму запиним в описании канала. 📌
Хорошего дня 🤝
#архитектура #плагины #Unity3D
Приветствую, друзья 👋
Сегодняшняя тема посвящена плагинам в Unity 3D
Плагины (или ассеты) в Unity 3D - это дополнительные компоненты, скрипты, ресурсы или библиотеки, разработанные сторонними разработчиками или компаниями для добавления новых функциональных возможностей или расширения возможностей существующего движка Unity.
Плагины предоставляют разработчикам готовые решения и инструменты для использования аналитики, визуализации, анимации, физики и других аспектов разработки игр и приложений.
Рассмотрим подробнее возможности плагинов в Unity 3D и особенности, которые необходимо учитывать при их использовании:
1️⃣Предоставление готовых решений:
Речь о возможности быстрой интеграции в проект Unity готовых решений и функциональности, реализованной сторонними разработчиками/компаниями.
Упрощение интеграции:
Как правило, плагины предоставляются в виде Unity Package (.unitypackage), поэтому их установка в проект Unity происходит через простой импорт и делает процесс интеграции быстрым и безболезненным.
Устанавлить плагины можно, как через Unity Package Manager (UPM), так и из сторонних источников.
2️⃣Решение сложных задач:
Часто решение сложных/трудоемких для реализации с нуля задач (например: системы аналитики, системы рекламной интеграцией, работа с физикой, и т.д.) упаковывают в плагины. Используя их, разработчики облегчают решение стоящих перед ними задач и получают проверенное, рабочее решение.
3️⃣Качество и поддержка:
В основном за разработку сторонних плагинов берутся опытные разработчики, они предлагают активную поддержку и обновления своих продуктов.
Это дает уверенность в качестве и надежности предоставляемых решений.
4️⃣Удобство управления платформенными зависимостями через External Dependency Manager (EDM4U) for Unity:
После установки плагина через Unity Package для управления платформенными (Android, iOS, и т.д.) зависимостями и обновлениями плагина можно использовать EDM4U ->
https://openupm.com/packages/com.google.external-dependency-manager/.
Это облегчает поддержку актуальных версий и упрощает процесс интеграции.
Как правило EDM4U входит в Unity Package плагина.
❗За разрешение платформенных зависимостей в EDM4U используется xml файл.
Данный файл должен находиться в директории плагина Editor и иметь имя *Dependencies.xml, где * означает имя директории плагина.
Внутри xml, как правило есть 2 секции:
- androidPackages. Зависимости, которые будут использоваться при Android сборке
- iosPods. Зависимости, которые будут использоваться при iOS сборке.
При конфликте (например при установки Pod'ов в iOS) потребуется модифицировать xml файл и подгонять его под нужные версии.
Под Android (Gradle) сборка, как правило проходит безболезненно.
‼️ℹ️Ниже приведены важные при работе с плагинами моменты, которые позволят избежать потенциальных проблем и сделать процесс разработки на Unity 3D более удобным и эффективным.
Важно:
- Следить за правильным подключением плагинов: все плагины необходимо устанавливать в папки по умолчанию (место будет предложено Unity при установке Unity Package).
Некоторые плагины "нацелены" на папки по умолчанию, и при размещении в альтернативном месте возрастает риск неопределенного поведения.
- Соблюдать версионность EDM4U: устанавливаемая версия должна соответствовать либо быть выше текущей версии, используемой в проекте
- Корректно размещать и именовать xml, отвечающий за решение платформенных зависимостей в EDM4U
- Тестировать работоспособность проекта после каждого изменения или добавления нового плагина.
❗Если в проекте требуется активно использовать предоставляемые плагинами API (например различные системы аналитики), я рекомендую выделить отдельный сервис/сервисы, которые будут использовать этот плагин.
Плагины продолжение 👇
Приветствую, друзья 👋
Сегодняшняя тема посвящена плагинам в Unity 3D
Плагины (или ассеты) в Unity 3D - это дополнительные компоненты, скрипты, ресурсы или библиотеки, разработанные сторонними разработчиками или компаниями для добавления новых функциональных возможностей или расширения возможностей существующего движка Unity.
Плагины предоставляют разработчикам готовые решения и инструменты для использования аналитики, визуализации, анимации, физики и других аспектов разработки игр и приложений.
Рассмотрим подробнее возможности плагинов в Unity 3D и особенности, которые необходимо учитывать при их использовании:
1️⃣Предоставление готовых решений:
Речь о возможности быстрой интеграции в проект Unity готовых решений и функциональности, реализованной сторонними разработчиками/компаниями.
Упрощение интеграции:
Как правило, плагины предоставляются в виде Unity Package (.unitypackage), поэтому их установка в проект Unity происходит через простой импорт и делает процесс интеграции быстрым и безболезненным.
Устанавлить плагины можно, как через Unity Package Manager (UPM), так и из сторонних источников.
2️⃣Решение сложных задач:
Часто решение сложных/трудоемких для реализации с нуля задач (например: системы аналитики, системы рекламной интеграцией, работа с физикой, и т.д.) упаковывают в плагины. Используя их, разработчики облегчают решение стоящих перед ними задач и получают проверенное, рабочее решение.
3️⃣Качество и поддержка:
В основном за разработку сторонних плагинов берутся опытные разработчики, они предлагают активную поддержку и обновления своих продуктов.
Это дает уверенность в качестве и надежности предоставляемых решений.
4️⃣Удобство управления платформенными зависимостями через External Dependency Manager (EDM4U) for Unity:
После установки плагина через Unity Package для управления платформенными (Android, iOS, и т.д.) зависимостями и обновлениями плагина можно использовать EDM4U ->
https://openupm.com/packages/com.google.external-dependency-manager/.
Это облегчает поддержку актуальных версий и упрощает процесс интеграции.
Как правило EDM4U входит в Unity Package плагина.
❗За разрешение платформенных зависимостей в EDM4U используется xml файл.
Данный файл должен находиться в директории плагина Editor и иметь имя *Dependencies.xml, где * означает имя директории плагина.
Внутри xml, как правило есть 2 секции:
- androidPackages. Зависимости, которые будут использоваться при Android сборке
- iosPods. Зависимости, которые будут использоваться при iOS сборке.
При конфликте (например при установки Pod'ов в iOS) потребуется модифицировать xml файл и подгонять его под нужные версии.
Под Android (Gradle) сборка, как правило проходит безболезненно.
‼️ℹ️Ниже приведены важные при работе с плагинами моменты, которые позволят избежать потенциальных проблем и сделать процесс разработки на Unity 3D более удобным и эффективным.
Важно:
- Следить за правильным подключением плагинов: все плагины необходимо устанавливать в папки по умолчанию (место будет предложено Unity при установке Unity Package).
Некоторые плагины "нацелены" на папки по умолчанию, и при размещении в альтернативном месте возрастает риск неопределенного поведения.
- Соблюдать версионность EDM4U: устанавливаемая версия должна соответствовать либо быть выше текущей версии, используемой в проекте
- Корректно размещать и именовать xml, отвечающий за решение платформенных зависимостей в EDM4U
- Тестировать работоспособность проекта после каждого изменения или добавления нового плагина.
❗Если в проекте требуется активно использовать предоставляемые плагинами API (например различные системы аналитики), я рекомендую выделить отдельный сервис/сервисы, которые будут использовать этот плагин.
Плагины продолжение 👇
#архитектура #плагины #Unity3D
Плагины продолжение
Слой сервисов и работа с плагинами
Напомню, слой сервисов разбирали в одной из предыдущих публикаций
Тезисно:
- Слой сервисов отвечает за набор дополнительных сервисов, которые потребуются например для сбора и анализа данных об игроках и их действиях в игре.
- Представляет собой набор классов с публичными методами.
- Сервисный класс должен предоставлять публичный доступ к API, который реализует сервис.
- Сервис создается один раз в нужном узле composition tree.
Далее в виде явной зависимости передаваться в контекстах вниз по иерархии composition tree.
ℹ️Например, если в проекте есть необходимость интегрировать несколько плагинов для работы с аналитикой: AppMetrica, Firebase, Amplitude, Appsflyer, Adjust, Tenjin, и т.д.
Итоговый сервис должен представлять собой один класс, который в конструкторе инстанцирует, инициализирует и дожидается (может происходить асинхронно) готовности каждой системы и имеет набор нужным публичных методов для работы с аналитикой.
При создании инстанса класса используется контекст (мы писали тут), в который можно передать нужные ключи/токены для инициализации плагинов.
Например, пусть сервис для работы с аналитикой называется AnalyticService, тогда один из публичных методов может выглядеть так:
В коде из контекста, вы всегда сможете получить доступ к AnalyticService и вызвать метод Track с нужными параметрами.
Резюмирую все вышесказанное
Сторонние плагины для Unity 3D, совместно с UPM и EDM4U дают значительные преимущества для разработчиков 👇 :
- расширяют возможности Unity, предоставляя готовые решения для сложных задач, таких как интеграция с внешними сервисами, взаимодействие с социальными сетями, поддержка анимации, управление физикой и многое другое.
- облегчают обносления: используя UPM и EDM4U, разработчики могут легко обновлять плагины до последних версий семантического управления версиями.
- гарантируют качество и поддержку: сторонние плагины находятся на поддержке и обновлении у разработчиков. Это гарантирует качество и надежность решений.
- ускоряют разработку: позволяют сэкономить время и ускорить процесс создания игр и приложений в Unity 3D.
- упрощают процесс разработки и повышают понимание кода через использование сервисного слоя в composition tree проекта.
❗Напомню, что ни один плагин не застрахован от багов, поэтому обязательно внимательно тестируйте заявленный функционал.
Благодарю за внимание!
Вопросы в комментариях приветствуются!
Плагины продолжение
Слой сервисов и работа с плагинами
Напомню, слой сервисов разбирали в одной из предыдущих публикаций
Тезисно:
- Слой сервисов отвечает за набор дополнительных сервисов, которые потребуются например для сбора и анализа данных об игроках и их действиях в игре.
- Представляет собой набор классов с публичными методами.
- Сервисный класс должен предоставлять публичный доступ к API, который реализует сервис.
- Сервис создается один раз в нужном узле composition tree.
Далее в виде явной зависимости передаваться в контекстах вниз по иерархии composition tree.
ℹ️Например, если в проекте есть необходимость интегрировать несколько плагинов для работы с аналитикой: AppMetrica, Firebase, Amplitude, Appsflyer, Adjust, Tenjin, и т.д.
Итоговый сервис должен представлять собой один класс, который в конструкторе инстанцирует, инициализирует и дожидается (может происходить асинхронно) готовности каждой системы и имеет набор нужным публичных методов для работы с аналитикой.
При создании инстанса класса используется контекст (мы писали тут), в который можно передать нужные ключи/токены для инициализации плагинов.
Например, пусть сервис для работы с аналитикой называется AnalyticService, тогда один из публичных методов может выглядеть так:
public void Track(string eventName, Dictionary<string, object> data)
{
...
}
В коде из контекста, вы всегда сможете получить доступ к AnalyticService и вызвать метод Track с нужными параметрами.
Резюмирую все вышесказанное
Сторонние плагины для Unity 3D, совместно с UPM и EDM4U дают значительные преимущества для разработчиков 👇 :
- расширяют возможности Unity, предоставляя готовые решения для сложных задач, таких как интеграция с внешними сервисами, взаимодействие с социальными сетями, поддержка анимации, управление физикой и многое другое.
- облегчают обносления: используя UPM и EDM4U, разработчики могут легко обновлять плагины до последних версий семантического управления версиями.
- гарантируют качество и поддержку: сторонние плагины находятся на поддержке и обновлении у разработчиков. Это гарантирует качество и надежность решений.
- ускоряют разработку: позволяют сэкономить время и ускорить процесс создания игр и приложений в Unity 3D.
- упрощают процесс разработки и повышают понимание кода через использование сервисного слоя в composition tree проекта.
❗Напомню, что ни один плагин не застрахован от багов, поэтому обязательно внимательно тестируйте заявленный функционал.
Благодарю за внимание!
Вопросы в комментариях приветствуются!