О чем этот пример

Когда нужно создать множество игровых объектов по сложному алгоритму, ручной перебор координат становится неудобным. В 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 в данной ячейке сетки.