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

Создание интерактивных визуальных эффектов, реагирующих на цвет игрового мира, — мощный инструмент для разработчика. Пример `snapshotPixel` демонстрирует, как в Phaser 3 можно получить цвет конкретного пикселя на экране в момент клика. Эта техника открывает двери для механик, где игровое окружение напрямую влияет на геймплей: от заклинаний, которые анализируют поверхность, до динамических систем освещения, подстраивающихся под фон. В этой статье мы разберем, как работает этот метод и как его можно применить в ваших проектах.

Версия 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('pym', 'assets/pics/cougar-face-of-nature.png');
        this.load.image('logo', 'assets/sprites/phaser3-logo.png');
        this.load.image('red', 'assets/particles/red.png');
    }

    create ()
    {
        const g = this.add.graphics().setDepth(1);

        this.input.on('pointerdown', function (pointer)
        {

            this.game.renderer.snapshotPixel(pointer.x, pointer.y, pixel =>
            {
                g.clear();
                g.fillStyle(pixel.color);
                g.fillRect(0, 0, 128, 128);

            });

        }, this);

        //  Everything from here down is just stuff to display, so you can grab from it

        const bg = this.add.image(400, 300, 'pym').setScale(3);
        bg.texture.setFilter(1);

        const particles = this.add.particles(0, 0, 'red', {
            speed: 100,
            scale: { start: 1, end: 0 },
            blendMode: 'ADD'
        });

        const logo = this.physics.add.image(400, 100, 'logo');

        logo.setVelocity(100, 200);
        logo.setBounce(1, 1);
        logo.setCollideWorldBounds(true);

        particles.startFollow(logo);
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 200 }
        }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Принцип работы snapshotPixel

Метод snapshotPixel принадлежит рендереру игры (this.game.renderer) и позволяет мгновенно получить данные о цвете пикселя по заданным координатам на канвасе. В отличие от создания полного скриншота (snapshot), этот метод легковесен и выполняется синхронно, что делает его идеальным для мгновенной реакции на действия игрока, например, на клик.

Ключевой особенностью является его колбэк-функция, которая получает объект с данными пикселя. В нашем примере этот объект содержит свойство color.

this.game.renderer.snapshotPixel(pointer.x, pointer.y, pixel => {
    // pixel.color содержит цвет в формате '#rrggbbaa'
});

Обработка клика и визуализация результата

В примере вызов snapshotPixel привязан к событию указателя 'pointerdown'. При каждом клике мыши передаются координаты клика (pointer.x, pointer.y).

Полученный цвет сразу же используется для отрисовки графики. Созданный заранее объект Graphics (`g`) очищается, ему задается новый стиль заливки, равный считанному цвету, и рисуется квадрат.

const g = this.add.graphics().setDepth(1);

this.input.on('pointerdown', function (pointer) {
    this.game.renderer.snapshotPixel(pointer.x, pointer.y, pixel => {
        g.clear();
        g.fillStyle(pixel.color); // Устанавливаем цвет из пикселя
        g.fillRect(0, 0, 128, 128); // Рисуем квадрат этим цветом
    });
}, this);

Обратите внимание на контекст this, переданный в метод on. Это необходимо, чтобы внутри колбэка обработчика события оставалась ссылка на экземпляр сцены.

Подготовка сцены: фон, физика и частицы

Вся остальная часть кода в create служит лишь для создания динамичной и красочной сцены, с которой можно взаимодействовать. Это демонстрационный "стенд".

1. **Фон:** Изображение масштабируется и для него отключается сглаживание (setFilter(1)), чтобы цвета были четче. 2. **Система частиц (ParticleEmitter):** Создается эмиттер, испускающий красные частицы, которые следуют за логотипом. 3. **Физический спрайт:** Логотип Phaser добавляется в мир физики Arcade. Ему задается скорость, упругость (setBounce) и включается столкновение с границами мира (setCollideWorldBounds). Именно за этим логотипом и летят частицы.

const bg = this.add.image(400, 300, 'pym').setScale(3);
bg.texture.setFilter(1);

const particles = this.add.particles(0, 0, 'red', {
    speed: 100,
    scale: { start: 1, end: 0 },
    blendMode: 'ADD'
});

const logo = this.physics.add.image(400, 100, 'logo');
logo.setVelocity(100, 200);
logo.setBounce(1, 1);
logo.setCollideWorldBounds(true);

particles.startFollow(logo);

Практическое применение и ограничения

Хотя пример прост, он иллюстрирует основу для более сложных механик: * **Цветовые головоломки:** Игрок должен кликать на объекты определенного цвета. * **Динамические эффекты:** Цвет фона в точке клика может влиять на силу или тип заклинания. * **Инструменты для разработки:** Создание пипетки для выбора цвета прямо из игровой сцены.

Важное ограничение: метод snapshotPixel считывает пиксель с итогового изображения на канвасе, уже после применения всех отрисовок, смешиваний (blendMode) и фильтров. Координаты (pointer.x, pointer.y) — это координаты относительно самого канваса, а не игрового мира. Для преобразования координат мира в координаты камеры (вида) можно использовать this.cameras.main.getWorldPoint().

Что попробовать дальше

Метод snapshotPixel — это ваш прямой доступ к визуальному состоянию игры в реальном времени. Он позволяет создавать глубокую связь между визуальным представлением и игровой логикой. Для экспериментов попробуйте

  1. Изменить размер и форму отрисовываемого Graphics объекта на основе, например, альфа-канала считанного пикселя
  2. Накопить несколько последних считанных цветов для создания палитры
  3. Использовать цвет для мгновенного изменения свойств физического тела, в которое попал клик (например, сделать его скорость зависимой от яркости цвета фона)