Доброе утро, друзья!
Подведем итоги опроса "Какими механизмами вы обеспечиваете полиморфизм?".
Первым делом хочу поблагодарить всех, кто принял участие и дал обратную связь 👍
Проголосовало чуть меньше 50% участников, это хороший результат.
Вижу, что вы знакомы с понятием полиморфизма 👍
Итак, на момент подведения итогов большинство из участников, принявших участие, выбрали виртуальные методы ~ 70% из 100%, далее следуют интерфейсы ~60% из 100% и другие конструкции языка лишь ~ 20% из 100%.
Что касается меня, для решения задач слоя бизнес-логики приложения я отдаю предпочтение "другим конструкциям языка". А именно реактивным объектам (из библиотеки UniRx).
Кроме этого к другим конструкциям языка относятся делегаты, шина сообщений и т.д.
Если речь идет про библиотеки, которые не завязаны на бизнес-логику приложения, то для обеспечения полиморфизма подойдут как виртуальные методы, так и интерфейсы.
Почему для решения задач слоя бизнес-логики я стараюсь избегать использования интерфейсов и виртуальных методов. Обеспечение полиморфизма такими способом, как правило, влечет за собой организацию связей в коде проекта через публичные методы. Наличие большого количества интерфейсов ведет к разрастанию кодовой базы, так как для каждого интерфейса нужна как минимум 1 реализация.
В итоге мы придем к коду, который мало устойчив к изменениям, в котором сложно ориентироваться.
При изменении состава команды у новых участников возникнут сложности с использованием публичного API приложения (которое уже было спроектировано).
Будет усиливаться зацепление кода.
Если есть желание поговорить подробнее про использование других конструкций языка, оставьте комментарий ⬇
Подведем итоги опроса "Какими механизмами вы обеспечиваете полиморфизм?".
Первым делом хочу поблагодарить всех, кто принял участие и дал обратную связь 👍
Проголосовало чуть меньше 50% участников, это хороший результат.
Вижу, что вы знакомы с понятием полиморфизма 👍
Итак, на момент подведения итогов большинство из участников, принявших участие, выбрали виртуальные методы ~ 70% из 100%, далее следуют интерфейсы ~60% из 100% и другие конструкции языка лишь ~ 20% из 100%.
Что касается меня, для решения задач слоя бизнес-логики приложения я отдаю предпочтение "другим конструкциям языка". А именно реактивным объектам (из библиотеки UniRx).
Кроме этого к другим конструкциям языка относятся делегаты, шина сообщений и т.д.
Если речь идет про библиотеки, которые не завязаны на бизнес-логику приложения, то для обеспечения полиморфизма подойдут как виртуальные методы, так и интерфейсы.
Почему для решения задач слоя бизнес-логики я стараюсь избегать использования интерфейсов и виртуальных методов. Обеспечение полиморфизма такими способом, как правило, влечет за собой организацию связей в коде проекта через публичные методы. Наличие большого количества интерфейсов ведет к разрастанию кодовой базы, так как для каждого интерфейса нужна как минимум 1 реализация.
В итоге мы придем к коду, который мало устойчив к изменениям, в котором сложно ориентироваться.
При изменении состава команды у новых участников возникнут сложности с использованием публичного API приложения (которое уже было спроектировано).
Будет усиливаться зацепление кода.
Если есть желание поговорить подробнее про использование других конструкций языка, оставьте комментарий ⬇
Привет, друзья 🙂
Ниже анонс тем для ближайших публикаций 👇
Все они вместе с затронутыми ранее темами являются важными составляющими разработки игр.
UPD: для удобства навигации заголовок рассмотренных тем дополнен ссылкой на публикацию
1 Деление игры на слои абстракции
Поговорим про:
- представление (view, отвечает на вопрос: "как")
- слой бизнес-логики (presentation model, отвечает на вопрос: "что делать")
- построение дерева приложения (иерархия или граф entity)
- контентный слой (набор контента, с которым стартует игра)
- слой сервисов (например, рекламный сервис, сервис аналитики) не влияющий на бизнес-логику игры
- слой состояний игровых объектов (state)
2 С чего должен начинаться Unity проект
Поговорим про нюансы на уровне Unity: количечтво точек входа, последовательность старта объектов
3 MonoBehaviour
Обсудим его роль в проекте
4 Организация префабов
Поговорим про правильную организацию и роль слоя view в ней
5 Жизненный цикл объектов
Обсудим, кто за него должен отвечать
6 Изолированность классов
Поговорим о том, как ее обеспечить
7 Dependency Injection
Обсудим, как применять. Затронем DI фреймворки. Разберем, как правильно внедрять зависимости
8 Абстракции
Как не использовать интерфейсы, при этом писать абстрактный код. Полиморфизм
9 Связи
Разберем, как выстроить связи между классами со слабым зацеплением в коде. Рассмотрим применение реактивных объектов из библиотеки UniRx
10 Контент
Как должен выглядеть контент, используемый игровыми объектами
11 Состояние объектов в игре
Поговорим про то, как и где хранить состояние объектов в игре, также состояние мира/игрока
12 Плагины
Обсудим, как использовать сторонние плагины, чтобы они вписывались в общую архитектуру проекта
13 Сериализация и десериализация
Как правильно сериализовать и десериализовать объекты внутри игры.
Ниже анонс тем для ближайших публикаций 👇
Все они вместе с затронутыми ранее темами являются важными составляющими разработки игр.
UPD: для удобства навигации заголовок рассмотренных тем дополнен ссылкой на публикацию
1 Деление игры на слои абстракции
Поговорим про:
- представление (view, отвечает на вопрос: "как")
- слой бизнес-логики (presentation model, отвечает на вопрос: "что делать")
- построение дерева приложения (иерархия или граф entity)
- контентный слой (набор контента, с которым стартует игра)
- слой сервисов (например, рекламный сервис, сервис аналитики) не влияющий на бизнес-логику игры
- слой состояний игровых объектов (state)
2 С чего должен начинаться Unity проект
Поговорим про нюансы на уровне Unity: количечтво точек входа, последовательность старта объектов
3 MonoBehaviour
Обсудим его роль в проекте
4 Организация префабов
Поговорим про правильную организацию и роль слоя view в ней
5 Жизненный цикл объектов
Обсудим, кто за него должен отвечать
6 Изолированность классов
Поговорим о том, как ее обеспечить
7 Dependency Injection
Обсудим, как применять. Затронем DI фреймворки. Разберем, как правильно внедрять зависимости
8 Абстракции
Как не использовать интерфейсы, при этом писать абстрактный код. Полиморфизм
9 Связи
Разберем, как выстроить связи между классами со слабым зацеплением в коде. Рассмотрим применение реактивных объектов из библиотеки UniRx
10 Контент
Как должен выглядеть контент, используемый игровыми объектами
11 Состояние объектов в игре
Поговорим про то, как и где хранить состояние объектов в игре, также состояние мира/игрока
12 Плагины
Обсудим, как использовать сторонние плагины, чтобы они вписывались в общую архитектуру проекта
13 Сериализация и десериализация
Как правильно сериализовать и десериализовать объекты внутри игры.
#слои_абстракции_геймдев #архитектура
Приветствую, друзья.
Сегодня мы обсудим важную тему - разделение игры на слои абстракции. Вопрос является ключевым для создания гибкой и масштабируемой игры. Хотя объем информации достаточно велик, буду стараться дать его как можно более лаконично и понятно.
Слои абстракции - это способ организации кода, который позволяет разделить функциональность приложения на несколько уровней. Каждый уровень отвечает за конкретный аспект решаемой задачи. Что позволяет упростить код и улучшить его читаемость, расширяемость и масштабируемость.
Правильное разделение существенно облегчает жизнь разработчика.
Минимально я выделяю семь слоев, среди них:
- слой бизнес-логики
- слой представления
- слой связей
- слой жизненного цикла объектов
- слой контента
- слой состояния игровых объектов
- слой сервисов.
На практике слои бизнес-логики и представления часто смешивают, что ведет к проблемам в поддержке и расширении функционала игры. Но делает разработку быстрее и проще из-за меньшего количества слоев.
Рассмотрим каждый из слоев подробнее.
Слой бизнес-логики (или presentation model, pm)
Часть, отвечающая на вопрос: "что делать". Содержит правила и логику игры, необходимые для ее функционирования.
Например: идти вперед, собирать предметы, открыть ящик, и т.д.
Слой представление (или view)
Часть, отвечающая на вопрос: "как". Отвечает за отображение игрового мира и взаимодействия с игроком.
Как именно действие должно представляться в игровом мире.
Например: как герой должен бежать вперед, как собирать предметы, как открывать ящик, и т.д.
Проведем аналогию с поездкой на такси:
Мы планируем доехать на такси из пункта "А" в пункт "Б".
Для решения этой задачи мы говорим такси, что нужно сделать.
Что нужно сделать? Доехать из пункта "А" в пункт "Б".
Такси при этом само знает, как именно оно поедет.
В данном случае слоем бизнес-логики (pm) выступает пассажир, который говорит, что делать.
Слоем представления (view) выступает такси, которое знает, как именно нужно ехать.
Слой связей
Отвечает за взаимодействие между объектами в игре.
Например связи между персонажем и окружающим миром или между различными игровыми объектами (враг и оружие). Как правило, cвязи выстраиваются через реактивные объекты: ReactiveProperty и ReactiveCommand.
Слой жизненного цикла объектов
Управляет созданием, удалением и обновлением объектов в игре.
Условно жизненный цикл можно представить в виде дерева или графа, где в каждый определенный момент будут работать определенные ветки.
Узел дерева - это некоторая игровая сущность (или как договорились называть ранее entity), описывающая набор логик, предоставляющая набор представлений, необходимых ресурсов и подготавливающая набор связей (реактивные объекты), которые будут использоваться слоями entity, view и pm для общения.
Игровая сущность (entity) может создавать другие игровые сущности, для связи используются реактивные объекты. Игровые сущности не находятся в иерархии наследования.
Именно слабое зацепление и высокая связность слоев entity, pm, view являются ключевыми факторами для создания гибкого и расширяемого приложения. Слабое зацепление обеспечивается за счет использования реактивных объектов, таких как ReactiveProperty и ReactiveCommand. Это позволяет связывать данные и логику между слоями, не нарушая их инкапсуляцию. В то же время, высокая связность обеспечивает общую логику приложения и облегчает отладку и поддержку кода. Это дает возможность легко модифицировать и расширять приложение без необходимости вносить изменения в другие части кода.
Реализующие их классы должны быть написаны таким образом, чтобы обеспечить инкапсуляцию с механизмом сокрытия.
Код должен быть написан декларативно, используя полиморфизм подтипов.
Продолжение 👇
Приветствую, друзья.
Сегодня мы обсудим важную тему - разделение игры на слои абстракции. Вопрос является ключевым для создания гибкой и масштабируемой игры. Хотя объем информации достаточно велик, буду стараться дать его как можно более лаконично и понятно.
Слои абстракции - это способ организации кода, который позволяет разделить функциональность приложения на несколько уровней. Каждый уровень отвечает за конкретный аспект решаемой задачи. Что позволяет упростить код и улучшить его читаемость, расширяемость и масштабируемость.
Правильное разделение существенно облегчает жизнь разработчика.
Минимально я выделяю семь слоев, среди них:
- слой бизнес-логики
- слой представления
- слой связей
- слой жизненного цикла объектов
- слой контента
- слой состояния игровых объектов
- слой сервисов.
На практике слои бизнес-логики и представления часто смешивают, что ведет к проблемам в поддержке и расширении функционала игры. Но делает разработку быстрее и проще из-за меньшего количества слоев.
Рассмотрим каждый из слоев подробнее.
Слой бизнес-логики (или presentation model, pm)
Часть, отвечающая на вопрос: "что делать". Содержит правила и логику игры, необходимые для ее функционирования.
Например: идти вперед, собирать предметы, открыть ящик, и т.д.
Слой представление (или view)
Часть, отвечающая на вопрос: "как". Отвечает за отображение игрового мира и взаимодействия с игроком.
Как именно действие должно представляться в игровом мире.
Например: как герой должен бежать вперед, как собирать предметы, как открывать ящик, и т.д.
Проведем аналогию с поездкой на такси:
Мы планируем доехать на такси из пункта "А" в пункт "Б".
Для решения этой задачи мы говорим такси, что нужно сделать.
Что нужно сделать? Доехать из пункта "А" в пункт "Б".
Такси при этом само знает, как именно оно поедет.
В данном случае слоем бизнес-логики (pm) выступает пассажир, который говорит, что делать.
Слоем представления (view) выступает такси, которое знает, как именно нужно ехать.
Слой связей
Отвечает за взаимодействие между объектами в игре.
Например связи между персонажем и окружающим миром или между различными игровыми объектами (враг и оружие). Как правило, cвязи выстраиваются через реактивные объекты: ReactiveProperty и ReactiveCommand.
Слой жизненного цикла объектов
Управляет созданием, удалением и обновлением объектов в игре.
Условно жизненный цикл можно представить в виде дерева или графа, где в каждый определенный момент будут работать определенные ветки.
Узел дерева - это некоторая игровая сущность (или как договорились называть ранее entity), описывающая набор логик, предоставляющая набор представлений, необходимых ресурсов и подготавливающая набор связей (реактивные объекты), которые будут использоваться слоями entity, view и pm для общения.
Игровая сущность (entity) может создавать другие игровые сущности, для связи используются реактивные объекты. Игровые сущности не находятся в иерархии наследования.
Именно слабое зацепление и высокая связность слоев entity, pm, view являются ключевыми факторами для создания гибкого и расширяемого приложения. Слабое зацепление обеспечивается за счет использования реактивных объектов, таких как ReactiveProperty и ReactiveCommand. Это позволяет связывать данные и логику между слоями, не нарушая их инкапсуляцию. В то же время, высокая связность обеспечивает общую логику приложения и облегчает отладку и поддержку кода. Это дает возможность легко модифицировать и расширять приложение без необходимости вносить изменения в другие части кода.
Реализующие их классы должны быть написаны таким образом, чтобы обеспечить инкапсуляцию с механизмом сокрытия.
Код должен быть написан декларативно, используя полиморфизм подтипов.
Продолжение 👇
#слои_абстракции_геймдев #архитектура
Слои абстракции продолжение 👇
Слой контента
Отвечает за описание всех игровых и логических объектов и их характеристики, также за конфигурацию игры. Представляет собой набор классов, экземпляры которых не должны модифицироваться в процессе игры.
Классы находятся в строгой иерархии наследования, общий предок всех контентных классов - класс Content.
Поля классов контентного слоя должны иметь публичные модификаторы.
Контентный слой должен предоставлять доступ к каждому уровню контентного дерева в виде типизированной коллекции.
Рассмотрим пример: предположим в игре есть 2 типа зданий: обычные и те, которые поддерживают апгрейд. Тогда иерархия контентных классов будет состоять из:
Content-Building-UpgradableBuilding.
В этом случае контентные коллекции должны выглядеть следующим образом:
Contents - коллекция содержащие все экземпляры классов, которые могут быть приведены к классу Content (экземпляры классов UpgradableBuilding, Buildings, Content).
Buildings - коллекция содержащая все экземпляры классов, которые могут быть приведены к классу Building (экземпляры классов UpgradableBuilding, Buildings).
UpgradableBuilding - коллекция содержащая все экземпляры классов, которые могут быть приведены к классу Building (экземпляры классов UpgradableBuilding).
Доступ к элементам коллекции должен осуществляться через id.
Слой состояния игровых объектов
Отвечает за хранение и обновление состояния объектов в игре.
Если игровой объект, описанный контентным классом, в процессе игры может менять свое состояние, для него явно должен присутствовать отдельный класс - состояние (state).
Классы состояния могут находится в иерархии наследования и должны иметь поля с публичными модификаторами доступа.
У класса состояния должно быть публичное поле contentId.
Те поля, на изменение которых может реагировать слой представления (view), должны быть оформлены в виде реактивных объектов. У контентного класса такого вида должен быть публичный метод CreateState, который вернет созданный экземпляр класса состояния нужного типа.
Экземпляры классов состояний можно сериализовывать, сохранять на диск, отправлять на сервер и при перезапуске игры восстанавливать состояние игрового мира.
Слой сервисов
Отвечает за набор дополнительных сервисов, например для сбора и анализа данных об игроках и их действиях в игре.
Представляет собой набор классов с публичными модификаторами доступа. Сервисный класс должен предоставлять публичный доступ к API, который реализует сервис.
Сервис должен быть создан 1 раз в нужном узле дерева приложения. Далее в виде явной зависимости передаваться вниз по иерархии.
Слои абстракции продолжение 👇
Слой контента
Отвечает за описание всех игровых и логических объектов и их характеристики, также за конфигурацию игры. Представляет собой набор классов, экземпляры которых не должны модифицироваться в процессе игры.
Классы находятся в строгой иерархии наследования, общий предок всех контентных классов - класс Content.
Поля классов контентного слоя должны иметь публичные модификаторы.
Контентный слой должен предоставлять доступ к каждому уровню контентного дерева в виде типизированной коллекции.
Рассмотрим пример: предположим в игре есть 2 типа зданий: обычные и те, которые поддерживают апгрейд. Тогда иерархия контентных классов будет состоять из:
Content-Building-UpgradableBuilding.
В этом случае контентные коллекции должны выглядеть следующим образом:
Contents - коллекция содержащие все экземпляры классов, которые могут быть приведены к классу Content (экземпляры классов UpgradableBuilding, Buildings, Content).
Buildings - коллекция содержащая все экземпляры классов, которые могут быть приведены к классу Building (экземпляры классов UpgradableBuilding, Buildings).
UpgradableBuilding - коллекция содержащая все экземпляры классов, которые могут быть приведены к классу Building (экземпляры классов UpgradableBuilding).
Доступ к элементам коллекции должен осуществляться через id.
Слой состояния игровых объектов
Отвечает за хранение и обновление состояния объектов в игре.
Если игровой объект, описанный контентным классом, в процессе игры может менять свое состояние, для него явно должен присутствовать отдельный класс - состояние (state).
Классы состояния могут находится в иерархии наследования и должны иметь поля с публичными модификаторами доступа.
У класса состояния должно быть публичное поле contentId.
Те поля, на изменение которых может реагировать слой представления (view), должны быть оформлены в виде реактивных объектов. У контентного класса такого вида должен быть публичный метод CreateState, который вернет созданный экземпляр класса состояния нужного типа.
Экземпляры классов состояний можно сериализовывать, сохранять на диск, отправлять на сервер и при перезапуске игры восстанавливать состояние игрового мира.
Слой сервисов
Отвечает за набор дополнительных сервисов, например для сбора и анализа данных об игроках и их действиях в игре.
Представляет собой набор классов с публичными модификаторами доступа. Сервисный класс должен предоставлять публичный доступ к API, который реализует сервис.
Сервис должен быть создан 1 раз в нужном узле дерева приложения. Далее в виде явной зависимости передаваться вниз по иерархии.
📌 UPD: группа желающих сделать тестовое задание для разбора сформирована 💪 всем спасибо за участие 👍
p/s если вы хотели, поучаствовать, но не успели, напишите, что-нибудь придумаем.
Приветствую, друзья 👋
С началом новой недели!
Пока мы готовим очередной пост, предлагаем вам выполнить и отправить на ревью небольшое тестовое задание)
Мы со своей стороны сделаем и опубликуем обезличенный разбор для первых трех желающих.
❗“Эталонный” вариант реализации опубликуем после того, как дадим основную часть теоретического блока)
Итак тестовое задание 🎮:
Игровая сцена разбита на квадраты 100x100.
При входе в игру в клетки игрового поля спавнятся здания 2х типов: простые (статичные) и те, которые могут апгрейдится до определенного уровня.
Каждый уровень здания - новая модель.
В контенте можно задать цепочки апгрейдов для зданий.
Например здание 1 (level 1) - здание 2 (level 2) - здание 3 (level 3).
Игрок (наблюдатель) может управлять камерой (WASD + мышь), чтобы можно свободно передвигаться по сцене. При перемещении нужно учитывать коллизии на зданиях и террейне.
Критерии оценки:
- Декомпозиция задачи ,
- Связи между слоями,
- Дорабатываемость и устойчивость к изменениям.
❗Визуальная составляющая не важна и полностью на ваше усмотрение.
Желающие принять участие, отпишитесь о своем намерении в комментариях к посту либо в личку Ирине.
Если требуется детализация, ждем вопросы.
По времени выполнения, предлагаю ориентироваться на неделю, чтобы была возможность спланировать и выбрать удобное время.
И чур не сходить с дистанции 🧗♂️
Всем продуктивной недели 💪
p/s если вы хотели, поучаствовать, но не успели, напишите, что-нибудь придумаем.
Приветствую, друзья 👋
С началом новой недели!
Пока мы готовим очередной пост, предлагаем вам выполнить и отправить на ревью небольшое тестовое задание)
Мы со своей стороны сделаем и опубликуем обезличенный разбор для первых трех желающих.
❗“Эталонный” вариант реализации опубликуем после того, как дадим основную часть теоретического блока)
Итак тестовое задание 🎮:
Игровая сцена разбита на квадраты 100x100.
При входе в игру в клетки игрового поля спавнятся здания 2х типов: простые (статичные) и те, которые могут апгрейдится до определенного уровня.
Каждый уровень здания - новая модель.
В контенте можно задать цепочки апгрейдов для зданий.
Например здание 1 (level 1) - здание 2 (level 2) - здание 3 (level 3).
Игрок (наблюдатель) может управлять камерой (WASD + мышь), чтобы можно свободно передвигаться по сцене. При перемещении нужно учитывать коллизии на зданиях и террейне.
Критерии оценки:
- Декомпозиция задачи ,
- Связи между слоями,
- Дорабатываемость и устойчивость к изменениям.
❗Визуальная составляющая не важна и полностью на ваше усмотрение.
Желающие принять участие, отпишитесь о своем намерении в комментариях к посту либо в личку Ирине.
Если требуется детализация, ждем вопросы.
По времени выполнения, предлагаю ориентироваться на неделю, чтобы была возможность спланировать и выбрать удобное время.
И чур не сходить с дистанции 🧗♂️
Всем продуктивной недели 💪
Telegram
Irina Zhi
#архитектура
Приветствую, друзья 👋
Сегодня затронем вторую тему из списка и поговорим о количестве точек входа в код проекта.
Точка входа может быть как одна, так и несколько.
Начнём с единой точки входа.
Единая точка входа - это главный скрипт, который инициализирует и контролирует все другие элементы проекта.
Представляет собой MonoBehaviour класс, который может быть легко просмотрен и понят.
В Unity единая точка входа может быть реализована с помощью скриптов и объектов, таких как менеджер сцен или стартовый класс.
Единая точка входа может включать в себя загрузку ресурсов, инициализацию компонентов, конфигурацию параметров и другие важные действия, необходимые для запуска и функционирования приложения.
Основные преимущества единой точки входа:
- возможность контролировать порядок инициализации элементов проекта. Особенно актуально, когда вы работаете с большим количеством ассетов и скриптов, и необходимо гарантировать, что все элементы будут инициализированы в нужном порядке
- улучшение производительности приложения. Достигается за счет того, что единая точка входа позволяет контролировать загрузку и инициализацию только тех элементов, которые необходимы для данного уровня или экрана, что уменьшает нагрузку на устройство
- повышение читаемости и поддерживаемости кода.
Применение единой точки входа является best practice и позволяет создать качественный и надежный продукт, существенно улучшает общую организацию и структуру кода, уменьшает риск возникновения ошибок и проблем с поддержкой, а также упрощает процесс разработки и тестирования.
Что касается нескольких точек входа в код проекта.
При таком подходе каждая точка входа представляет собой отдельный вход в код и может быть реализована с помощью GameObject на сцене.
На каждом GameObject расположены MonoBehaviour скрипты, в методах Awake или Start которых выполняется определенный код.
Использование нескольких точек входа проще в реализации, подходит для прототипов но неэффективно для крупных проектов.
Плюсы использования нескольких точек входа в код:
- простота использования (если речь о прототипах)
- отпадает необходимость задумываться о жизненном цикле объектов.
Минусы использования нескольких точек входа:
- усложнение отладки и увеличение времени на ее проведение
- снижение читаемости кода и усложнение его понимания.
Что касается меня, я являюсь сторонником единой точки входа.
Рассмотрим на примере:
В иерархии объектов на сцене я создаю GameObject с названием Root, на котором размещаю компонент EntryPoint. В Awake создаю первую Entity - RootEntity, далее код развивается древовидно.
В каждую из веток кода можно попасть через навигатор кода.
Каждая Entity, Pm, View включается в себя структуру Ctx, которая описывает все зависимости текущего класса.
В итоге код можно представить в виде дерева.
Кроме того, наличие Ctx в каждой Entity, Pm и View позволяет вам легко отслеживать все зависимости, что улучшает читаемость и поддерживаемость кода.
Приветствую, друзья 👋
Сегодня затронем вторую тему из списка и поговорим о количестве точек входа в код проекта.
Точка входа может быть как одна, так и несколько.
Начнём с единой точки входа.
Единая точка входа - это главный скрипт, который инициализирует и контролирует все другие элементы проекта.
Представляет собой MonoBehaviour класс, который может быть легко просмотрен и понят.
В Unity единая точка входа может быть реализована с помощью скриптов и объектов, таких как менеджер сцен или стартовый класс.
Единая точка входа может включать в себя загрузку ресурсов, инициализацию компонентов, конфигурацию параметров и другие важные действия, необходимые для запуска и функционирования приложения.
Основные преимущества единой точки входа:
- возможность контролировать порядок инициализации элементов проекта. Особенно актуально, когда вы работаете с большим количеством ассетов и скриптов, и необходимо гарантировать, что все элементы будут инициализированы в нужном порядке
- улучшение производительности приложения. Достигается за счет того, что единая точка входа позволяет контролировать загрузку и инициализацию только тех элементов, которые необходимы для данного уровня или экрана, что уменьшает нагрузку на устройство
- повышение читаемости и поддерживаемости кода.
Применение единой точки входа является best practice и позволяет создать качественный и надежный продукт, существенно улучшает общую организацию и структуру кода, уменьшает риск возникновения ошибок и проблем с поддержкой, а также упрощает процесс разработки и тестирования.
Что касается нескольких точек входа в код проекта.
При таком подходе каждая точка входа представляет собой отдельный вход в код и может быть реализована с помощью GameObject на сцене.
На каждом GameObject расположены MonoBehaviour скрипты, в методах Awake или Start которых выполняется определенный код.
Использование нескольких точек входа проще в реализации, подходит для прототипов но неэффективно для крупных проектов.
Плюсы использования нескольких точек входа в код:
- простота использования (если речь о прототипах)
- отпадает необходимость задумываться о жизненном цикле объектов.
Минусы использования нескольких точек входа:
- усложнение отладки и увеличение времени на ее проведение
- снижение читаемости кода и усложнение его понимания.
Что касается меня, я являюсь сторонником единой точки входа.
Рассмотрим на примере:
В иерархии объектов на сцене я создаю GameObject с названием Root, на котором размещаю компонент EntryPoint. В Awake создаю первую Entity - RootEntity, далее код развивается древовидно.
В каждую из веток кода можно попасть через навигатор кода.
Каждая Entity, Pm, View включается в себя структуру Ctx, которая описывает все зависимости текущего класса.
В итоге код можно представить в виде дерева.
Кроме того, наличие Ctx в каждой Entity, Pm и View позволяет вам легко отслеживать все зависимости, что улучшает читаемость и поддерживаемость кода.
#разбортестового
Приветствую, друзья 👋
Сегодня публикуем разбор одного из присланных тестовых заданий.
Разбор представлен в 2-х форматах:
- Видео. Постарался сделать сжато, выделив суть.
- Текстовый. Для тех, кто не планирует смотреть видео.
Но я рекомендую выделить время как на прочтение, так и просмотр)
Итак, приступим, начнем с замечаний
1. Отсутствует единая точка входа.
Вход в код осуществляется в 2 классах:
- SceaneLoader, Awake
- Player, Start.
2. Разделение на слои абстракции.
Выполнено, но не до конца.
Есть классы отвечающие за несколько зон.
Так, например, класс UpgradableBuilding содержит в себе следующие ответственности:
- контент
- бизнес-логика смены зданий
- слой представления.
Класс Player содержит избыточную ответственность:
- бизнес-логику (управление и передвижение камеры)
- слой представления.
3. Слой State.
В текущей реализации будет невозможно создать BuildingController из State в случае сохранения игрового состояния мира на диск и его последующего восстановления.
4. Загрузка ресурсов.
Процесс загрузки ресурсов требует особого внимания. Независимо от сложности проекта, следует описать в комментариях способы загрузки и обработки большого количества ресурсов. В противном случае возможно переполнение оперативной памяти устройства, что может привести к негативным последствиям.
5. Организация префабов с UpgradableBuilding.
Префабы изначально содержат все возможные уровни апгрейда зданий, по умолчанию все кроме первого уровня находятся в неактивном состоянии.
В идеале UpgradableBuilding не должен знать свою цепочку апгрейда.
Возможность задавать цепочку апгрейда должна быть доступна через контент. Это необходимо для того, чтобы гейм-дизайнер или контент-менеджер могли управлять апгрейдом самостоятельно при настройке баланса игры без участия разработки.
Для этого необходим отдельный контентный класс, в котором прописывается:
- уровень,
- id здания, которое апгрейдим,
- id здания, на какое апгрейдим.
6. Использование большого количества MonoBehaviour.
7. Утилитарные классы можно не инстанцировать, вместо этого использовать статические классы и методы. Например, сделать статическим класс GridGenerator, метод GetGrid.
8. Использования постфикса Controller в классах.
Уйти от использования постфикса Controller в классах, это может вызвать диссонанс у проверяющего.
Controller из MVC - это слой, который отвечает за пользовательский ввод и уведомляет модель, далее слой представления рендерит изменения.
8. Использовать namespace.
---
Что понравилось в тестовом:
1. Простота кода
2. Единообразие с методом Init.
Тестовое выполнено довольно неплохо
Спасибо автору за проделанную работу и предоставленный для разбора материал 💪
Всем хорошего дня и прекрасных выходных!
Приветствую, друзья 👋
Сегодня публикуем разбор одного из присланных тестовых заданий.
Разбор представлен в 2-х форматах:
- Видео. Постарался сделать сжато, выделив суть.
- Текстовый. Для тех, кто не планирует смотреть видео.
Но я рекомендую выделить время как на прочтение, так и просмотр)
Итак, приступим, начнем с замечаний
1. Отсутствует единая точка входа.
Вход в код осуществляется в 2 классах:
- SceaneLoader, Awake
- Player, Start.
2. Разделение на слои абстракции.
Выполнено, но не до конца.
Есть классы отвечающие за несколько зон.
Так, например, класс UpgradableBuilding содержит в себе следующие ответственности:
- контент
- бизнес-логика смены зданий
- слой представления.
Класс Player содержит избыточную ответственность:
- бизнес-логику (управление и передвижение камеры)
- слой представления.
3. Слой State.
В текущей реализации будет невозможно создать BuildingController из State в случае сохранения игрового состояния мира на диск и его последующего восстановления.
4. Загрузка ресурсов.
Процесс загрузки ресурсов требует особого внимания. Независимо от сложности проекта, следует описать в комментариях способы загрузки и обработки большого количества ресурсов. В противном случае возможно переполнение оперативной памяти устройства, что может привести к негативным последствиям.
5. Организация префабов с UpgradableBuilding.
Префабы изначально содержат все возможные уровни апгрейда зданий, по умолчанию все кроме первого уровня находятся в неактивном состоянии.
В идеале UpgradableBuilding не должен знать свою цепочку апгрейда.
Возможность задавать цепочку апгрейда должна быть доступна через контент. Это необходимо для того, чтобы гейм-дизайнер или контент-менеджер могли управлять апгрейдом самостоятельно при настройке баланса игры без участия разработки.
Для этого необходим отдельный контентный класс, в котором прописывается:
- уровень,
- id здания, которое апгрейдим,
- id здания, на какое апгрейдим.
6. Использование большого количества MonoBehaviour.
7. Утилитарные классы можно не инстанцировать, вместо этого использовать статические классы и методы. Например, сделать статическим класс GridGenerator, метод GetGrid.
8. Использования постфикса Controller в классах.
Уйти от использования постфикса Controller в классах, это может вызвать диссонанс у проверяющего.
Controller из MVC - это слой, который отвечает за пользовательский ввод и уведомляет модель, далее слой представления рендерит изменения.
8. Использовать namespace.
---
Что понравилось в тестовом:
1. Простота кода
2. Единообразие с методом Init.
Тестовое выполнено довольно неплохо
Спасибо автору за проделанную работу и предоставленный для разбора материал 💪
Всем хорошего дня и прекрасных выходных!
#библиотека_программиста #геймдев #слои_абстракции
Привествую! По просьбам читателей и в дополнение к предыдущим постам, сегодняшняя публицация будет посвящена литературе по слоям абстракции.
К сожалению, хорошей литературы по слоям абстракции в геймдеве я не встречал.
Но для понимания на концептуальном уровне могу посоветовать следующие варианты:
📚
1. Предметно-ориентированное проектирование (DDD). Структуризация сложных программных систем, Эванс Эрик, стр. 79.
2. Архитектура корпоративных программных приложений, Мартин Фаулер, стр. 43.
3. Программист-прагматик. Путь от подмастерья к мастеру, Эндрю Хант, Дэвид Томас, стр. 32.
Приятного прочтения 🙂
Привествую! По просьбам читателей и в дополнение к предыдущим постам, сегодняшняя публицация будет посвящена литературе по слоям абстракции.
К сожалению, хорошей литературы по слоям абстракции в геймдеве я не встречал.
Но для понимания на концептуальном уровне могу посоветовать следующие варианты:
📚
1. Предметно-ориентированное проектирование (DDD). Структуризация сложных программных систем, Эванс Эрик, стр. 79.
2. Архитектура корпоративных программных приложений, Мартин Фаулер, стр. 43.
3. Программист-прагматик. Путь от подмастерья к мастеру, Эндрю Хант, Дэвид Томас, стр. 32.
Приятного прочтения 🙂
Привествую, друзья.
Одна из тем, которой я касаюсь при отборе в команду - использование интерфеса IDisposable.
Перед очередной нашей публикацией предлагаю вам принять участие в опросе 👇
Одна из тем, которой я касаюсь при отборе в команду - использование интерфеса IDisposable.
Перед очередной нашей публикацией предлагаю вам принять участие в опросе 👇
Что случится при вызове метода Dispose в объекте ref типа, который реализует интерфейс IDisposable?
Anonymous Quiz
13%
Освободится память
25%
Освободятся неупраляемые ресурсы
48%
Разрабочик решает, что произойдет
14%
Затрудняюсь ответить
#idisposable #управление_ресурсами
Приветствую, друзья!
Подведем итоги опроса про интерфейс IDisposable 👇
На момент подведения итогов получены следующие результаты:
✅ 44% - разработчик решает, что произойдет
16% - освободится память
26% - освободятся неуправляемые ресурсы
14% - затрудняются ответить.
Как показал опрос использование интерфейса IDisposable в C# часто некорректно связывают только с освобождением памяти или освобождением неуправляемых ресурсов.
‼️ На самом деле сам разработчик может задать сценарий происходящего.
Понимание работы IDisposable понадобится нам для дальнейших публикаций и разбора кода, поэтому приступим.
Один из вариантов использования интерфейса IDisposable в C# - реализация паттерна "ресурсов", суть которого состоит в управлении использованием ресурсов, таких как: файлы, сетевые подключения, базы данных и других неуправляемых ресурсов.
Управляемые ресурсы - это ресурсы, которыми управляет сборщик мусора, такие как объекты ref типа, созданные с использованием оператора new.
Сборщик мусора автоматически освобождает память, выделенную под управляемые ресурсы, когда они больше не используются.
Неуправляемые ресурсы - это ресурсы, которые не попадают под управление сборщика мусора, например: открытые файлы, сетевые подключения, базы данных, оборудование и т.д.
Освобождение неуправляемых ресурсов требует явного вызова методов для их освобождения, что и реализуется через использование интерфейса IDisposable.
Таким образом использование интерфейса IDisposable для реализации паттерна "ресурсов" помогает управлять ресурсами и предотвращать утечки памяти.
Рассмотрим другие сценарии.
Реализация паттерна "заимствования" (borrowing).
Паттерн будет полезен при работе с потоками данных или потоковыми операциями, где необходимо убедиться, что определенные ресурсы используются только одним потоком в определенный момент времени, и избежать ошибок при многопоточной обработке данных.
При данном подходе интерфейс IDisposable используют для создания блоков кода, в которых происходит заимствование (borrowing) ресурса и автоматическое освобождение этого ресурса после завершения блока.
Рассмотрим пример реализации паттерна "заимствования", где использование интерфейса IDisposable позволит гарантировать правильную обработку ресурса и избежать ошибок при работе с потоками данных.
В примере класс StreamResource представляет собой ресурс (поток данных), который может быть заимствован в блоке using, после чего происходит автоматическое освобождение ресурса.
Внутри блока using происходит обработка потока данных.
Таким образом, использование интерфейса IDisposable в рассмотренном примере позволяет гарантировать правильную обработку ресурса и избежать ошибок при работе с потоками данных.
Продолжение 👇
Приветствую, друзья!
Подведем итоги опроса про интерфейс IDisposable 👇
На момент подведения итогов получены следующие результаты:
✅ 44% - разработчик решает, что произойдет
16% - освободится память
26% - освободятся неуправляемые ресурсы
14% - затрудняются ответить.
Как показал опрос использование интерфейса IDisposable в C# часто некорректно связывают только с освобождением памяти или освобождением неуправляемых ресурсов.
‼️ На самом деле сам разработчик может задать сценарий происходящего.
Понимание работы IDisposable понадобится нам для дальнейших публикаций и разбора кода, поэтому приступим.
Один из вариантов использования интерфейса IDisposable в C# - реализация паттерна "ресурсов", суть которого состоит в управлении использованием ресурсов, таких как: файлы, сетевые подключения, базы данных и других неуправляемых ресурсов.
Управляемые ресурсы - это ресурсы, которыми управляет сборщик мусора, такие как объекты ref типа, созданные с использованием оператора new.
Сборщик мусора автоматически освобождает память, выделенную под управляемые ресурсы, когда они больше не используются.
Неуправляемые ресурсы - это ресурсы, которые не попадают под управление сборщика мусора, например: открытые файлы, сетевые подключения, базы данных, оборудование и т.д.
Освобождение неуправляемых ресурсов требует явного вызова методов для их освобождения, что и реализуется через использование интерфейса IDisposable.
Таким образом использование интерфейса IDisposable для реализации паттерна "ресурсов" помогает управлять ресурсами и предотвращать утечки памяти.
Рассмотрим другие сценарии.
Реализация паттерна "заимствования" (borrowing).
Паттерн будет полезен при работе с потоками данных или потоковыми операциями, где необходимо убедиться, что определенные ресурсы используются только одним потоком в определенный момент времени, и избежать ошибок при многопоточной обработке данных.
При данном подходе интерфейс IDisposable используют для создания блоков кода, в которых происходит заимствование (borrowing) ресурса и автоматическое освобождение этого ресурса после завершения блока.
Рассмотрим пример реализации паттерна "заимствования", где использование интерфейса IDisposable позволит гарантировать правильную обработку ресурса и избежать ошибок при работе с потоками данных.
class StreamResource : IDisposable
{
private Stream _stream;
public StreamResource(Stream stream)
{
_stream = stream;
}
public Stream GetStream()
{
return _stream;
}
public void Dispose()
{
_stream = null;
}
}
// Использование ресурса в блоке using
using (var resource = new StreamResource(new FileStream("file.txt", FileMode.Open)))
{
var stream = resource.GetStream();
// обработка потока данных
}
В примере класс StreamResource представляет собой ресурс (поток данных), который может быть заимствован в блоке using, после чего происходит автоматическое освобождение ресурса.
Внутри блока using происходит обработка потока данных.
Таким образом, использование интерфейса IDisposable в рассмотренном примере позволяет гарантировать правильную обработку ресурса и избежать ошибок при работе с потоками данных.
Продолжение 👇
#idisposable #управление_ресурсами
IDisposable продолжение 👇
Другим примером использования интерфейса IDisposable является реализация механизма отмены операции или транзакции.
Например, у вас есть сложная операция, которую нужно выполнить в несколько этапов, и необходима возможность отмены операции в любой момент времени.
Рассмотрим реализацию механизма отмены операции на примере:
В примере класс Operation представляет собой операцию, которая может быть выполнена и отменена.
В блоке using используется операция с возможностью отмены.
Если операция завершается успешно, то она просто выполняется, и интерфейс IDisposable не используется.
Если же происходит ошибка, то операция отменяется с помощью метода Cancel, который также вызывается при автоматическом освобождении ресурса благодаря интерфейсу IDisposable.
Использование интерфейс IDisposable в рассмотренном выше примере позволяет реализовать механизм отмены и гарантировать, что операция будет правильно завершена или отменена в любом случае.
✅ Итак, мы рассмотрели варианты использования интерфейса IDisposable для реализации:
- паттерна "ресурсы" для управления ресурсам и предотвращения утечек памяти
- паттерна "заимствования" (borrowing) для работы с потоками данных
- реализация механизма отмены операции или транзакции.
Всем хорошего дня 👋
Для тех, кто планирует более глубокое погружение, в следующем посте подборка тематической литературы 👇
IDisposable продолжение 👇
Другим примером использования интерфейса IDisposable является реализация механизма отмены операции или транзакции.
Например, у вас есть сложная операция, которую нужно выполнить в несколько этапов, и необходима возможность отмены операции в любой момент времени.
Рассмотрим реализацию механизма отмены операции на примере:
class Operation : IDisposable
{
private bool _isCompleted = false;
public void Execute()
{
// выполнение операции
_isCompleted = true;
}
public void Cancel()
{
if (!_isCompleted)
{
// отмена операции
_isCompleted = true;
}
}
public void Dispose()
{
if (!_isCompleted)
{
Cancel();
}
}
}
// Использование операции с возможностью отмены
using (var operation = new Operation())
{
try
{
operation.Execute();
// выполнение операции
}
catch (Exception ex)
{
// обработка ошибки
operation.Cancel();
}
}
В примере класс Operation представляет собой операцию, которая может быть выполнена и отменена.
В блоке using используется операция с возможностью отмены.
Если операция завершается успешно, то она просто выполняется, и интерфейс IDisposable не используется.
Если же происходит ошибка, то операция отменяется с помощью метода Cancel, который также вызывается при автоматическом освобождении ресурса благодаря интерфейсу IDisposable.
Использование интерфейс IDisposable в рассмотренном выше примере позволяет реализовать механизм отмены и гарантировать, что операция будет правильно завершена или отменена в любом случае.
✅ Итак, мы рассмотрели варианты использования интерфейса IDisposable для реализации:
- паттерна "ресурсы" для управления ресурсам и предотвращения утечек памяти
- паттерна "заимствования" (borrowing) для работы с потоками данных
- реализация механизма отмены операции или транзакции.
Всем хорошего дня 👋
Для тех, кто планирует более глубокое погружение, в следующем посте подборка тематической литературы 👇
#библиотека_программиста #геймдев #idisposable
Подборка литературы по использованию IDisposable.
📚
1. Де Смет, Барт. C# 5.0 Unleashed, глава 20, "Диспозиция и финализация".
2. Скит, Джон. C# in Depth, глава 6, "Размещение объектов и сборка мусора".
3. MSDN. "Использование using в C#", (https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/using-statement).
4. CodeProject. "Implementing IDisposable and the Dispose Pattern Properly", (https://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P).
5. Albahari, Joseph and Albahari, Ben. C# 9.0 in a Nutshell: The Definitive Reference, глава 9, "Memory Management, Pointers, and Unsafe Code".
6. Nagel, Christian. Professional C# 7 and .NET Core 2.0, глава 21, "Unsafe Code and Pointers".
7. Скит, Джон. C# in Depth, глава 15, "Unsafe code and pointers".
8.Agafonov, Eugene. Mastering C# Concurrency: Write Flawless C# Code for Concurrent and Parallel Programming, глава 7, "Low-level Threading in C#".
9. Miles, Rob. C# Programming Yellow Book, глава 25, "Unsafe Code".
10. Официальная документация Microsoft по C#, раздел "Unsafe Code and Pointers".
11. C# Language Specification, раздел "28.1 Pointer types".
Приятного прочтения 🙂
Подборка литературы по использованию IDisposable.
📚
1. Де Смет, Барт. C# 5.0 Unleashed, глава 20, "Диспозиция и финализация".
2. Скит, Джон. C# in Depth, глава 6, "Размещение объектов и сборка мусора".
3. MSDN. "Использование using в C#", (https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/using-statement).
4. CodeProject. "Implementing IDisposable and the Dispose Pattern Properly", (https://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P).
5. Albahari, Joseph and Albahari, Ben. C# 9.0 in a Nutshell: The Definitive Reference, глава 9, "Memory Management, Pointers, and Unsafe Code".
6. Nagel, Christian. Professional C# 7 and .NET Core 2.0, глава 21, "Unsafe Code and Pointers".
7. Скит, Джон. C# in Depth, глава 15, "Unsafe code and pointers".
8.Agafonov, Eugene. Mastering C# Concurrency: Write Flawless C# Code for Concurrent and Parallel Programming, глава 7, "Low-level Threading in C#".
9. Miles, Rob. C# Programming Yellow Book, глава 25, "Unsafe Code".
10. Официальная документация Microsoft по C#, раздел "Unsafe Code and Pointers".
11. C# Language Specification, раздел "28.1 Pointer types".
Приятного прочтения 🙂
Docs
оператор using — обеспечение правильного использования удаленных объектов - C# reference
Использование инструкции или объявления C# для обеспечения правильного использования удаленных объектов
GameDev: разработка на Unity3D pinned «Пост - приветствие 👋 Новый год - время новых начинаний, и к наступающему новому 2023 году мы подошли с решением и готовностью создать канал, посвященный разработке игр на Unity. Мы - это Сергей и Ирина Жильниковы. О Сергее: Более 15 лет в разработке…»
#monobehaviour #архитектура
Приветствую, друзья 👋
Сегодняшняя публикация посвящена роли MonoBehaviour в проекте.
MonoBehaviour - это базовый класс в Unity, который используется для написания скриптов, управляющих поведением игровых объектов.
Он предоставляет множество методов жизненного цикла, которые могут быть переопределены для реализации логики игровых объектов.
Некоторые из основных методов, используемые в жизненном цикле объекта, включают в себя:
- Awake(): вызывается при создании объекта после инициализации всех его компонентов, но до того, как он станет активным в иерархии сцены.
- Start(): вызывается после Awake() и до первого обновления фрейма.
✅ В методе можно инициализировать переменные и компоненты, которые зависят от других объектов в сцене.
- Update(): вызывается каждый кадр и используется для обновления поведения объекта.
✅ В методе можно изменять свойства объекта, перемещать его, обрабатывать ввод и т.д.
- FixedUpdate(): вызывается с фиксированной частотой и используется для обновления физики объекта.
✅ Метод должен использоваться всякий раз, когда вам нужно изменять физические свойства объекта, такие как скорость, позиция, силы и т.д.
- LateUpdate(): вызывается после того, как все объекты обновили свои позиции в текущем кадре.
✅ Метод полезен, когда необходимо обновить объект, исходя из его новой позиции после обновления других объектов.
- OnEnable(): вызывается, когда объект становится активным в иерархии сцены.
- OnDisable(): вызывается, когда объект становится неактивным в иерархии сцены.
- OnDestroy(): вызывается перед уничтожением объекта.
В дополнение к методам, MonoBehaviour имеет свойства, ниже некоторые из них:
- transform - для доступа к компоненту Transform объекта,
- gameObject - для доступа к объекту, на котором находится компонент
- и многие другие, которые позволяют получить доступ к различным свойствам и компонентам объекта.
С помощью MonoBehaviour можно реализовать множество функций, например:
- управление движением объектов,
- обработка столкновений,
- взаимодействие с пользователем и многое другое.
⛔На практике разработчики часто смешивают слои бизнес-логики, представления и контента в наследнике MonoBehaviour.
Такое смешение является плохой практикой по нескольким причинам:
1. Нарушение принципа единственной ответственности (SRP).
Каждый класс должен быть ответственным только за одну вещь, и смешение различных слоев функциональности в одном классе приводит к необходимости поддерживать несколько ответственностей одновременно.
Это усложняет код и его тестирование, увеличивает количество ошибок.
2. Сложность переноса и интеграции кода.
Когда вся функциональность приложения сосредоточена в наследнике MonoBehaviour, усложняется перенос в другую среду или интеграции с другими проектами.
Разделение функциональности на различные классы и слои позволяет легче переносить код и переиспользовать его.
3. Сложность тестирования.
Когда код приложения находится в одном монолитном классе, усложняется тестирование. Возникает необходимость создания сложных тестовых сценариев для проверки функциональности, что ведет к росту времени и увеличивает вероятность возниконовения ошибок.
4. Нарушение принципа разделения интерфейса и реализации (ISP).
Классы должны предоставлять только те методы и свойства, которые необходимы для работы с ними, а не всю функциональность приложения.
Смешение различных слоев функциональности в одном классе нарушает ISP и делает код менее гибким и модульным.
5. Усложнение поддержки кода.
Смешение различных слоев функциональности в одном классе делает код менее читабельным и понятным для других разработчиков.
Это усложняет поддержку и дальнейшее развитие приложения.
6. Трудности в отслеживании состояния объектов и их взаимодействия друг с другом.
Часто компоненты MonoBehaviour создаются и удаляются динамически в зависимости от событий в игре, подобное использование MonoBehaviour может сделать код менее гибким и менее управляемым.
Продолжение 👇
Приветствую, друзья 👋
Сегодняшняя публикация посвящена роли MonoBehaviour в проекте.
MonoBehaviour - это базовый класс в Unity, который используется для написания скриптов, управляющих поведением игровых объектов.
Он предоставляет множество методов жизненного цикла, которые могут быть переопределены для реализации логики игровых объектов.
Некоторые из основных методов, используемые в жизненном цикле объекта, включают в себя:
- Awake(): вызывается при создании объекта после инициализации всех его компонентов, но до того, как он станет активным в иерархии сцены.
- Start(): вызывается после Awake() и до первого обновления фрейма.
✅ В методе можно инициализировать переменные и компоненты, которые зависят от других объектов в сцене.
- Update(): вызывается каждый кадр и используется для обновления поведения объекта.
✅ В методе можно изменять свойства объекта, перемещать его, обрабатывать ввод и т.д.
- FixedUpdate(): вызывается с фиксированной частотой и используется для обновления физики объекта.
✅ Метод должен использоваться всякий раз, когда вам нужно изменять физические свойства объекта, такие как скорость, позиция, силы и т.д.
- LateUpdate(): вызывается после того, как все объекты обновили свои позиции в текущем кадре.
✅ Метод полезен, когда необходимо обновить объект, исходя из его новой позиции после обновления других объектов.
- OnEnable(): вызывается, когда объект становится активным в иерархии сцены.
- OnDisable(): вызывается, когда объект становится неактивным в иерархии сцены.
- OnDestroy(): вызывается перед уничтожением объекта.
В дополнение к методам, MonoBehaviour имеет свойства, ниже некоторые из них:
- transform - для доступа к компоненту Transform объекта,
- gameObject - для доступа к объекту, на котором находится компонент
- и многие другие, которые позволяют получить доступ к различным свойствам и компонентам объекта.
С помощью MonoBehaviour можно реализовать множество функций, например:
- управление движением объектов,
- обработка столкновений,
- взаимодействие с пользователем и многое другое.
⛔На практике разработчики часто смешивают слои бизнес-логики, представления и контента в наследнике MonoBehaviour.
Такое смешение является плохой практикой по нескольким причинам:
1. Нарушение принципа единственной ответственности (SRP).
Каждый класс должен быть ответственным только за одну вещь, и смешение различных слоев функциональности в одном классе приводит к необходимости поддерживать несколько ответственностей одновременно.
Это усложняет код и его тестирование, увеличивает количество ошибок.
2. Сложность переноса и интеграции кода.
Когда вся функциональность приложения сосредоточена в наследнике MonoBehaviour, усложняется перенос в другую среду или интеграции с другими проектами.
Разделение функциональности на различные классы и слои позволяет легче переносить код и переиспользовать его.
3. Сложность тестирования.
Когда код приложения находится в одном монолитном классе, усложняется тестирование. Возникает необходимость создания сложных тестовых сценариев для проверки функциональности, что ведет к росту времени и увеличивает вероятность возниконовения ошибок.
4. Нарушение принципа разделения интерфейса и реализации (ISP).
Классы должны предоставлять только те методы и свойства, которые необходимы для работы с ними, а не всю функциональность приложения.
Смешение различных слоев функциональности в одном классе нарушает ISP и делает код менее гибким и модульным.
5. Усложнение поддержки кода.
Смешение различных слоев функциональности в одном классе делает код менее читабельным и понятным для других разработчиков.
Это усложняет поддержку и дальнейшее развитие приложения.
6. Трудности в отслеживании состояния объектов и их взаимодействия друг с другом.
Часто компоненты MonoBehaviour создаются и удаляются динамически в зависимости от событий в игре, подобное использование MonoBehaviour может сделать код менее гибким и менее управляемым.
Продолжение 👇
#monobehaviour #архитектура
Продолжение Роль MonoBehaviour в проекте 👇
✅Что же является хорошей практикой?
Хорошей практикой является использование MonoBehaviour в качестве слоя View в Unity проекте.
Несколько правил, которые сделают использование данного класса эффективным:
1. Разделяйте логику и представление:
MonoBehaviour должен использоваться только для отображения объектов на сцене
2. Разделяйте игровые логики в отдельные классы:
Все игровые логики должны быть разделены в отдельных классах. Это обеспечит легкость понимания кода и возможность повторного использования
ℹ️ исключение может составлять логика, которая используется для работы самого представления.
Вопросы в комментариях приветствуются!
Лёгкой и продуктивной недели 💪
Продолжение Роль MonoBehaviour в проекте 👇
✅Что же является хорошей практикой?
Хорошей практикой является использование MonoBehaviour в качестве слоя View в Unity проекте.
Несколько правил, которые сделают использование данного класса эффективным:
1. Разделяйте логику и представление:
MonoBehaviour должен использоваться только для отображения объектов на сцене
2. Разделяйте игровые логики в отдельные классы:
Все игровые логики должны быть разделены в отдельных классах. Это обеспечит легкость понимания кода и возможность повторного использования
ℹ️ исключение может составлять логика, которая используется для работы самого представления.
Вопросы в комментариях приветствуются!
Лёгкой и продуктивной недели 💪
Приветствую, друзья 👋
По плану публикаций следующая тема должна быть посвящена организации префабов и роли слоя view в ней.
Но нам поступило несколько запросов на пост про CI/CD.
Поэтому предлагаем вам принять участие в опросе и выбрать тему следующей публикации 🙂
Поехали 👇
По плану публикаций следующая тема должна быть посвящена организации префабов и роли слоя view в ней.
Но нам поступило несколько запросов на пост про CI/CD.
Поэтому предлагаем вам принять участие в опросе и выбрать тему следующей публикации 🙂
Поехали 👇
Выбираем тему следующей публикации 👇
Final Results
57%
Организация префабов и роль слоя view в ней
43%
CI/CD в игровой разработке
#архитектура #prefab #view
Приветствую, друзья! 👋
По результатам голосования за выбор темы публикации между "Организацией префабов и роли слоя view в ней" и "CI/CD в игровой разработке" с результатом 57% победу одержали префабы.
Поэтому сегодня говорим про организацию префабов и роль слоя view в ней.
Начнем с организации.
Организация префабов в Unity - важный аспект процесса разработки игры.
Префаб - заранее созданный объект, который можно использовать в разных сценах игры.
Правильная организация позволит упростить процесс разработки, и организовать префабы таким образом, чтобы они были легко доступны и понятны для всей команды.
✅ Советы по организации префабов:
- Создание папок
Распределяйте префабы по папкам в соответствии с их функциональным назначением. Это упростит поиски нужного префаба. Например, разные папки для префабов игровых персонажей, окружения, звуков и т.д.
- Именование префабов
Имя префаба должно отражать его суть.
Ясные и понятные имена для каждого префаба позволяют легче его идентифицировать и искать.
- Использование тегов
Unity позволяет назначать теги для объектов, включая префабы.
Это упрощает поиск в больших проектах.
Назначение одного и того же тега нескольким префабам, позволит сгруппировать их вместе.
- Использование переменных
Используйте переменные для определения свойств префабов.
Например, переменная для определения здоровья игрового персонажа или скорости движения.
- Обновление префабов
При обновлении префаба, задействованного в сцене, убедитесь, что изменения не нарушит логику игры.
Например, если вы обновляете префаб игрового персонажа, убедитесь, что изменения не приведут к проблемам с анимацией или поведением персонажа.
- Переиспользование префабов
Будет полезно, если вы хотите создать множество однотипных объектов.
Например, при создании уровня, который включает множество блоков, можно создать префаб блока и использовать его для всех блоков в уровне.
Переиспользование префабов может значительно упростить процесс разработки игры в Unity, поскольку это позволяет использовать один раз созданный объект в разных частях игры.
✅ Советы по правильному переиспользованию префабов:
- Универсальность
Если планируется использование префаба в разных сценах игры, сделайте его универсальным для всех этих сцен.
Например, если вы создаете префаб здания, которое будет использоваться в разных уровнях игры, убедитесь, что он подходит для любого уровня, не только для текущего.
- Настраиваемость
Префабы могут быть настроены для изменения свойств в режиме редактирования Unity.
Например, вы можете создать префаб игрового персонажа и настроить его для разных типов персонажей, таких как главный герой, противники и т.д.
Это может упростить процесс создания игровых объектов в будущем.
- Версионнирование
Если вы обновляете префаб, который уже используется в игре, убедитесь, что новая версия не повлияет на уже созданные объекты.
Хорошей практикой является создание новых версий префаба с новым именем и обновление ссылок на них в игре.
- Документирование
Хорошей практикой является документирование использования префабов, чтобы другие члены команды знали как и могли легко использовать их в своей работе.
- Тестирование
Перед тем, как использовать префаб в игре, убедитесь, что он работает правильно.
Протестируйте его в разных условиях и убедитесь, что он работает корректно.
Продолжение 👇
Приветствую, друзья! 👋
По результатам голосования за выбор темы публикации между "Организацией префабов и роли слоя view в ней" и "CI/CD в игровой разработке" с результатом 57% победу одержали префабы.
Поэтому сегодня говорим про организацию префабов и роль слоя view в ней.
Начнем с организации.
Организация префабов в Unity - важный аспект процесса разработки игры.
Префаб - заранее созданный объект, который можно использовать в разных сценах игры.
Правильная организация позволит упростить процесс разработки, и организовать префабы таким образом, чтобы они были легко доступны и понятны для всей команды.
✅ Советы по организации префабов:
- Создание папок
Распределяйте префабы по папкам в соответствии с их функциональным назначением. Это упростит поиски нужного префаба. Например, разные папки для префабов игровых персонажей, окружения, звуков и т.д.
- Именование префабов
Имя префаба должно отражать его суть.
Ясные и понятные имена для каждого префаба позволяют легче его идентифицировать и искать.
- Использование тегов
Unity позволяет назначать теги для объектов, включая префабы.
Это упрощает поиск в больших проектах.
Назначение одного и того же тега нескольким префабам, позволит сгруппировать их вместе.
- Использование переменных
Используйте переменные для определения свойств префабов.
Например, переменная для определения здоровья игрового персонажа или скорости движения.
- Обновление префабов
При обновлении префаба, задействованного в сцене, убедитесь, что изменения не нарушит логику игры.
Например, если вы обновляете префаб игрового персонажа, убедитесь, что изменения не приведут к проблемам с анимацией или поведением персонажа.
- Переиспользование префабов
Будет полезно, если вы хотите создать множество однотипных объектов.
Например, при создании уровня, который включает множество блоков, можно создать префаб блока и использовать его для всех блоков в уровне.
Переиспользование префабов может значительно упростить процесс разработки игры в Unity, поскольку это позволяет использовать один раз созданный объект в разных частях игры.
✅ Советы по правильному переиспользованию префабов:
- Универсальность
Если планируется использование префаба в разных сценах игры, сделайте его универсальным для всех этих сцен.
Например, если вы создаете префаб здания, которое будет использоваться в разных уровнях игры, убедитесь, что он подходит для любого уровня, не только для текущего.
- Настраиваемость
Префабы могут быть настроены для изменения свойств в режиме редактирования Unity.
Например, вы можете создать префаб игрового персонажа и настроить его для разных типов персонажей, таких как главный герой, противники и т.д.
Это может упростить процесс создания игровых объектов в будущем.
- Версионнирование
Если вы обновляете префаб, который уже используется в игре, убедитесь, что новая версия не повлияет на уже созданные объекты.
Хорошей практикой является создание новых версий префаба с новым именем и обновление ссылок на них в игре.
- Документирование
Хорошей практикой является документирование использования префабов, чтобы другие члены команды знали как и могли легко использовать их в своей работе.
- Тестирование
Перед тем, как использовать префаб в игре, убедитесь, что он работает правильно.
Протестируйте его в разных условиях и убедитесь, что он работает корректно.
Продолжение 👇
#архитектура #prefab #view
Продолжение Роль слоя view в префабах 👇
View - наследник MonoBehaviour.
Его роль в организации префабов заключается в разделения ответственности между слоями представления и бизнес-логики.
Такой подход упрощает поддержку кода и делает его более гибким и масштабируемым.
View отвечает за отображение данных в игровом мире и может сообщать о них, также реагирует на изменение данных в pm.
Возможность реагировать на изменение данных в pm, отслеживать их и вызывать команды из слоя представления достигается через использование реактивных объектов, таких как ReactiveProperty или ReactiveCommand, помогает обеспечить правильное взаимодействие между слоями, упростить тестирование и отладку кода.
ReactiveProperty - это реактивный объект, который автоматически оповещает все подписанные на него объекты об изменении своего значения.
Он может использоваться для отслеживания изменений свойств.
Например, текущего здоровья игрока или его координат на карте.
ReactiveCommand - это реактивный объект, который представляет собой команду, которую можно вызвать.
Он позволяет разделять ответственность между слоем представления и pm, так как view не знает, что происходит за его пределами.
Например, при нажатии на кнопку "атаковать" в интерфейсе игрока, ReactiveCommand вызывает метод pm, который обрабатывает эту команду.
Кроме того, использование view позволяет легко настраивать префабы и создавать новые визуальные элементы, не затрагивая при этом pm.
Например, можно добавить новый элемент интерфейса, который будет отображать текущую скорость игрока, и при этом не вносить изменений в pm.
✅ Правила организации префабов с помощью View:
1. Каждый префаб должен иметь свой рутовый GameObject, на который необходимо повесить класс view.
2. В классе view необходимо явно прописать набор зависимостей
Набор зависимостей заполняем перетаскиванием. Они будут представлять собой другие GameObject'ы из иерархии префаба, необходимые для корректного отображения данных.
Например, у игрока может быть HpBar, который является дочерним объектом рутового GameObject'а, на котором также висит свой view класс.
Пример из Unity
3. В каждом классе view должен быть публичный метод SetCtx.
SetCtx вызывается при инициализации view через код в классе entity, после инстанцирования префаба.
Данный метод принимает контекст (обычно это структура) в виде зависимости.
Пример кода
Контекст должен содержать все необходимые зависимости для работы view.
Например, текущее здоровье игрока или его координаты на карте, реактивные объекты, контент.
Пример кода
‼️ Контекст view не должен содержать: context, entity, pm, view, content, state, так как в таком случае вы усилите зацепление.
Таким образом, использование view в организации префабов является важным элементом архитектуры Unity-проектов, который позволяет разделять ответственность между view и pm, упрощает поддержку и расширение кода и делает проект более гибким и масштабируемым.
Продолжение Роль слоя view в префабах 👇
View - наследник MonoBehaviour.
Его роль в организации префабов заключается в разделения ответственности между слоями представления и бизнес-логики.
Такой подход упрощает поддержку кода и делает его более гибким и масштабируемым.
View отвечает за отображение данных в игровом мире и может сообщать о них, также реагирует на изменение данных в pm.
Возможность реагировать на изменение данных в pm, отслеживать их и вызывать команды из слоя представления достигается через использование реактивных объектов, таких как ReactiveProperty или ReactiveCommand, помогает обеспечить правильное взаимодействие между слоями, упростить тестирование и отладку кода.
ReactiveProperty - это реактивный объект, который автоматически оповещает все подписанные на него объекты об изменении своего значения.
Он может использоваться для отслеживания изменений свойств.
Например, текущего здоровья игрока или его координат на карте.
ReactiveCommand - это реактивный объект, который представляет собой команду, которую можно вызвать.
Он позволяет разделять ответственность между слоем представления и pm, так как view не знает, что происходит за его пределами.
Например, при нажатии на кнопку "атаковать" в интерфейсе игрока, ReactiveCommand вызывает метод pm, который обрабатывает эту команду.
Кроме того, использование view позволяет легко настраивать префабы и создавать новые визуальные элементы, не затрагивая при этом pm.
Например, можно добавить новый элемент интерфейса, который будет отображать текущую скорость игрока, и при этом не вносить изменений в pm.
✅ Правила организации префабов с помощью View:
1. Каждый префаб должен иметь свой рутовый GameObject, на который необходимо повесить класс view.
2. В классе view необходимо явно прописать набор зависимостей
Набор зависимостей заполняем перетаскиванием. Они будут представлять собой другие GameObject'ы из иерархии префаба, необходимые для корректного отображения данных.
Например, у игрока может быть HpBar, который является дочерним объектом рутового GameObject'а, на котором также висит свой view класс.
Пример из Unity
3. В каждом классе view должен быть публичный метод SetCtx.
SetCtx вызывается при инициализации view через код в классе entity, после инстанцирования префаба.
Данный метод принимает контекст (обычно это структура) в виде зависимости.
Пример кода
Контекст должен содержать все необходимые зависимости для работы view.
Например, текущее здоровье игрока или его координаты на карте, реактивные объекты, контент.
Пример кода
‼️ Контекст view не должен содержать: context, entity, pm, view, content, state, так как в таком случае вы усилите зацепление.
Таким образом, использование view в организации префабов является важным элементом архитектуры Unity-проектов, который позволяет разделять ответственность между view и pm, упрощает поддержку и расширение кода и делает проект более гибким и масштабируемым.