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

Обработка смены ориентации устройства — ключевая задача для мобильных игр. Неправильная реакция на поворот экрана может испортить пользовательский опыт, особенно на iOS, где поведение браузера имеет свои особенности. Рассмотрим, как использовать Scale Manager в Phaser для точного определения ориентации и адаптации игрового процесса под текущее положение устройства. Эта техника полезна не только для корректного отображения интерфейса, но и для реализации геймплея, завязанного на ориентацию (например, в головоломках или аркадах), и для сбора аналитики о том, как пользователи предпочитают играть.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor()
    {
        super();
    }

    preload ()
    {
        // this.load.setBaseURL('https://cdn.phaserfiles.com/v385');
    }

    create ()
    {
        var print = this.add.text(0, 0, '');

        this.scale.on('orientationchange', function (orientation)
        {
            var s = [ orientation ];
            if (orientation === Phaser.Scale.PORTRAIT)
            {
                s.push('PORTRAIT PRIMARY')
            }
            else if (orientation === Phaser.Scale.PORTRAIT_SECONDARY)
            {
                s.push('PORTRAIT SECONDARY')
            }
            else if (orientation === Phaser.Scale.LANDSCAPE)
            {
                s.push('LANDSCAPE PRIMARY')
            }
            else if (orientation === Phaser.Scale.LANDSCAPE_SECONDARY)
            {
                s.push('LANDSCAPE SECONDARY')
            } else
            {
                s.push('??')
            }

            print.text = s.join('\n')
        });

        print.text = this.scale.orientation;
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Настройка Scale Manager: Основа работы

Вся магия отслеживания ориентации начинается с правильной конфигурации игры. Ключевым объектом здесь является config, который передается в конструктор Phaser.Game. Хотя в примере явно не заданы настройки масштабирования, Phaser по умолчанию создает Scale Manager, который отслеживает изменения состояния окна браузера, включая ориентацию.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: Example
};

Важно помнить, что для мобильных устройств часто требуется дополнительная настройка масштабирования (например, использование scale.mode: Phaser.Scale.FIT), чтобы игра занимала весь экран. В данном же примере фокус сделан именно на событии смены ориентации.

Событие orientationchange: Ловим поворот

Ядро логики находится в методе create сцены. Мы подписываемся на событие 'orientationchange' объекта this.scale. Это событие генерируется Scale Manager каждый раз, когда система браузера определяет изменение ориентации устройства.

this.scale.on('orientationchange', function (orientation) {
    // Обработчик события
});

Обработчик получает один аргумент — orientation. Это числовая константа, которую Phaser получает от браузера. Не стоит путать это событие с нативным JavaScript-событием window.orientationchange — Phaser абстрагирует эту логику и предоставляет унифицированный API.

Определяем тип ориентации: Декодируем константы

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

if (orientation === Phaser.Scale.PORTRAIT) {
    s.push('PORTRAIT PRIMARY')
}
else if (orientation === Phaser.Scale.PORTRAIT_SECONDARY) {
    s.push('PORTRAIT SECONDARY')
}
else if (orientation === Phaser.Scale.LANDSCAPE) {
    s.push('LANDSCAPE PRIMARY')
}
else if (orientation === Phaser.Scale.LANDSCAPE_SECONDARY) {
    s.push('LANDSCAPE SECONDARY')
} else {
    s.push('??')
}

* PORTRAIT и LANDSCAPE — это основные (primary) ориентации (когда устройство повернуто «естественным» образом). * PORTRAIT_SECONDARY и LANDSCAPE_SECONDARY — обратные (secondary) ориентации (устройство перевернуто). Такой подход позволяет точно реагировать не просто на «альбомный» или «книжный» режим, а на конкретный разворот устройства, что может быть критично для игр с управлением акселерометром.

Отображение состояния: Текстовый вывод

Для демонстрации результата в примере используется текстовый объект. При старте сцены мы сразу выводим текущую ориентацию, доступную через свойство this.scale.orientation.

print.text = this.scale.orientation;

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

print.text = s.join('\n')

Такой подход полезен для отладки. В реальном проекте вместо вывода текста вы, скорее всего, будете вызывать метод ремасштабирования игрового мира, перераспределения элементов UI или изменения логики управления.

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

Использование события orientationchange от Scale Manager — это надежный и кроссплатформенный способ сделать вашу игру на Phaser отзывчивой к поворотам экрана. Он избавляет от необходимости работать напрямую с сырыми API браузера, которые могут отличаться на iOS и Android. Для экспериментов попробуйте: 1. Связать смену ориентации с переключением между двумя разными игровыми сценами или режимами камеры. 2. Динамически менять расположение элементов управления (например, джойстика) в зависимости от того, в какой руке пользователь держит устройство (определяется по PRIMARY/SECONDARY). 3. Реализовать «жесткую» блокировку игры в одной ориентации, но с возможностью ручного переворота через системную кнопку, обрабатывая это событие.