--- title: Оптимизация производительности во время выполнения в игре на Defold brief: Это руководство описывает, как оптимизировать игру на Defold для стабильной работы с высокой частотой кадров. --- # Оптимизация скорости выполнения Прежде чем приступать к оптимизации игры с целью достичь стабильной высокой частоты кадров, нужно понять, где находятся узкие места. Что именно занимает наибольшее время в кадре вашей игры? Рендеринг? Логика игры? Сценовый граф? Чтобы это выяснить, рекомендуется использовать встроенные инструменты профилирования. Используйте [экранный или веб-профайлер](/manuals/profiling/), чтобы проанализировать производительность игры и затем принять решение, что и стоит оптимизировать. После этого можно переходить к устранению проблем. ## Снижение времени выполнения скриптов Снижение времени выполнения скриптов требуется, если профайлер показывает высокие значения в области `Script`. В общем случае следует стараться выполнять как можно меньше кода в каждом кадре. Выполнение большого объёма кода в `update()` и `on_input()` в каждом кадре может сильно повлиять на производительность, особенно на слабых устройствах. Вот некоторые рекомендации: ### Используйте реактивные шаблоны Не опрашивайте состояние, если можно получить обратный вызов (callback). Не анимируйте вручную то, что можно поручить движку (например, используйте `go.animate()` вместо ручной анимации). ### Сокращение сборки мусора Если вы создаёте много короткоживущих объектов (например, таблиц 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 ``` В этом случае строка будет хешироваться каждый раз при получении сообщения. Лучше сделать так: ```lua 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. Пример: ```lua 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 и использовать его повторно: ```lua 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'ов — [об этом на форуме](https://forum.defold.com/t/draw-calls-and-defold/4674) * Снизьте избыточную отрисовку (overdraw) * Упростите шейдеры — изучите [оптимизации GLSL в статье Khronos](https://www.khronos.org/opengl/wiki/GLSL_Optimizations). Вы также можете изменить стандартные шейдеры, используемые в Defold (находятся в `builtins/materials`), и снизить точность с `highp` до, например, `mediump`, что в некоторых случаях может немного повысить производительность на слабых устройствах. ## Снижение сложности сценового графа Это необходимо, если профайлер показывает высокие значения в области `GameObject`, особенно в `UpdateTransform`. Рекомендации: * Culling — отключает игровые объекты (и их компоненты), если они в данный момент не видимы. Метод определения зависит от типа игры. В 2D-игре достаточно отключать объекты, находящиеся за пределами прямоугольной области. Это можно реализовать с помощью физического триггера или разбив объекты на группы. Когда известно, какие объекты нужно отключить или включить, отправьте соответствующее сообщение `disable` или `enable` каждому объекту. ## Отсечение по фрустуму (Frustum culling) Сценарий рендеринга может автоматически игнорировать объекты вне фрустума. Подробнее — в [руководстве по Render Pipeline](/manuals/render/#frustum-culling). # Оптимизация под конкретные платформы ## Android Device Performance Framework Android Dynamic Performance Framework — это набор API, позволяющих играм взаимодействовать с системами питания и температуры устройств Android. Это помогает отслеживать поведение системы и настраивать производительность игры на устойчивом уровне без перегрева устройства. Используйте [расширение ADPF](https://defold.com/extension-adpf/), чтобы отслеживать и оптимизировать производительность на Android.