О чем этот пример
Управление размером игрового поля во время выполнения — мощный инструмент для создания адаптивных интерфейсов, кат-сцен с разным соотношением сторон или эффектов "изменения перспективы". Часто разработчики настраивают масштаб один раз при запуске, но Phaser позволяет делать это динамически, реагируя на действия игрока. В этой статье разберем рабочий пример, который показывает, как менять размер игры по клику, переключая фоновые изображения и обновляя интерфейс. Вы научитесь использовать `ScaleManager` для живой адаптации вашего геймплея.
Версия 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('pic1', 'assets/pics/neuromancer.jpg');
this.load.image('pic2', 'assets/pics/monika-krawinkel-amberstar-title.png');
this.load.image('pic3', 'assets/pics/game14-angel-dawn.png');
this.load.image('pic4', 'assets/pics/ninja-masters2.png');
}
create ()
{
const pic1 = this.add.image(0, 0, 'pic1').setOrigin(0);
const pic2 = this.add.image(0, 0, 'pic2').setOrigin(0).setVisible(false);
const pic3 = this.add.image(0, 0, 'pic3').setOrigin(0).setVisible(false);
const pic4 = this.add.image(0, 0, 'pic4').setOrigin(0).setVisible(false);
const text = this.add.text(10, 10, 'Click to change game size', { font: '16px Courier', fill: '#00ff00' });
let state = 0;
this.input.on('pointerdown', function ()
{
if (state === 0)
{
// this.scale.setGameSize(320, 200);
this.scale.resize(320, 200);
text.setText('320 x 200');
pic1.setVisible(false);
pic2.setVisible(true);
state = 1;
}
else if (state === 1)
{
// this.scale.setGameSize(640, 400);
this.scale.resize(640, 400);
text.setText('640 x 400');
pic2.setVisible(false);
pic3.setVisible(true);
state = 2;
}
else if (state === 2)
{
// this.scale.setGameSize(1216, 896);
this.scale.resize(1216, 896);
text.setText('1216 x 896');
pic3.setVisible(false);
pic4.setVisible(true);
state = 3;
}
else if (state === 3)
{
// this.scale.setGameSize(800, 600);
this.scale.resize(800, 600);
text.setText('800 x 600');
pic4.setVisible(false);
pic1.setVisible(true);
state = 0;
}
}, this);
// this.scale.on('resize', resize, this);
}
resize (gameSize, baseSize, displaySize, resolution)
{
const width = gameSize.width;
const height = gameSize.height;
this.cameras.resize(width, height);
}
}
const config = {
type: Phaser.CANVAS,
backgroundColor: '#2dab2d',
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-example',
width: 800,
height: 600
},
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ресурсов
В методе preload() загружаются четыре фоновых изображения. Важно использовать this.load.setBaseURL() для указания базового пути, чтобы не прописывать полные URL для каждого ассета.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('pic1', 'assets/pics/neuromancer.jpg');
this.load.image('pic2', 'assets/pics/monika-krawinkel-amberstar-title.png');
this.load.image('pic3', 'assets/pics/game14-angel-dawn.png');
this.load.image('pic4', 'assets/pics/ninja-masters2.png');
В create() создаются все четыре изображения с координатами (0,0) и установленным setOrigin(0). Это выравнивает левый верхний угол картинки с левым верхним углом игрового мира. Изначально видимым оставляют только первое изображение (pic1), остальные скрывают с помощью setVisible(false). Также создается текстовый объект для отображения текущего разрешения.
const pic1 = this.add.image(0, 0, 'pic1').setOrigin(0);
const pic2 = this.add.image(0, 0, 'pic2').setOrigin(0).setVisible(false);
const pic3 = this.add.image(0, 0, 'pic3').setOrigin(0).setVisible(false);
const pic4 = this.add.image(0, 0, 'pic4').setOrigin(0).setVisible(false);
const text = this.add.text(10, 10, 'Click to change game size', { font: '16px Courier', fill: '#00ff00' });
Обработка клика и изменение размера
Логика строится вокруг переменной state, которая отслеживает текущий этап цикла (от 0 до 3). На событие pointerdown (this.input.on('pointerdown', ...)) вешается обработчик, который в зависимости от state выполняет три ключевых действия.
1. **Изменение размера игрового поля:** Вызывается метод this.scale.resize(width, height). Этот метод ScaleManager немедленно изменяет внутренний размер игры (game size).
2. **Обновление интерфейса:** Текстовому объекту задается новый текст с текущим разрешением.
3. **Смена фона:** Текущее видимое изображение скрывается, а следующее — показывается.
if (state === 0) {
this.scale.resize(320, 200);
text.setText('320 x 200');
pic1.setVisible(false);
pic2.setVisible(true);
state = 1;
}
Обратите внимание: в старых версиях Phaser использовался метод this.scale.setGameSize(), но в актуальных (3.60+) рекомендуется использовать this.scale.resize(). В примере показана обратная совместимость — старый метод закомментирован.
Конфигурация масштабирования игры
Корректная работа динамического ресайза невозможна без правильной начальной настройки. В объект config.scale передаются важные параметры.
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-example',
width: 800,
height: 600
}
- mode: Phaser.Scale.FIT — это самый важный параметр. Он гарантирует, что при любом изменении внутреннего размера игры (через resize), канвас будет пропорционально вписан в родительский элемент (parent), сохраняя соотношение сторон. Без этого режима изменение размера могло бы приводить к растяжению или обрезке изображения.
- width и height задают стартовое разрешение игры (800x600), которое будет изменяться по клику.
- parent указывает ID HTML-элемента, в который будет встроена игра.
Реакция на системное событие resize (дополнительно)
В коде примера закомментирован обработчик события resize объекта this.scale. Этот обработчик автоматически вызывается не только при ручном вызове this.scale.resize(), но и когда пользователь меняет размер окна браузера (если это разрешено настройками).
// this.scale.on('resize', resize, this);
Функция resize(gameSize, baseSize, displaySize, resolution) получает детальную информацию о новых размерах. Внутри нее можно, например, перенастроить камеры под новый размер игрового мира, чтобы видимая область соответствовала изменившимся границам.
resize (gameSize, baseSize, displaySize, resolution) {
const width = gameSize.width;
const height = gameSize.height;
this.cameras.resize(width, height);
}
В данном примере эта функциональность не активна, но ее включение — хорошая практика для создания полноценно адаптивных сцен, которые корректно реагируют на любой триггер изменения размера.
Что попробовать дальше
Метод this.scale.resize() — это прямой способ программно управлять размером игрового мира в Phaser 3. Комбинируя его с переключением видимости объектов и обработкой событий, вы можете создавать сложные адаптивные сцены и визуальные эффекты. Для экспериментов попробуйте: изменить режим масштабирования (Phaser.Scale.NONE или Phaser.Scale.ENVELOP) в конфиге и посмотреть на разное поведение; анимировать изменение размера, вызывая resize в цикле с промежуточными значениями; или привязать ресайз не к клику, а к определенным игровым событиям, например, переходу между уровнями с разной композицией.
