О чем этот пример
При отрисовке большого количества одинаковых спрайтов производительность может значительно упасть из-за частых вызовов отрисовки. Phaser по умолчанию группирует графические объекты в батчи для эффективной отправки данных на GPU. В этой статье мы разберем, как вручную настроить размер такого батча, чтобы найти баланс между использованием памяти и скоростью рендеринга для вашей конкретной сцены. Это особенно полезно для проектов с тайловыми картами, частицами или большими массивами одинаковых объектов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('mushroom', 'assets/sprites/mushroom16x16.png');
}
create ()
{
// 64 x 32 = 2048
for (let y = 0; y < 32; y++)
{
for (let x = 0; x < 64; x++)
{
this.add.image(x * 16, y * 16, 'mushroom').setOrigin(0);
}
}
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1024,
height: 512,
render: {
// A custom batch size of 1024 quads
batchSize: 1024
},
scene: Example
};
const game = new Phaser.Game(config);
Проблема: множественные вызовы отрисовки
Каждый спрайт, добавленный на сцену, должен быть отрисован. Если спрайтов тысячи, а система рендеринга отправляет их на GPU по одному, это создает огромную нагрузку и приводит к просадкам FPS.
Phaser решает эту проблему, объединяя спрайты в группы — батчи. Вместо тысячи отдельных команд рендеринга отправляется одна команда для целой группы. Однако размер этой группы по умолчанию может быть неоптимальным для вашей игры.
// Без батчинга — 2048 отдельных вызовов отрисовки
for (let y = 0; y < 32; y++) {
for (let x = 0; x < 64; x++) {
this.add.image(x * 16, y * 16, 'mushroom').setOrigin(0);
}
}
Решение: настройка `batchSize` в конфиге
Ключ к управлению батчингом лежит в конфигурации рендерера. В объекте config вы можете задать свойство render, а внутри него — batchSize. Это число определяет, сколько квадов (условных графических единиц, зачастую спрайтов) может содержать один батч.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 1024,
height: 512,
render: {
// Устанавливаем кастомный размер батча в 1024 квада
batchSize: 1024
},
scene: Example
};
В данном примере мы устанавливаем размер батча равным 1024. Это означает, что наши 2048 спрайтов будут разбиты на 2 батча (2048 / 1024 = 2), что в два раза уменьшает количество вызовов к GPU по сравнению с отрисовкой каждого спрайта по отдельности.
Как выбрать оптимальный размер?
Идеального значения для всех проектов не существует. Выбор зависит от специфики вашей игры и целевой платформы.
* **Меньший размер (например, 256):** Требует меньше видеопамяти на один батч, но может увеличить количество вызовов рендеринга. Может быть полезно на слабых устройствах с ограниченной памятью. * **Больший размер (например, 4096):** Уменьшает количество вызовов рендеринга до минимума, но резервирует больше памяти. Идеально для статичных сцен с огромным количеством объектов на мощных ПК.
// Примеры различных конфигураций
// Для мобильной игры
render: { batchSize: 512 }
// Для десктопной игры с тяжелой сценой
render: { batchSize: 2048 }
Рекомендуется проводить тесты производительности (FPS, использование памяти) с разными значениями batchSize для ваших самых загруженных сцен.
Важные ограничения и детали
1. **Только для WebGL.** Данная настройка работает только с рендерером Phaser.WEBGL. В Phaser.CANVAS она не применяется.
2. **Влияние на память.** Батч резервирует область памяти (вершинный буфер) под максимальное количество объектов. Слишком большое значение batchSize может привести к неэффективному использованию памяти, особенно если в сцене редко используется полный батч.
3. **Смена текстуры.** Батч «рвется» при смене текстуры. Если вы отрисовываете спрайты с 'mushroom', а затем с 'star', Phaser завершит текущий батч и начнет новый. Поэтому для максимальной эффективности сортируйте объекты по используемым текстурам.
// Этот код вызовет два батча
this.add.image(100, 100, 'mushroom');
this.add.image(200, 200, 'star'); // Новый батч!
this.add.image(300, 300, 'mushroom'); // Снова батч для 'mushroom'
Что попробовать дальше
Ручная настройка batchSize — это мощный инструмент для тонкой оптимизации рендеринга в Phaser. Начните со значения по умолчанию и изменяйте его, только если профилирование показывает узкое место, связанное с вызовами отрисовки. Для экспериментов попробуйте создать сцену с 10 тысячами спрайтов и измерьте FPS при batchSize: 64, 512 и 4096. Также исследуйте, как на производительность влияет чередование спрайтов с разными текстурами, и попробуйте предварительно отсортировать их для минимизации разрывов батчей.
