This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English

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

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

Снижение времени выполнения скриптов

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

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

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

Сокращение сборки мусора

Если вы создаёте много короткоживущих объектов (например, таблиц 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

Во всех трёх случаях будет получена позиция игрового объекта с id 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. Ниже приведены несколько аспектов, которые следует учесть при попытке ускорить рендеринг:

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

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

Это необходимо, если профайлер показывает высокие значения в области GameObject, особенно в UpdateTransform. Рекомендации:

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

Отсечение по фрустуму (Frustum culling)

Сценарий рендеринга может автоматически игнорировать объекты вне фрустума. Подробнее — в руководстве по Render Pipeline.

Оптимизация под конкретные платформы

Android Device Performance Framework

Android Dynamic Performance Framework — это набор API, позволяющих играм взаимодействовать с системами питания и температуры устройств Android. Это помогает отслеживать поведение системы и настраивать производительность игры на устойчивом уровне без перегрева устройства. Используйте расширение ADPF, чтобы отслеживать и оптимизировать производительность на Android.