О чем этот пример
В классических веб-приложениях модальные окна — привычный элемент интерфейса. В играх они тоже нужны: для пауз, инвентаря или диалогов. Этот пример показывает, как в Phaser создать несколько независимых сцен, чтобы одна работала как фон, а другая — как модальное окно. Вы научитесь настраивать позиционирование, рендеринг и взаимодействие сцен, что особенно полезно для сложных интерфейсов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
const backgroundSceneConfig = {
key: 'background',
active: true,
create: createBackground,
render: renderBackground,
pack: {
files: [
{ type: 'image', key: 'face', url: 'assets/pics/bw-face.png' }
]
}
};
const modalSceneConfig = {
key: 'modal',
active: true,
renderToTexture: false,
x: 64,
y: 64,
width: 320,
height: 200,
create: createModal,
render: renderModal,
pack: {
files: [
{ type: 'image', key: 'logo', url: 'assets/pics/agent-t-buggin-acf-logo.png' }
]
}
};
const gameConfig = {
type: Phaser.CANVAS,
parent: 'phaser-example',
width: 800,
height: 600,
scene: [ backgroundSceneConfig, modalSceneConfig ]
};
const game = new Phaser.Game(gameConfig);
function createBackground ()
{
this.add.image(400, 300, 'face');
}
function createModal ()
{
this.cameras.main.setBackgroundColor('rgba(255,0,0,0.4)');
console.log(this.cameras.main.backgroundColor);
this.add.image(0, 0, 'logo').setOrigin(0);
}
const r = 0;
function renderBackground (ctx)
{
ctx.fillStyle = 'rgb(' + r + ', 0, 0)';
ctx.fillRect(0, 0, 32, 32);
r += 2;
if (r >= 256)
{
r = 0;
}
}
function renderModal (ctx)
{
ctx.fillStyle = 'rgb(0, ' + r + ', 0)';
ctx.fillRect(0, 0, 32, 32);
r += 2;
if (r >= 256)
{
r = 0;
}
}
Настройка сцен через конфигурационные объекты
Вместо передачи классов в массив scene можно использовать конфигурационные объекты. Это даёт больше контроля на этапе инициализации.
Каждая сцена — это объект с ключевыми свойствами. Например, key — уникальный идентификатор, active — запускать ли сцену сразу, create — функция для начальной настройки.
const backgroundSceneConfig = {
key: 'background',
active: true,
create: createBackground,
render: renderBackground
};
const modalSceneConfig = {
key: 'modal',
active: true,
renderToTexture: false,
x: 64,
y: 64,
width: 320,
height: 200,
create: createModal,
render: renderModal
};
Обратите внимание на renderToTexture: false. Это важно: если бы значение было true, сцена рендерилась бы в текстуру, а не прямо на холст. Для модального окна мы хотим прямое наложение.
Свойства `x,y,width,heightопределяют область отрисовки сценыmodal` на основном холсте. В данном случае окно смещено на 64 пикселя от краёв и имеет размер 320x200.
Загрузка ассетов и инициализация игры
Каждая сцена может иметь свой собственный блок предзагрузки pack. Это удобно для распределения ресурсов.
pack: {
files: [
{ type: 'image', key: 'face', url: 'assets/pics/bw-face.png' }
]
}
Затем конфиги обеих сцен передаются в настройки игры. Порядок в массиве имеет значение: сцены рендерятся последовательно. Сначала background, потом modal — так модальное окно окажется поверх фона.
const gameConfig = {
type: Phaser.CANVAS,
parent: 'phaser-example',
width: 800,
height: 600,
scene: [ backgroundSceneConfig, modalSceneConfig ]
};
const game = new Phaser.Game(gameConfig);
Создание графики в сценах
Функция create выполняется один раз при создании сцены. В ней размещаются основные объекты.
В фоновой сцене просто добавляется изображение по центру.
function createBackground ()
{
this.add.image(400, 300, 'face');
}
В модальной сцене сначала задаётся цвет фона камеры с прозрачностью. Это создаёт эффект затемнения. Затем добавляется логотип в левый верхний угол окна.
function createModal ()
{
this.cameras.main.setBackgroundColor('rgba(255,0,0,0.4)');
this.add.image(0, 0, 'logo').setOrigin(0);
}
Вызов setOrigin(0) привязывает изображение к точке (0,0) внутри области модальной сцены, то есть к её левому верхнему углу.
Кастомный рендеринг с помощью функции render
Функция render предоставляет прямой доступ к контексту рендеринга (ctx). Она вызывается каждый кадр после отрисовки всех объектов сцены. В примере она используется для анимации цветного квадрата.
Важный момент: переменная `rобъявлена глобально и используется в обеих функцияхrender`. Это не лучшая практика для реального проекта, но здесь демонстрирует общее состояние.
let r = 0;
function renderBackground (ctx)
{
ctx.fillStyle = 'rgb(' + r + ', 0, 0)';
ctx.fillRect(0, 0, 32, 32);
r += 2;
if (r >= 256) { r = 0; }
}
function renderModal (ctx)
{
ctx.fillStyle = 'rgb(0, ' + r + ', 0)';
ctx.fillRect(0, 0, 32, 32);
r += 2;
if (r >= 256) { r = 0; }
}
Квадрат в фоновой сцене меняет красную компоненту, а в модальной — зелёную. Поскольку они используют одну переменную `r`, их анимации синхронизированы. Квадраты рисуются в координатах (0,0) относительно своей сцены. На фоне он будет в самом верху слева, а в модальном окне — в его левом верхнем углу.
Что попробовать дальше
Использование конфигурационных объектов для сцен открывает гибкий путь к созданию сложных композиций, таких как модальные окна, HUD или раздельные игровые слои. Для экспериментов попробуйте: изменить renderToTexture на true и посмотреть на эффект, добавить интерактивность кнопкам внутри модальной сцены или организовать обмен данными между сценами через глобальные события (this.events).
