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

Современные игры запускаются на устройствах с самыми разными разрешениями экрана. Один из ключевых вопросов для разработчика — как заставить игровое поле корректно отображаться на любом из них, не растягивая и не обрезая контент. Встроенный в Phaser менеджер масштабирования Scale Manager предлагает несколько стратегий. В этой статье мы разберем одну из самых полезных — режим `Phaser.Scale.FIT`, который автоматически подгоняет размер игрового канваса под родительский контейнер, сохраняя исходные пропорции игры.

Версия 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('pic', 'assets/pics/zero-two.png');
    }

    create ()
    {
        this.add.image(0, 0, 'pic').setOrigin(0);
    }
}

const config = {
    type: Phaser.AUTO,
    backgroundColor: '#2dab2d',
    scale: {
        mode: Phaser.Scale.FIT,
        parent: 'phaser-example',
        width: 800,
        height: 600
    },
    scene: Example
};

const game = new Phaser.Game(config);

Что делает режим FIT?

Когда вы задаете режим масштабирования Phaser.Scale.FIT в конфигурации игры, Phaser берет на себя всю работу по адаптации размера игрового холста (<canvas>). Алгоритм его работы прост и эффективен:

1. **Определяет размеры контейнера.** Phaser смотрит на размеры HTML-элемента, указанного в свойстве parent конфигурации scale. 2. **Вычисляет коэффициент масштабирования.** Система находит такой коэффициент, при котором ваша игра с исходным размером (width, height) полностью поместится внутрь контейнера. 3. **Применяет масштаб.** Канвас и вся игровая сцена масштабируются на этот коэффициент. По бокам или сверху и снизу могут появиться пустые области (поля), так как пропорции игры сохраняются.

Это идеальный режим для случаев, когда критически важно, чтобы весь игровой мир был виден целиком, без обрезки, даже если для этого игра будет отображаться чуть меньше возможного размера экрана.

scale: {
    mode: Phaser.Scale.FIT,
    parent: 'phaser-example',
    width: 800,
    height: 600
}

Разбор конфигурации

Давайте подробно рассмотрим объект конфигурации scale из примера. Каждое свойство здесь играет важную роль.

* **mode: Phaser.Scale.FIT** — это ключевая настройка, которая включает описанный выше алгоритм адаптивного масштабирования. * **parent: 'phaser-example'** — это id HTML-элемента (например, <div id="phaser-example">), внутри которого Phaser создаст и будет контролировать канвас. Если элемент не найден, игра будет использовать тело документа (document.body). * **width: 800 и height: 600** — это **базовое**, или внутреннее, разрешение вашей игры. Все координаты в игровом мире (например, this.add.image(0, 0, 'pic')) отсчитываются относительно этой виртуальной области 800x600 пикселей. Phaser будет стремиться вписать именно эту область в контейнер.

const config = {
    type: Phaser.AUTO,
    backgroundColor: '#2dab2d',
    scale: {
        mode: Phaser.Scale.FIT,
        parent: 'phaser-example',
        width: 800,
        height: 600
    },
    scene: Example
};

Сцена и позиционирование

Обратите внимание на код сцены в примере. Изображение загружается и добавляется в точку с координатами (0, 0) — верхний левый угол игрового мира.

create ()
{
    this.add.image(0, 0, 'pic').setOrigin(0);
}

Здесь есть важный нюанс: вызов .setOrigin(0).

* По умолчанию в Phaser точка позиционирования (origin) изображения находится в его центре. То есть, если указать координаты (0, 0), центр картинки окажется в точке (0, 0). * setOrigin(0) меняет точку origin на верхний левый угол самого изображения. Таким образом, левый верхний угол картинки совпадет с левым верхним углом игрового мира (0, 0).

Это стандартный прием, когда вы хотите использовать изображение как фон, который должен начинаться строго от края. Без setOrigin(0) по краям игрового поля остались бы пустые места, равные половине размера картинки.

При использовании FIT это внутреннее позиционирование не меняется. Независимо от того, как Phaser масштабирует канвас для вписывания в контейнер, изображение всегда будет начинаться от левого верхнего угла виртуального мира размером 800x600.

На практике: как это выглядит в браузере

Представьте, что у вас есть контейнер #phaser-example, который занимает 100% ширины окна браузера.

1. **Если окно браузера имеет пропорции ровно 4:3** (как 800:600), игра растянется на всю доступную площадь без полей. 2. **Если окно шире (например, 16:9)**, игра будет масштабирована так, чтобы ее высота (600 виртуальных пикселей) заняла всю высоту контейнера. По бокам появятся пустые поля цвета backgroundColor. 3. **Если окно уже**, игра впишется по ширине, а поля появятся сверху и снизу.

Система всегда выбирает масштаб так, чтобы **целиком** показать область 800x600, ни пикселя не теряя за краями. Это основное отличие FIT от, например, режима RESIZE, который может растягивать изображение с нарушением пропорций, или ENVELOP, который заполняет контейнер целиком, возможно обрезая часть игрового мира.

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

Режим Phaser.Scale.FIT — это надежный и простой способ сделать вашу игру адаптивной к разным размерам экрана, гарантируя, что весь игровой контент будет виден игроку. Он отлично подходит для большинства казуальных и пошаговых игр, где важна целостность картины. **Идеи для экспериментов:** 1. Поменяйте FIT на Phaser.Scale.RESIZE в конфиге и посмотрите, как изображение растягивается на весь контейнер, искажаясь. 2. Попробуйте режим Phaser.Scale.ENVELOP. Он, наоборот, масштабирует игру так, чтобы заполнить контейнер полностью, что может привести к обрезке краев изображения. 3. Добавьте в сцену интерактивный объект (например, спрайт по клику) и убедитесь, что его координаты также привязаны к базовому разрешению 800x600, а не к реальным пикселям экрана.