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

Визуальные эффекты могут превратить простую графику в захватывающий элемент геймплея. В этой статье мы разберем, как создать сложный визуальный эффект, объединяющий Bitmap Mask с инверсией альфа-канала и размытием через PostFX. Это полезно для выделения областей интереса, создания порталов, нестандартных затемнений или динамических интерфейсов, где часть экрана должна быть "активной" на фоне общего блюра. Мы подробно разберем пример кода, который создает белую фигуру, выступающую в роли "окна" в черном затемняющем слое, при этом сама фигура имеет эффект размытия.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class GameScene extends Phaser.Scene {

	preload() {
  }
  
  create() {
 		const poly = new Phaser.Geom.Polygon();
    poly.setTo([ new Phaser.Math.Vector2(200, 100), new Phaser.Math.Vector2(350, 100), new Phaser.Math.Vector2(375, 200), new Phaser.Math.Vector2(150, 200) ]);
    const graphics = this.add.graphics();
    graphics.postFX.addBlur();
		const blackOverlay = this.add.graphics();
    blackOverlay.fillStyle(0x000000, 1);
    blackOverlay.fillRect(0,0, 1000,1000);
      

    graphics.lineStyle(5, 0xFFFFFF);
    graphics.fillStyle(0xFFFFFF);
    graphics.fillPoints(poly.points, true);
       
    let mask = new Phaser.Display.Masks.BitmapMask(this, graphics);
    mask.invertAlpha = true;
    blackOverlay.setMask(mask);
  }
}

new Phaser.Game({
  type: Phaser.WEBGL,
  width: 800,
  height: 600,
  scene: [GameScene],
  parent: 'phaser-example',
  scale: {
    mode: Phaser.Scale.RESIZE,
  },
});

Подготовка сцены и настройка масштабирования

Код начинается с создания основной игровой сцены GameScene. Ключевой момент здесь — конфигурация объекта Phaser.Game, в частности, настройка масштабирования.

scale: {
  mode: Phaser.Scale.RESIZE,
}

Использование Phaser.Scale.RESIZE заставляет игру динамически подстраивать свой размер под размеры родительского контейнера (в данном случае, элемента с id='phaser-example'). Это особенно важно для адаптивного дизайна, когда игра должна корректно отображаться на экранах с разным разрешением. Все последующие координаты и размеры рассчитываются относительно этого динамического канваса.

Создание геометрии и графики с эффектом размытия

В методе create() мы создаем визуальные элементы. Первым делом определяется многоугольник (Polygon), который задает форму нашего будущего "окна".

const poly = new Phaser.Geom.Polygon();
poly.setTo([ new Phaser.Math.Vector2(200, 100), new Phaser.Math.Vector2(350, 100), new Phaser.Math.Vector2(375, 200), new Phaser.Math.Vector2(150, 200) ]);

Затем создается объект graphics — холст для рисования. К нему сразу применяется PostFX эффект размытия.

const graphics = this.add.graphics();
graphics.postFX.addBlur();

Эффект addBlur() применяется ко всему, что будет нарисовано на этом объекте graphics. После этого на нем рисуется залитый белый цветом многоугольник по заданным точкам.

graphics.lineStyle(5, 0xFFFFFF);
graphics.fillStyle(0xFFFFFF);
graphics.fillPoints(poly.points, true);

Таким образом, у нас есть размытая белая фигура на прозрачном фоне.

Создание слоя затемнения и Bitmap Mask

Теперь создается второй объект graphicsblackOverlay. Он представляет собой черный прямоугольник, который будет закрывать весь экран, создавая эффект затемнения.

const blackOverlay = this.add.graphics();
blackOverlay.fillStyle(0x000000, 1);
blackOverlay.fillRect(0,0, 1000,1000);

Самый важный этап — создание Bitmap Mask и её применение. Маска создается на основе нашего первого объекта graphics (с размытой фигурой).

let mask = new Phaser.Display.Masks.BitmapMask(this, graphics);
mask.invertAlpha = true;
blackOverlay.setMask(mask);

Объект graphics (маска) имеет размытую белую фигуру на прозрачном фоне. Обычно маска использует альфа-канал: непрозрачные области маски показывают содержимое замаскированного объекта (blackOverlay), а прозрачные — скрывают. Однако флаг invertAlpha = true инвертирует это поведение. Теперь прозрачные области маски (фон вокруг белой фигуры) ПРОПУСКАЮТ черный цвет, а непрозрачные (сама белая фигура) — СКРЫВАЮТ его. В итоге черный слой виден везде, кроме области, совпадающей с белой фигурой, образуя "окно".

Итоговый визуальный эффект

В результате получается трехслойная композиция: 1. **Фон сцены:** По умолчанию прозрачный (черный в браузере). 2. **Черный слой (blackOverlay):** Закрывает весь экран, но на него наложена инвертированная маска. 3. **Маска (graphics):** Размытая белая фигура.

Эффект для пользователя: весь экран затемнен черным полупрозрачным (в данном случае — полностью непрозрачным) цветом, но в области заданного многоугольника это затемнение отсутствует, "вырезая" окно. При этом края этого окна имеют приятное размытие благодаря PostFX, что создает плавный переход между затемненной и активной зоной.

// Итоговая картинка: черный экран с размытым белым "окном" в центре.

Из-за инверсии маски сама белая фигура не видна как объект, она выполняет лишь роль "трафарета".

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

Этот пример демонстрирует мощь комбинации Bitmap Mask с инверсией и PostFX эффектами в Phaser 3. Вы научились создавать нестандартные области видимости с плавными границами. Для экспериментов попробуйте: 1. Анимировать позиции точек многоугольника, чтобы "окно" двигалось. 2. Заменить blackOverlay на текстуру или картинку, чтобы создать эффект "волшебного шара". 3. Изменить PostFX эффект у graphics на addGlow или addBloom для создания сияющего портала. 4. Использовать эту технику для создания динамического фокуса камеры в стратегической игре.