Culling: автоматическое и ручное

Culling в контексте игровых движков означает процесс определения и исключения объектов, которые не видимы на экране, чтобы оптимизировать производительность. В Phaser culling используется для экономии ресурсов при рендеринге сцены с большим количеством спрайтов или тайлсетов.

Phaser предоставляет два основных подхода к culling: автоматический и ручной. Каждый из них имеет свои особенности и области применения.


Автоматическое Culling

Phaser использует систему камер для определения, какие объекты находятся в видимой области. Спрайты, текстуры и тайлы проверяются на пересечение с областью камеры, и рендерятся только те, что видны.

Ключевые моменты:

  • Автоматическое culling активируется по умолчанию для TilemapLayer и Group.
  • Для спрайтов внутри Group используется проверка метода Camera.worldView, который возвращает область видимости камеры.
  • Автоматическое исключение невидимых объектов снижает нагрузку на GPU и повышает FPS.

Пример автоматического culling для TilemapLayer:

const map = this.make.tilemap({ key: 'level1' });
const tileset = map.addTilesetImage('tiles', 'tilesImage');
const layer = map.createLayer('Ground', tileset, 0, 0);

// Включение автоматического culling
layer.setCullPadding(32); // добавляет запас пикселей, чтобы тайлы появлялись заранее

Особенности:

  • setCullPadding(pixels) позволяет заранее рендерить тайлы за пределами экрана, чтобы избежать внезапного появления объектов.
  • Автоматический culling оптимален для динамических сцен, где объекты перемещаются с постоянной скоростью.

Ручное Culling

Ручное culling требуется, когда нужно больше контроля над процессом рендеринга объектов. Например, когда объекты частично видны, а их рендеринг должен зависеть от сложной логики.

Подходы к ручному culling:

  1. Проверка позиции объекта относительно камеры
function isVisible(sprite, camera) {
    const bounds = sprite.getBounds();
    return Phaser.Geom.Intersects.RectangleToRectangle(bounds, camera.worldView);
}

sprites.forEach(sprite => {
    sprite.visible = isVisible(sprite, this.cameras.main);
});
  1. Использование слоёв и групп для фильтрации видимых объектов
  • Создание Group с объектами, которые подлежат culling.
  • Применение функции фильтрации в update цикле.
  • Управление видимостью через sprite.setVisible(true|false) вместо удаления объекта.

Преимущества ручного подхода:

  • Возможность применять сложные условия, например, видимость зависит не только от положения, но и от состояния объекта.
  • Можно оптимизировать рендеринг для огромного числа объектов, когда автоматическое culling неэффективно.

Настройка Culling для производительности

Оптимизация тайлсетов:

  • Минимизировать количество тайлов в TilemapLayer.
  • Использовать setCullPadding, чтобы тайлы подгружались заранее.
  • Разделять карту на слои с разной частотой обновления.

Оптимизация спрайтов и групп:

  • Использовать ручное culling для объектов с нестандартной геометрией.
  • Применять методы setActive и setVisible вместо удаления из сцены.
  • Группировать объекты по близости к камере и проверять видимость только для нужных групп.

Пример комбинированного подхода:

const enemies = this.add.group();
enemies.getChildren().forEach(enemy => {
    enemy.setActive(false);
    enemy.setVisible(false);
});

function update() {
    enemies.getChildren().forEach(enemy => {
        const visible = Phaser.Geom.Intersects.RectangleToRectangle(
            enemy.getBounds(), this.cameras.main.worldView
        );
        enemy.setActive(visible);
        enemy.setVisible(visible);
    });
}

Такой подход сочетает автоматическое определение области камеры и ручное управление активностью объектов, что позволяет добиться максимальной производительности на больших уровнях.


Взаимодействие с другими системами Phaser

  • Physics: объекты, которые не видимы, часто не нужно проверять на коллизии. Ручной culling позволяет отключать физику через body.enable = false.
  • Анимации: скрытые спрайты можно приостанавливать (sprite.anims.pause()), чтобы не тратить ресурсы на проигрывание анимаций вне экрана.
  • События: объекты вне камеры могут не принимать события, что уменьшает нагрузку на обработчики ввода.

Резюме по стратегиям Culling

  • Автоматическое culling: подходит для стандартных тайлсетов и групп, минимальная настройка, интеграция с камерой.
  • Ручное culling: требуется для сложных сцен, больших массивов объектов и специфической логики видимости.
  • Комбинированный подход: оптимальный вариант для крупных игр, сочетает преимущества обоих методов.

Эффективное использование culling в Phaser позволяет уменьшить количество рендеримых объектов, снизить нагрузку на GPU и CPU, повысить FPS и обеспечить плавное воспроизведение сцены даже на слабых устройствах.