О чем этот пример
При создании ретро-игр или проектов с фиксированным разрешением часто возникает необходимость полного контроля над процессом масштабирования. Phaser предоставляет для этого режим `NONE`, который отключает автоматические реакции на изменение размера окна. Это полезно, когда вы хотите вручную задавать уровень зума, например, для пиксель-арт игр, чтобы сохранить чёткость графики и избежать размытия. В этой статье мы разберём пример, где масштабирование инициируется только при явном событии ресайза окна.
Версия 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('bg', 'assets/tests/zoom/background.png');
this.load.image('ship', 'assets/tests/zoom/viper.png');
this.load.image('bullet', 'assets/tests/zoom/bullet.png');
}
create ()
{
this.add.image(0, 0, 'bg').setOrigin(0);
const bullet = this.add.image(-10, -10, 'bullet');
const ship = this.add.image(40, 40, 'ship').setInteractive();
let tween;
ship.on('pointerdown', function ()
{
if (tween)
{
tween.stop();
}
bullet.setPosition(40, 40);
tween = this.tweens.add({
targets: bullet,
x: 200
});
}, this);
}
}
const config = {
type: Phaser.AUTO,
backgroundColor: '#000000',
scale: {
mode: Phaser.Scale.NONE,
autoCenter: Phaser.Scale.CENTER_BOTH,
parent: 'phaser-example',
width: 160,
height: 144,
zoom: Phaser.Scale.MAX_ZOOM
},
scene: Example
};
const game = new Phaser.Game(config);
// In scaleMode NONE the Scale Manager is effectively disabled, so you need to
// tell it when a resize happens yourself:
window.addEventListener('resize', event =>
{
game.scale.setMaxZoom();
}, false);
document.body.style.backgroundColor = '#000000';
Настройка конфигурации: режим NONE и фиксированный зум
Ключевая настройка происходит в объекте config.scale. Здесь мы явно указываем движку не использовать автоматическое масштабирование под размер окна.
scale: {
mode: Phaser.Scale.NONE,
autoCenter: Phaser.Scale.CENTER_BOTH,
parent: 'phaser-example',
width: 160,
height: 144,
zoom: Phaser.Scale.MAX_ZOOM
}
- mode: Phaser.Scale.NONE — это главный параметр. Он отключает встроенный менеджер масштабирования Phaser. Игра больше не будет реагировать на изменение размеров окна браузера автоматически.
- width и height задают внутреннее, игровое разрешение. В нашем случае это 160x144, типичное для ретро-консолей.
- zoom: Phaser.Scale.MAX_ZOOM — это начальный уровень масштабирования. Phaser рассчитает максимальный целочисленный зум, при котором игра поместится в родительский контейнер (parent) без выхода за его границы. Это гарантирует чёткое отображение пикселей.
- autoCenter: Phaser.Scale.CENTER_BOTH отвечает за выравнивание игровой области по центру контейнера после применения зума.
Сцена: загрузка ресурсов и создание объектов
В сцене мы загружаем фоновое изображение, спрайт корабля и пули. Важно отметить, что позиционирование объектов (this.add.image(x, y, 'key')) происходит относительно внутренней системы координат игры (160x144), а не окна браузера.
create ()
{
this.add.image(0, 0, 'bg').setOrigin(0);
const bullet = this.add.image(-10, -10, 'bullet');
const ship = this.add.image(40, 40, 'ship').setInteractive();
}
- setOrigin(0) для фона устанавливает точку привязки в левый верхний угол (0,0), что удобно для его выравнивания.
- Корабль (ship) делается интерактивным с помощью setInteractive(), чтобы на него можно было кликнуть.
- Пуля (bullet) изначально помещается за пределы видимой области (-10, -10).
Интерактивность: ручное управление анимацией
По клику на корабль мы запускаем анимацию движения пули. Это демонстрирует, что вся игровая логика (взаимодействие, твины) работает независимо от настроек масштабирования.
let tween;
ship.on('pointerdown', function ()
{
if (tween)
{
tween.stop();
}
bullet.setPosition(40, 40);
tween = this.tweens.add({
targets: bullet,
x: 200
});
}, this);
- При каждом клике существующий твин останавливается (tween.stop()), пуля возвращается в начальную позицию рядом с кораблём, и запускается новый твин для её движения до координаты x=200.
- Обратите внимание на передачу контекста this в колбэк события, чтобы внутри функции можно было обратиться к this.tweens.
Ручная обработка ресайза окна
Поскольку мы отключили Scale Manager (Phaser.Scale.NONE), игра больше не слушает события изменения размера окна. Ответственность за это перекладывается на разработчика. В примере мы вручную добавляем слушатель на глобальный объект window.
window.addEventListener('resize', event =>
{
game.scale.setMaxZoom();
}, false);
- При любом изменении размера окна браузера вызывается game.scale.setMaxZoom(). Этот метод пересчитывает и применяет максимально возможный целочисленный зум для текущих размеров контейнера, сохраняя чёткость пикселей и центрируя игровую область.
- Без этого слушателя игра оставалась бы одного размера при ресайзе окна, что могло бы привести к появлению пустых областей или обрезанию контента.
Что попробовать дальше
Режим Phaser.Scale.NONE — мощный инструмент для проектов, требующих полного контроля над отображением. Он идеально подходит для пиксель-арт игр, ретро-проектов или любых случаев, где критически важна чёткость и детализация. Для экспериментов попробуйте изменить начальное значение zoom в конфиге на произвольное число, реализовать плавное изменение зума с помощью tweens вместо setMaxZoom() или привязать обработчик ресайза к кнопкам на игровом интерфейсе для ручного управления масштабом.
