Особенности разработки мобильной MMO RTS. Часть 4



    Содержание:


    1. Оптимизация размера игры
    2. Бандлы и загружаемые ресурсы. Что требуется от системы?
    3. Дифы манифеста
    4. Экономия на кодогенерации

    Мы прошли экватор цикла о создании MMO RTS. Сегодняшняя статья посвящена оптимизации.

    Оптимизации размера игры


    Помните предупреждение от AppStore и GooglePlay о том, что вы пытаетесь загрузить приложение больше 100 Мб через мобильную сеть? Это сообщение очень сильно снижает показатели конверсии. Продвигать такие объемные игры очень дорого. Мы провели исследование и выяснили, что конверсия падает почти на 20 %. Для бесплатных игр этот показатель на грани выживания, для платных не так критичен.

    На iOS всё еще сложнее. Начиная с ARM64, в билд попадают 2 разных исполняемых файла, для 32-битной архитектуры и 64-битной. То есть вместо 70 Мб для вшитых ресурсов остается только 30.

    На каждом iOS-билде мы проводим пессимистичное вычисление его размера. Для этого xCode-архив делится на ресурсы и исполняемый файл. Ресурсы жмутся в .zip, и результат суммируется с размером исполняемого файла. Этого показателя достаточно, чтобы узнать, как изменяется размер проекта. Более подробное руководство и формулы есть на сайте Unity.

    Если вся графика правильно жмется, меши оптимизированы, а ненужные зависимости устранены, остается не так много решений – например, вынесение контента в бандлы и оптимизация кодогенерации.

    Бандлы и загружаемые ресурсы. Что требуется от системы?


    Вся базовая графика, необходимая для отображения UI пользователю после логина, остается в билде.



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

    Если вкратце, система работает так:

    1. В Unity-проекте есть набор папок, названия которых заканчиваются на .bundle. Содержимое этих бандлов – ресурсы, запрашиваемые клиентом в рантайме по имени файла этого ресурса.
    2. Через специальную утилиту разработчик билдит измененные бандлы и формирует манифест. Это текстовый файл с информацией, необходимой клиенту.
    3. Сформированные бандлы выливаются на контент-сервер, а манифест на сервер, который возвращает его клиентам во время логина. Бандлы могут обновиться или добавиться без обновления клиента.
    4. Клиент парсит манифест, загружает и кэширует бандлы, как только их запрашивает код.

    В итоге у нас сформировались требования к манифесту.



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

    Система поддерживает зависимости бандлов друг от друга. Часто разные 3D модели зависят от общего бандла с текстурами. Информация хранится в манифесте и используется в клиенте для приоритизации загрузки ресурсов.

    Мы добавили возможность локализовать бандлы. Это нужно для игровых баннеров с текстами на разных языках и озвучки визарда.

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



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

    Экономия на кодогенерации


    Что касается кодогенерации, тут нужно понимать, как работает платформа .NET/Mono и IL2CPP. Обращайте внимание на generic-типы. Для .NET/Mono каждая специализация generic является отдельным типом. Для reference-типов специализации ссылаются на одну – Object. В случае с value-типами компилятору нужно учитывать размер объекта этого типа. Потом он создает отдельные специализации.

    Основные проблемные места – классы с большой реализацией и generic-коллекции. Помимо типизированных массивов, неприятным моментом для нас оказалось то, что использование значений перечислений enum в качестве значения ключа в словаре приводит к генерации новой копии кода Dictionary.

    Для выявления таких реализаций мы использовали ReSharper и его опцию Find generic substitutions. После того, как мы их обнаружили, стараемся свести количество специализаций к минимуму.

    Другие статьи из серии:


    • +14
    • 8,2k
    • 2
    Plarium
    134,74
    Разработчик мобильных и браузерных игр
    Поделиться публикацией

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

      0
      Было бы замечательно, если бы вы добавили ссылки на все 4 части в конец каждой статьи.
        0
        Дельное замечание, спасибо, добавим.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое