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

Разработка игр для мобильных устройств и современных мониторов часто требует поддержки высокого разрешения (Retina, 4K). Простое увеличение размеров спрайтов приводит к размытию и потере детализации. В этой статье мы разберем пример использования масштабирования в Phaser с параметром `resolution`, который позволяет работать с hi-res ассетами на любых экранах, сохраняя четкость и производительность. Этот подход особенно полезен для создания игр с красивой графикой, которые должны выглядеть одинаково хорошо на iPhone с Retina дисплеем и на обычном PC мониторе.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


//  To test this on a non-retina display use Chrome Dev Tools,
//  toggle the device bar (ctrl + shift + m), pick the 'Responsive' mode and set DPR to 2.0

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

var game = new Phaser.Game(config);

function preload ()
{
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('pic', 'assets/pics/akira.jpg');
}

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

Проблема: высокое разрешение vs размеры экрана

Загружая изображение высокого разрешения (например, 1600x1200) и пытаясь поместить его в игровое окно размером 800x600, мы сталкиваемся с двумя проблемами: 1. Если просто нарисовать изображение целиком, оно будет обрезано или выйдет за границы. 2. Если масштабировать его через setScale, пиксели "размажутся", особенно на дисплеях с высоким DPR (Device Pixel Ratio).

Phaser предлагает решение через комбинацию настроек масштабирования (Scale Manager) и параметра resolution в конфиге игры.

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

Конфигурация масштабирования и параметр resolution

Ключевой элемент — объект scale в конфигурации игры. - mode: Phaser.Scale.FIT — режим масштабирования. FIT гарантирует, что игровое поле (800x600 логических пикселей) будет пропорционально вписываться в родительский элемент (parent), сохраняя соотношение сторон. - width и height — это логические размеры игры, в которых вы рассчитываете координаты и размещение объектов. - resolution: 2 — самый важный параметр для работы с hi-res. Он указывает, что загруженные изображения (ассеты) имеют разрешение вдвое выше логического. То есть, если логический размер изображения в игре 400x300, его реальный файл должен быть 800x600.

Эта связь позволяет Phaser корректно рассчитывать внутреннее масштабирование ассетов.

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

Загрузка изображения и его корректное размещение

В функции preload мы загружаем изображение высокого разрешения. В примере используется картинка akira.jpg. Важно понимать, что Phaser теперь знает, что её физическое разрешение вдвое выше логического (из-за resolution: 2).

function preload () {
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('pic', 'assets/pics/akira.jpg');
}

В функции create мы добавляем изображение в точку (0,0) и устанавливаем его масштаб в 0.5. Почему именно 0.5? Потому что логически мы хотим разместить изображение размером 800x600 (логические пиксели) в нашей игровой области 800x600. Но его реальный размер файла — 1600x1200 (вдвое больше по каждому измерению из-за resolution: 2). Коэффициент 0.5 компенсирует это: 1600 * 0.5 = 800, 1200 * 0.5 = 600.

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

Как это работает на разных дисплеях

На дисплее с DPR = 1 (обычный монитор) изображение будет отрисовано в логических размерах 800x600, используя пиксели из файла 1600x1200, но с интерполяцией (сжатием). На дисплее с DPR = 2 (Retina) система использует исходные пиксели более эффективно: каждый логический пиксель игры будет представлен двумя физическими пикселями монитора, и изображение останется четким.

Режим Phaser.Scale.FIT гарантирует, что на экране с любым физическим размером игровое поле 800x600 будет показано полностью, без обрезки. Параметр resolution и масштаб 0.5 обеспечивают корректное использование высокого разрешения ассета внутри этого поля.

Для тестирования на обычном мониторе можно использовать Chrome Dev Tools, как указано в комментарии исходника.

//  To test this on a non-retina display use Chrome Dev Tools,
//  toggle the device bar (ctrl + shift + m), pick the 'Responsive' mode and set DPR to 2.0

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

Использование resolution в конфигурации масштабирования Phaser — это чистый и эффективный способ поддержки высокого разрешения в ваших играх. Он позволяет отделить логический дизайн игры (где вы работаете с удобными координатами) от физического качества ассетов. Для экспериментов попробуйте: 1. Изменить значение resolution на 1 или 3 и подобрать соответствующий setScale. 2. Использовать разные режимы Phaser.Scale (например, ENVELOP) вместе с hi-res ассетами. 3. Загружать несколько изображений с разным исходным разрешением и масштабировать их относительно друг друга.