Один из секретов быстрой и качественной разработки это унификация. В этой статье мы рассмотрим пример реализации Универсального Автономного Модуля UAM (Universal Autonomous Module). 

В прошлой статье мы уже говорили о концепции модульной архитектуры, если вы еще не знакомы, то переходите по ссылке Модульная архитектура в Unity. Та концепция хоть и имела кучу плюсов, но не подходила ко всем типам проектов/жанрам. Сегодня же мы рассмотрим более распространенный и универсальный подход к реализации модулей. Подобные модули в Unity сообществе иногда называют более обобщенно - ассетами, в статье не будет использоваться такое обобщение. 

Однажды заказчик (издатель) выдал нам техническое задание на разработку модуля, который должен легко интегрироваться в любой проект, всех студий издателя. Но не будем вдаваться в подробности этого конкретного модуля. Представьте что вам досталась такая задача. Что бы вы делали? Таким модулем может быть что-то часто встречающееся в приложениях. Например внутриигровой магазин или еще что либо. В статье будет взят за пример реализация лидерборда для мобилок и планшетов. 

Цель ясна, осталось расписать задачи и реализовать модуль.

Задачи или же критерии модуля получились следующие:

  1. Модуль должен быть универсальным. То есть подходить к любому проекту. 

  2. Модуль должен быть автономным. Должен работать не требуя дополнительных пакетов. Он должен самостоятельно функционировать, если его интегрировать в пустой проект.

  3. Так как модуль полностью автономный, он имеет свою вьюшку, свой контент: окна, кнопки, звуки итп. Поэтому при необходимости должен легко редактироваться, и не иметь в дальнейшем проблем при обновлении версии модуля.

    Визуальную составляющую можно менять, но лучше сделать и использовать нейтральный UI/UX дизайн подходящий к любому приложению. Такое решение возникло в связи с современными требованиями к дизайну приложений. Нынешние пользователи мобильных приложений чаще выбирают что-то уже знакомое чем что-то новое.

  4. Интеграция модуля в проект должна быть простой и не занимать много времени. Для интеграции к модулю должна прилагаться документация, с пошаговой инструкцией.

  5. * Перед релизом модуль необходимо протестировать. 

Большими преимуществами модулей являются безопасность, надежность и качество. Так как модули обособлены от остальной части проекта, ничто не нарушает их работу. Тестирование модулей выполняется при их разработке. Далее будучи в связке с проектом тестирование им уже не требуется. Что соответственно сокращает время на тестирование проекта в целом.

Представим что функционал и спецификация лидерборда будет такой:

  • На главном меню приложения будет кнопка вызова окна лидерборда. Так как данные для заполнения лидерборда запрашиваются из сервера, в случае отсутствия сети кнопка будет не интерактивной… 

  • Модуль имеет свою музыку, звуки и виброотклик. Поэтому при переходе в окно лидерборда, запускается музыка которая относится только к лидерборду. Соответственно музыка самого приложения должна отключаться. 

  • Для работы модуля требуется только его интеграция. Поэтому модуль уже имеет все необходимые плагины для автономной работы. 

  • Подобные модули могут иметь немалый функционал, в связи с чем необходимо отправлять ивенты аналитики. Но отправлять под каким ключом? Ответ на этот вопрос будет позже.

Архитектурно модуль будет выглядеть следующим образом:

Пакет модуля состоит из сборки самого модуля, и плагинов для поддержания автономности. Если в проекте уже есть эти плагины, то плагины пакета не импортируются. Сборка модуля состоит из классов логики, конфигов, вьюшек и всего остального необходимого для работы модуля, а также одноименного фасадного класса LeaderBoard. Все элементы сборки находятся в пространстве имен модуля LeaderBoard, и являются закрытыми для других сборок. Единственный открытый элемент - это фасадный класс LeaderBoard. 

Так как модуль должен быть универсальным и простым в интеграции, наиболее очевидным решением будет сделать класс LeaderBoard синглтоном. LeaderBoard это класс фасад, поэтому он имеет единственную ответственность - связь модуля с проектом. Класс разделен на три части(partial):

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

  2. LeaderBoard_Advanced - эта часть содержит в себе редко используемые, специфические возможности для интеграции.

  3. Дополнительная часть LeaderBoard_Additional - эту часть можно считать не фасадной, в ней находятся вспомогательные закрытые поля и методы, которые необходимы для работы основной и продвинутой частей класса LeaderBoard. Эта часть позволяет содержать фасадную часть в чистоте от ненужных при интеграции полей и методов.  

Одна из преимуществ использования фасада - это семантически понятное и логичное наименование элементов класса, для того кто будет интегрировать модуль. Фасад позволяет абстрагироваться от внутренней логики модуля, и правил наименования  элементов в сборке модуля. И само наличие фасада дает понять, что все взаимодействие с модулем будет выполняться через него.

Теперь мы плавно переходим к интеграции модуля. Сначала необходимо обсудить некоторые нюансы. 

Забегая вперед скажу, что сразу сделать такой модуль абсолютно универсальным очень сложно. При разработке нашего модуля мы его хорошо протестировали, в том числе по интеграции на нескольких наших внутренних проектах. Но в одном из сторонних проектах использовался NGUI. У него свои интерфейсы отличные от UGUI. Пришлось добавлять пару методов для таких случаев.

Для мобильных устройств ориентация экрана, в котором будет работать приложение, выбирается на стадии написания ТЗ. Обычно ориентация фиксированная вертикальная(портретная) или горизонтальная(альбомная), полностью адаптивную верстку используют крайне редко. В нашем случае мы будем рассматривать две версии модуля вертикальная и горизонтальная, которые отличаются только версткой. 

Плагины(или же SDK), находящиеся в модуле, могут требовать привязку к ключам(или ID) конкретного приложения. В связи с этим такие плагины по умолчанию не активны. Их можно активировать при введении ключей во время интеграции. Или переложить ответственность на такой же плагин, который уже установлен в самом проекте. Например для отправки ивентов аналитики модуля, можно ввести ключ SDK аналитики в конфиге модуля. Или подписаться на отправку событий через фасадный класс. Модуль универсальный, поэтому в нем имеется один или несколько способов привязки. Ниже приведу пример:

Способ 1 - через делегат:

public Action<string, Dictionary<string, object>> OnLeaderBoardAnalyticEvent = (s,d) => { };

Способ 2 - через мессенджер:

OnLeaderBoardAnalyticEvent += ReBroadcastAnalyticEvent;
...
private void ReBroadcastAnalyticEvent(string eventName, Dictionary<string, object> parameters)
{
    Messenger.Broadcast<string, Dictionary<string,object>>
          (EventNames_LeaderBoard.ANALYTIC_EVENT, eventName, parameters);
}

Некоторые современные плагины могут требовать перейти в современную инпут систему. Поэтому модуль будет переводить настройки проекта в совмещенный тип ввода.

В финальном этапе разработки модуля, нам остается составить небольшой документ по интеграции модуля. Он будет выглядеть примерно так:

Интеграция модуля LeaderBoard  

Для интеграции пакета с лидербордом необходимо выполнить следующее:

0. Скачать ниже по ссылкам один из пакетов, в зависимости от фиксированной ориентации экрана горизонтальная/вертикальная. 

- для вертикального(портретного) режима экрана LeaderBoard 1.0.17_vertical_01.07.23 

- для горизонтального(альбомного) режима экрана LeaderBoard 1.0.17_horizontal_01.07.23 

1. Импортировать один из пакетов, в зависимости от фиксированной ориентации экрана горизонтальная/вертикальная. Перед началом импорта, сохраните все изменения вашего проекта. При импорте модуль потребует перезапустить Unity.

2. Перетянуть префаб LeaderBoard на сцену Menu. Или создать его через ваш EntryPoint. Префаб должен находиться только на одной из стартовых сцен, условно “Menu”. Префаб LeaderBoard является singleton DontDestoyOnLoad объектом.

3. В лидерборде есть канвас, в нем необходимо настроить слой рендера. По замыслу лидерборд должен отображаться поверх остальных UI за исключением экрана загрузки. В текущей версии лидерборда все визуальные объекты являются классическими Unity UI объектами. 

4. Настроить модуль через конфиг LeaderBoardConfigs.

5. В идеале все скриптовое взаимодействие с модулем должно выполняться через класс LeaderBoard (singleton). Если данный класс не имеет необходимого интерфейса взаимодействия, просьба написать в комментариях к этому доку, что еще требуется.

5.1 В модуле присутствуют музыка и звуки. При вкл/выкл, настройки громкости звука в настройках вашего приложения необходимо также вкл/выкл, настроить звук у модуля. Для этого выполняйте соответствующие вызовы методов:

LeaderBoard.Instance.EnableSound();
LeaderBoard.Instance.DisableSound();
LeaderBoard.Instance.SetSoundVolume();

5.2 [Android] В модуле присутствуют ивенты аналитики, и SDK для их отправки. Чтобы ивенты отправлялись, необходимо ввести ключи в конфиг LeaderBoardConfigs и поставить галочку - включить необходимый SDK. Или же если необходимого для вас SDK в модуле нет, то есть возможность привязать отправку ивентов к аналитике вашего проекта. Есть два способа привязки:

 Способ 1 - через делегат:

LeaderBoard.Instance.OnLeaderBoardAnalyticEvent += SendEvent;

Способ 2 - через мессенджер:

private void OnEnable()
{
    Messenger.AddListener<string, Dictionary<string,object>>
          (EventNames_LeaderBoard.ANALYTIC_EVENT, SendEvent);
}

private void OnDisable()
{
    Messenger.RemoveListener<string, Dictionary<string, object>>
          (EventNames_LeaderBoard.ANALYTIC_EVENT, SendEvent);
}

Ивенты также отправляются в logs (консоль). Чтобы отключить отправку в logs необходимо убрать галочку в конфиге LeaderBoardConfigs с поля EnabledAnalyticLogs.

6. При импорте модуля, автоматически устанавливается новая InputSystem. Если вы уже используете новую InputSystem, то не беспокойтесь, модуль не имеет своего InputAction.

При установке системы появится диалоговое окно с выбором активной системы ввода. Что бы вы не выбрали вы всегда можете поменять активную InputSystem в ProjectSettings/Player/OtherSettings/ActiveInputHandling

Возможные конфликты

1. Дубликат библиотеки NewtonSoft. В этом случае удалите эту библиотеку в модуле. Конфликт может возникнуть при использовании плагина Json.net.

Дополнительный возможности 

1. В некоторых случаях вам может понадобиться проверка “не открыто ли какое либо окно модуля, которое перекрывает/блокирует взаимодействие с вашей игрой”. Для проверки используйте:

LeaderBoard.Instance.CheckGameIsBlocked();

2. При вкл/выкл какого либо окна модуля, вызывается событие OnAnyWindowEnabled(bool). При необходимости подпишитесь на это событие.

3. Если вы хотите выполнить нажатие на кнопку вызова окна лидерборда через код, воспользуйтесь методом 

LeaderBoard.Instance.ClickOnButton();

Комментарии (0)