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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    text;
    ship;

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

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

        this.text = this.add.text(320, 128, 'Please set your\nphone to landscape', { font: '48px Courier', fill: '#00ff00', align: 'center' }).setOrigin(0.5);

        this.checkOriention(this.scale.orientation);

        this.scale.on('orientationchange', this.checkOriention, this);
    }

    checkOriention (orientation)
    {
        if (orientation === Phaser.Scale.PORTRAIT)
        {
            this.ship.alpha = 0.2;
            this.text.setVisible(true);
        }
        else if (orientation === Phaser.Scale.LANDSCAPE)
        {
            this.ship.alpha = 1;
            this.text.setVisible(false);
        }
    }
}

const config = {
    type: Phaser.AUTO,
    backgroundColor: '#000000',
    scale: {
        mode: Phaser.Scale.FIT,
        parent: 'phaser-example',
        autoCenter: 1,
        width: 640,
        height: 256
    },
    scene: Example
};

const game = new Phaser.Game(config);

Настройка Scale Manager в конфигурации

Вся работа с ориентацией начинается с правильной конфигурации scale в объекте конфигурации игры. Именно здесь мы задаём базовые правила масштабирования.

const config = {
    scale: {
        mode: Phaser.Scale.FIT,
        parent: 'phaser-example',
        autoCenter: 1,
        width: 640,
        height: 256
    },
    scene: Example
};

Ключевые параметры: - mode: Phaser.Scale.FIT гарантирует, что игра будет пропорционально вписана в родительский контейнер без обрезки. - autoCenter: 1 центрирует игровое поле по горизонтали и вертикали. - width и height задают внутреннее разрешение игры (размер игрового мира), под которое создаются ваши ассеты.

Получение текущей ориентации и подписка на события

В методе create() сцены мы можем сразу получить текущую ориентацию и подписаться на её изменения. Это делается с помощью свойства this.scale.orientation и события orientationchange.

create ()
{
    // Создаём игровые объекты
    this.ship = this.add.image(0, 0, 'pic').setOrigin(0);
    this.text = this.add.text(320, 128, 'Please set your\nphone to landscape', { font: '48px Courier', fill: '#00ff00', align: 'center' }).setOrigin(0.5);

    // Проверяем ориентацию при старте
    this.checkOriention(this.scale.orientation);

    // Подписываемся на событие изменения ориентации
    this.scale.on('orientationchange', this.checkOriention, this);
}

Метод this.scale.on принимает три аргумента: имя события, функцию-обработчик и контекст (this), который будет передан в эту функцию. Без указания контекста this внутри checkOriention будет неопределён.

Обработчик изменений: метод checkOriention

Ядро логики находится в методе checkOriention. Он получает текущую ориентацию в качестве аргумента и сравнивает её с константами Phaser.Scale.PORTRAIT и Phaser.Scale.LANDSCAPE.

checkOriention (orientation)
{
    if (orientation === Phaser.Scale.PORTRAIT)
    {
        this.ship.alpha = 0.2;
        this.text.setVisible(true);
    }
    else if (orientation === Phaser.Scale.LANDSCAPE)
    {
        this.ship.alpha = 1;
        this.text.setVisible(false);
    }
}

В портретном режиме корабль становится полупрозрачным (альфа-канал 0.2), а текстовое предупреждение отображается. В альбомном режиме корабль полностью видим, а текст скрывается. Это наглядный способ дать пользователю понять, как правильно держать устройство.

Практические советы и распространённые сценарии

Простого переключения видимости часто недостаточно. Вот что ещё можно делать в обработчике orientationchange:

// Пример: изменение положения UI-элементов
if (orientation === Phaser.Scale.LANDSCAPE) {
    uiPanel.setPosition(600, 50); // Панель справа
} else {
    uiPanel.setPosition(50, 300); // Панель снизу
}

// Пример: перезапуск физического мира
if (orientation === Phaser.Scale.LANDSCAPE) {
    this.physics.world.setBounds(0, 0, 800, 400);
} else {
    this.physics.world.setBounds(0, 0, 400, 800);
}

Важно помнить, что при смене ориентации физические границы мира (world bounds) не меняются автоматически. Их нужно обновлять вручную, чтобы объекты не "улетали" за экран.

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

Scale Manager в Phaser — это мощный и простой инструмент для создания отзывчивых мобильных игр. Для экспериментов попробуйте не скрывать, а перераспределять UI-элементы, менять активность игровых механик (например, в портрете управление тапом, в альбоме — виртуальный джойстик) или динамически подгружать ассеты разного размера в зависимости от ориентации.