О чем этот пример
Создание и уничтожение игровых объектов в реальном времени может быть ресурсоемкой операцией, особенно при частых вызовах. Phaser предлагает элегантное решение — пулы объектов на основе групп (Group). Используя пулы, вы можете переиспользовать уже созданные, но временно неактивные объекты, что значительно снижает нагрузку на сборщик мусора и ускоряет работу игры. Эта статья покажет, как создать простой пул спрайтов с ограничением по размеру и управлять его состоянием.
Версия 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('cokecan', 'assets/sprites/cokecan.png');
}
create ()
{
const info = this.add.text(0, 0, 'Click to add objects', { fill: '#00ff00' });
// Our pool - essentially a Group that takes advantage of maxSize
// Setting the maxSize property limits the amount of objects allowed in this pool
const cans = this.add.group({
defaultKey: 'cokecan',
maxSize: 10
});
let x = 60;
this.input.on('pointerdown', () =>
{
// Pluck an entry from the pool. If it doesn't already exist, create it.
cans.get(x, 300);
x += 74;
info.setText([
`Used: ${cans.getTotalUsed()}`,
`Free: ${cans.getTotalFree()}`
]);
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что такое пул объектов?
Пул (англ. pool) — это шаблон проектирования, который предполагает заблаговременное создание набора (пула) переиспользуемых объектов. Вместо того чтобы постоянно создавать новые объекты (например, пули, врагов, эффекты) и удалять их, вы активируете объект из пула, когда он нужен, и деактивируете, возвращая в пул, когда его работа завершена.
В Phaser за это отвечает класс Group. Его свойство maxSize превращает обычную группу в пул с фиксированной вместимостью. Все объекты создаются заранее или по требованию, но их количество никогда не превысит установленный лимит.
Создание пула с помощью группы
В методе create сцены мы инициализируем пул. Ключевой параметр — maxSize. Также мы указываем defaultKey — текстуру, которая будет использоваться для автоматического создания объектов в пуле.
const cans = this.add.group({
defaultKey: 'cokecan',
maxSize: 10
});
Этот код создает группу-пул cans. Параметр defaultKey: 'cokecan' говорит Phaser, что новые объекты в этой группе должны быть спрайтами с текстурой 'cokecan'. Важнее всего maxSize: 10 — он ограничивает общее количество спрайтов в этой группе (как активных, так и неактивных) десятью. Phaser не сможет создать одиннадцатый объект.
Извлечение объекта из пула
Когда требуется новый объект (например, по клику мыши), мы не создаем его с нуля, а "достаем" из пула с помощью метода get().
cans.get(x, 300);
Метод group.get(x, y) — это сердце механизма пула. Phaser действует так:
1. Проверяет, есть ли в группе неактивный (выключенный и невидимый) объект.
2. Если есть — он активируется (включается, становится видимым) и помещается в указанные координаты (x, y).
3. Если неактивных объектов нет, но общее количество объектов в группе (total) меньше maxSize, Phaser создает новый объект с использованием defaultKey, активирует его и помещает в (x, y).
4. Если группа заполнена (все объекты активны), метод вернет undefined. В нашем примере этого не произойдет, так как мы просто увеличиваем координату `x` для следующего спрайта.
Мониторинг состояния пула
Для отладки и балансировки игры полезно знать, сколько объектов пула сейчас занято, а сколько свободно. Группа с maxSize предоставляет для этого два метода.
info.setText([
`Used: ${cans.getTotalUsed()}`,
`Free: ${cans.getTotalFree()}`
]);
* group.getTotalUsed(): Возвращает количество активных (используемых) объектов в группе.
* group.getTotalFree(): Возвращает количество неактивных (свободных) объектов, готовых к переиспользованию.
Сумма этих двух значений всегда будет равна текущему общему количеству объектов в группе (group.getLength()), которое не может превысить maxSize. В интерфейсе это отображается как динамически обновляемый текст.
Что попробовать дальше
Использование групп с ограничением maxSize — это простой и эффективный способ внедрить паттерн "Пул объектов" в вашу игру на Phaser. Он минимизирует затраты на создание и уничтожение объектов, что критически важно для производительности в сценах с большим количеством однотипных сущностей (стрельба, частицы, враги).
**Идеи для экспериментов:**
1. Реализуйте систему стрельбы: создайте пул для пуль с maxSize: 30. При выстреле "доставайте" пулю из пула, а при столкновении с целью или выходе за границы экрана — деактивируйте ее с помощью bullet.setActive(false).setVisible(false), возвращая в пул.
2. Сымитируйте нехватку ресурсов: установите очень маленький maxSize (например, 3) и обработайте ситуацию, когда group.get() возвращает undefined.
3. Используйте пул для анимаций частиц, создавая эффекты взрывов или подбора предметов без просадок FPS.
