Read this manual in English

Оптимизация игры на Defold

Важно понимать технические ограничения платформы (платформ), на которой должна запускаться ваша игра, и оптимизировать ее для данной платформы (платформ) при разработке. Следует учитывать несколько аспектов:

  • Размер приложения
  • Скорость
  • Использование памяти
  • Использование батареи

Оптимизация размера приложения

При сборке и бандлинге вашего приложения Defold создаст дерево зависимостей. Система сборки запустится из коллекции начальной загрузки (bootstrap collection), указанной в файле game.project, и проверит каждую коллекцию на которую ссылаются, игровой объект и компонент, чтобы выстроить список используемых ресурсов. Только эти ресурсы будут включены в окончательный бандл приложения. Все, на что нет прямых ссылок, будет исключено. Хотя полезно знать, что неиспользуемые ресурсы не будут включены, вам как разработчику все же необходимо учитывать, что входит в окончательное приложение, а также размер отдельных ассетов и общий размер бандла приложения. Некоторые целевые платформы и каналы распространения имеют ограничения на размер приложения:

  • Apple и Google определили ограничения на размер приложений при загрузке через мобильные сети (в отличие от загрузки через Wi-Fi).
    • Летом 2019 года эти ограничения составляли 100 МБ для Google Play и 150 МБ для Apple App Store.
  • Facebook имеет рекомендацию, что запуск Facebook Instant Game должен занимать менее 5 секунд, а желательно менее 3 секунд.
    • Что это означает для фактического размера приложения, четко не определено, но мы говорим о размере в диапазоне до 20 МБ.
  • Размер проигрываемой рекламы обычно ограничен от 2 до 5 МБ в зависимости от рекламной сети.

Согласно исследованию 2017 года, было показано, что «на каждые 6 МБ увеличения размера APK-файла наблюдается снижение коэффициента конверсии установок на 1%». (источник)

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

Уменьшение размера движка

Вы можете использовать файл манифеста приложения для удаления тех компонентов движка, которые вам не нужны. Вы можете, например, удалить подключаемые физические движки, если ваша игра не использует физику. Воспользуйтесь Manifestation online tool для создания манифеста приложения.

Оптимизация звуков

Defold поддерживает файлы .ogg и .wav, где .ogg обычно используется для музыки, а .wav - для звуковых эффектов. Звуки должны быть 16-битными с частотой дискретизации 44100, поэтому перед кодированием звуков необходимо выполнить все нужные оптимизации. Вы можете редактировать звуки во внешнем звуковом редакторе, чтобы снизить качество или преобразовать из .wav в .ogg.

Оптимизация графики

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

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

  • Максимальный размер текстуры в HTML5: https://webglstats.com/webgl/parameter/MAX_TEXTURE_SIZE
  • Максимальный размер текстуры в iOS:
    • iPad: 2048x2048
    • iPhone 4: 2048x2048
    • iPad 2, 3, Mini, Air, Pro: 4096x4096
    • iPhone 4s, 5, 6+, 6s: 4096x4096
  • Максимальный размер текстуры на Android сильно различается, но в целом все относительно новые устройства поддерживают 4096x4096.

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

Вы можете узнать больше о том, как оптимизировать текстуры и управлять ими в этом посте на форуме.

Исключение контента для загрузки по запросу

Другой способ уменьшить исходный размер приложения - исключить части игрового контента из бандла приложения и сделать их загружаемыми по мере необходимости. Исключенный контент может быть чем угодно, от целых уровней до разблокируемых персонажей, скинов, оружия или транспортных средств. Defold предоставляет систему под названием Live Update для исключения содержимого для загрузки по запросу. Подробнее читайте в Руководстве по Live Update.

Оптимизации размера специфичные для Android

Сборки под Android должны поддерживать как 32-разрядные, так и 64-разрядные архитектуры CPU. Когда вы готовите бандл под Android, вы можете указать, какие архитектуры CPU включать:

Подписывание Android бандла

Google Play поддерживает мульти-APK для каждой версии игры, что означает, что вы можете уменьшить размер приложения, создав два APK, по одному на архитектуру CPU и загрузить оба в Google Play.

Вы также можете использовать комбинацию файлов APK-расширения и Live Update контент) благодаря расширению APKX с портала экстеншенов.

Оптимизация скорости приложения

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

Уменьшение времени выполнения скрипта

Уменьшение времени выполнения скрипта необходимо, если профилировщик показывает высокие значения для категории Script. Как правило, вы, конечно, должны стараться запускать как можно меньше кода в каждом кадре. Запуск большого количества кода в update() и on_input() в каждом кадре может повлиять на производительность вашей игры, особенно на маломощных устройствах. Вот некоторые рекомендации:

Используйте шаблоны реактивного программирования

Не запрашивайте изменения, если вы можете получить функцию обратного вызова. Не анимируйте что-либо вручную и не выполняйте задачи, которые могут быть переданы движку (например, go.animate вместо анимации чего-либо вручную).

Сократите объем сборки мусора

Если вы создаете множество короткоживущих объектов, таких как таблицы Lua, в каждом кадре, это в конечном итоге вызовет сборщик мусора Lua. Когда это происходит, это может проявляться в виде небольших пауз/скачков во времени кадра. Повторно используйте таблицы там, где вы можете и действительно старайтесь избегать создания таблиц Lua внутри циклов и подобных конструкций, если это возможно.

Заранее пред-хешируйте идентификаторы сообщений и действий

Если вы обрабатываете много сообщений или имеете дело с большим количеством событий ввода, рекомендуется предварительно хешировать задействуемые строки. Рассмотрим этот фрагмент кода:

function on_message(self, message_id, message, sender)
    if message_id == hash("message1") then
        msg.post(sender, hash("message3"))
    elseif message_id == hash("message2") then
        msg.post(sender, hash("message4"))
    end
end

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

local MESSAGE1 = hash("message1")
local MESSAGE2 = hash("message2")
local MESSAGE3 = hash("message3")
local MESSAGE4 = hash("message4")

function on_message(self, message_id, message, sender)
    if message_id == MESSAGE1 then
        msg.post(sender, MESSAGE3)
    elseif message_id == MESSAGE2 then
        msg.post(sender, MESSAGE4)
    end
end

Предпочитайте URL-ы и кэшируйте их

Передача сообщений или другие способы адресации игрового объекта или компонента могут быть выполнены как путем предоставления идентификатора в виде строки или хэша, так и в виде URL-адреса. Если используется строка или хеш, они будут внутренне переведены в URL. Поэтому рекомендуется кэшировать часто используемые URL-адреса, чтобы получить максимальную производительность системы. Обратите внимание на следующий пример:

    local pos = go.get_position("enemy")
    local pos = go.get_position(hash("enemy"))
    local pos = go.get_position(msg.url("enemy"))
    -- do something with pos

Во всех трех случаях будет извлечена позиция игрового объекта с идентификатором enemy. В первом и втором случае идентификатор (строка или хэш) будет преобразован в URL-адрес перед использованием. Это говорит нам о том, что для максимальной производительности лучше кэшировать URL-адреса и использовать кешированную версию:

    function init(self)
        self.enemy_url = msg.url("enemy")
    end

    function update(self, dt)
        local pos = go.get_position(self.enemy_url)
        -- do something with pos
    end

Сократите время, необходимое для рендеринга кадра

Уменьшение времени, необходимого для рендеринга кадра, необходимо, если профилировщик показывает высокие значения в категориях Render и Render Script. При попытке сократить время, необходимое для рендеринга кадра, следует учитывать несколько моментов:

  • Уменьшение количества вызовов отрисовки - Подробнее о сокращении вызовов отрисовки читайте в этом посте на форуме
  • Уменьшение перерисовки
  • Снижение сложности шейдеров - читайте об оптимизации GLSL в этой статье от Kronos. Вы также можете изменить шейдеры, используемые Defold по умолчанию (находятся в builtins/materials), и уменьшить точность шейдеров, чтобы получить некоторую скорость на маломощных устройствах. Все шейдеры используют точность highp, и изменение, например, до mediump может в некоторых случаях немного улучшить производительность.

Снижение сложности графа сцены

Уменьшение сложности графа сцены необходимо, если профилировщик показывает высокие значения в категории GameObject и, более конкретно, для семплов ` UpdateTransform`. Некоторые действия, которые необходимо предпринять в этом случае:

  • Culling - Отключите игровые объекты (и их компоненты), если они в данный момент не видны. Как это определяется, во многом зависит от типа игры. Для 2D-игры это может быть просто и, выражается как правило, в отключении игровых объектов, находящихся за пределами прямоугольной области. Вы можете использовать физический триггер, чтобы обнаружить это, или сгруппировав ваши объекты по корзинам. Как только вы определили, какие объекты нужно отключить или включить, вы делаете это, отправляя сообщение disable или enable каждому игровому объекту.

Оптимизация использования памяти

Этот раздел еще не закончен. Темы, которые будут затронуты:

Оптимизация использования батареи

Этот раздел еще не закончен. Темы, которые будут затронуты:

  • Запуск кода каждый кадр
  • Акселерометр на мобильном устройстве
  • Профилирование