О чем этот пример
Когда нужно создать множество игровых объектов по сложному алгоритму, ручной перебор координат становится неудобным. В Phaser есть мощный метод `createFromCallback` для компонента Blitter, который позволяет генерировать и позиционировать объекты (bobs) с помощью функции обратного вызова. Это идеально подходит для создания узоров, сеток с отклонениями или любых процедурно генерируемых наборов спрайтов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
t = 16;
i = 0;
y = 0;
x = 0;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball', 'assets/demoscene/blue_ball.png');
}
create ()
{
const blitter = this.add.blitter(0, 0, 'ball');
blitter.createFromCallback(this.placeBob.bind(this), this.t * 7);
}
placeBob (bob)
{
if (this.i % 16 === 0)
{
this.x += 96;
this.y = 0;
}
this.y += 32;
bob.x = this.x + (Math.sin(this.y) * 16);
bob.y = this.y;
this.i++;
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что такое Blitter и Bob?
Blitter — это особый тип игрового объекта в Phaser, оптимизированный для быстрого отображения множества однотипных спрайтов (например, частиц или тайлов). Он работает с текстурой-источником (в нашем случае это изображение 'ball').
Каждый отдельный спрайт, управляемый Blitter, называется Bob. Bob — это легковесный объект, содержащий свои координаты (`x,y`) и ссылку на область текстуры.
Создав один Blitter, вы можете производить множество Bob, экономя ресурсы.
const blitter = this.add.blitter(0, 0, 'ball');
Метод createFromCallback
Вместо того чтобы вручную вызывать blitter.create(x, y) для каждого объекта, метод createFromCallback автоматизирует этот процесс.
Он принимает два аргумента:
1. Функцию обратного вызова, которая будет выполнена для каждого создаваемого Bob.
2. Количество Bob, которое нужно создать.
Phaser создает пустой Bob, передает его в вашу функцию, а вы внутри этой функции задаете ему координаты и любые другие свойства.
blitter.createFromCallback(this.placeBob.bind(this), this.t * 7);
// this.t * 7 = 16 * 7 = 112 объектов будет создано
Логика размещения в функции обратного вызова
Функция placeBob — это сердце примера. Она определяет, где будет расположен каждый новый Bob. Phaser вызывает ее 112 раз, каждый раз передавая новый, только что созданный объект Bob в параметр bob.
Код использует приватные переменные класса (this.i, this.x, this.y) для отслеживания состояния и расчета позиции.
1. Каждые 16 объектов (this.i % 16 === 0) происходит переход на новую колонку (this.x += 96) и сброс вертикальной позиции (this.y = 0).
2. Для каждого объекта вертикальная позиция увеличивается на 32 пикселя.
3. Финальные координаты Bob вычисляются с небольшим синусоидальным смещением по оси X, чтобы создать волнообразный эффект.
placeBob (bob)
{
if (this.i % 16 === 0)
{
this.x += 96;
this.y = 0;
}
this.y += 32;
bob.x = this.x + (Math.sin(this.y) * 16);
bob.y = this.y;
this.i++;
}
В результате получается 7 колонок по 16 объектов в каждой, где каждый ряд изгибается по синусоиде.
Где это пригодится на практике?
Такой подход не ограничивается созданием статических узоров. Его можно адаптировать для различных задач:
* **Генерация ландшафта:** Функция обратного вызова может читать данные карты высот (например, из шума Перлина) и расставлять тайлы земли или травы. * **Расстановка врагов или предметов:** Создать паттерн появления врагов в уровне, где позиция каждого следующего врага зависит от сложности или типа предыдущего. * **Создание сложных частичных эффектов:** Инициализация частиц дыма, огня или магической ауры с уникальными стартовыми параметрами для каждой.
Главное преимущество — инкапсуляция логики создания в одну функцию, что делает код чище и управляемее, чем цикл с условиями.
Что попробовать дальше
Метод createFromCallback в Blitter — это элегантный и производительный способ процедурного размещения множества объектов. Он отделяет логику создания от кода инициализации, предоставляя чистый интерфейс для генерации.
**Идеи для экспериментов:**
1. Замените Math.sin(this.y) на Math.cos(this.x) или комбинацию функций для создания более сложных сеток (например, "рябь").
2. Внутри placeBob меняйте не только координаты, но и другие свойства Bob, например, bob.frame для анимации или bob.alpha для градиента прозрачности.
3. Попробуйте сделать логику размещения зависимой от внешних данных — например, от массива 0 и 1, который определяет, создавать ли Bob в данной ячейке сетки.
