О чем этот пример
Переключение между игровыми сценами — это не всегда резкая смена экрана. Phaser предлагает мощный API для создания плавных и визуально привлекательных переходов, которые можно интегрировать даже в физический симулятор. Эта статья покажет, как использовать метод `scene.transition()` для анимированного перехода между двумя сценами, в каждой из которых активна физика Matter.js. Этот подход полезен для создания эффектных пауз, меню или смены игровых локаций без потери интерактивности текущей сцены.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class SceneA extends Phaser.Scene
{
constructor ()
{
super({ key: 'sceneA' });
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball1', 'assets/sprites/pangball.png');
}
create ()
{
this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);
for (let i = 0; i < 64; i++)
{
const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball1');
ball.setCircle();
ball.setFriction(0.005);
ball.setBounce(1);
}
this.input.once('pointerdown', function (event)
{
this.scene.transition({ target: 'sceneB', duration: 2000 });
}, this);
}
}
class SceneB extends Phaser.Scene
{
constructor ()
{
super({ key: 'sceneB' });
}
preload ()
{
// this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball2', 'assets/sprites/shinyball.png');
}
create ()
{
this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);
for (let i = 0; i < 64; i++)
{
const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball2');
ball.setCircle();
ball.setFriction(0.005);
ball.setBounce(1);
}
this.input.once('pointerdown', function (event)
{
this.scene.transition({ target: 'sceneA', duration: 2000 });
}, this);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: [ SceneA, SceneB ],
physics: {
default: 'matter'
}
};
const game = new Phaser.Game(config);
Настройка сцены и загрузка ассетов
Каждая сцена в примере является самостоятельным классом, расширяющим Phaser.Scene. В конструкторе задается уникальный ключ сцены, который используется для ссылок.
В методе preload() задается базовый URL для загрузки и загружается одно изображение для спрайтов. Обратите внимание, что SceneB закомментировала установку базового URL, так как он уже был установлен в SceneA и сохраняется между сценами.
class SceneA extends Phaser.Scene
{
constructor ()
{
super({ key: 'sceneA' });
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ball1', 'assets/sprites/pangball.png');
}
Создание физического мира и объектов
В методе create() происходит основная настройка. Сначала устанавливаются границы физического мира Matter.js с помощью this.matter.world.setBounds(). Последние аргументы true, true, false, true определяют, какие границы (верхняя, правая, нижняя, левая) будут иметь физические тела (стены).
Затем в цикле создаются 64 физических спрайта с помощью this.matter.add.image(). Каждому шару задается форма окружения (setCircle()), очень низкое трение (setFriction(0.005)) и упругий отскок (setBounce(1)). Шары появляются в случайных позициях по X и выше верхней границы экрана по Y, что создает эффект 'падения'.
create ()
{
this.matter.world.setBounds(0, 0, 800, 600, 32, true, true, false, true);
for (let i = 0; i < 64; i++)
{
const ball = this.matter.add.image(Phaser.Math.Between(100, 700), Phaser.Math.Between(-600, 0), 'ball1');
ball.setCircle();
ball.setFriction(0.005);
ball.setBounce(1);
}
Инициирование перехода между сценами
Ключевой момент — запуск перехода по событию пользователя. Используя this.input.once('pointerdown', ...), мы назначаем одноразовый обработчик клика или касания.
Внутри обработчика вызывается метод this.scene.transition(). Он принимает объект конфигурации, где target — это ключ целевой сцены (например, 'sceneB'), а duration — длительность перехода в миллисекундах (здесь 2000 мс или 2 секунды). Phaser сам управляет анимацией затемнения/появления.
this.input.once('pointerdown', function (event)
{
this.scene.transition({ target: 'sceneB', duration: 2000 });
}, this);
}
Конфигурация игры и физики
Общая конфигурация игры определяет рендерер, размеры, фон и, что важно, систему физики. Указание physics: { default: 'matter' } активирует для всех сцен в проекте движок Matter.js.
В свойстве scene массивом передаются классы сцен. Phaser создаст их экземпляры в порядке перечисления, но активной будет первая сцена (SceneA).
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: [ SceneA, SceneB ],
physics: {
default: 'matter'
}
};
const game = new Phaser.Game(config);
Что попробовать дальше
Метод scene.transition() предоставляет простой и эффективный способ создания плавных переходов между сценами, которые продолжают жить своей физической жизнью во время анимации. Это отлично подходит для игр, где важно сохранять визуальную непрерывность. Для экспериментов попробуйте: изменить длительность перехода; использовать другие события для запуска (например, таймер или столкновение); добавить пользовательскую функцию обратного вызова onUpdate для управления прозрачностью или масштабом сцен во время перехода; или комбинировать это с камерой для эффектов панорамирования.
