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

При работе с зацикленной музыкой или звуками в Phaser можно столкнуться с неочевидным поведением: после первого проигрывания трек может замолчать. Эта проблема часто возникает из-за внутреннего кэширования аудиофайлов и может испортить впечатление от игры. Данная статья разбирает конкретный пример, объясняет причину сбоя и показывает, как правильно инициализировать и воспроизводить зацикленную музыку, чтобы избежать неожиданных пауз.

Версия 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.audio('theme', [
            'assets/audio/kyobi/wavs/nextLevel.wav'
        ]);
    }

    create ()
    {
        this.add.text(32, 32, 'Click to start music', { fill: '#ffffff' });

        this.sound.pauseOnBlur = false;

        this.input.once('pointerdown', () => {

            const music = this.sound.add('theme');

            music.play({ loop: true });

            this.add.text(32, 64, '5 seconds until loop', { fill: '#ffffff' });

        });
    }
}

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

const game = new Phaser.Game(config);

Суть проблемы в примере

В предоставленном исходном коде есть скрытая проблема с воспроизведением зацикленного звука. На первый взгляд, всё логично: в preload загружается аудиофайл, а по клику он создается, проигрывается и ставится на повтор.

Однако, если запустить этот пример и подождать, может оказаться, что после завершения первого проигрывания трек не начнется заново, а просто остановится. Это поведение не соответствует ожидаемому от параметра loop: true.

Причина кроется в том, как Phaser управляет внутренними аудиоконтекстами и кэшем. Если аудио не было «подготовлено» к воспроизведению заранее, система может некорректно обработать запрос на повтор.

Правильная инициализация звука

Ключевое решение — создать звуковой объект (Sound) заранее, в методе create, а не в обработчике клика. Это позволяет Phaser полностью инициализировать аудио и правильно обработать флаг зацикливания.

Вот исправленная часть метода create. Обратите внимание, что мы создаем объект music сразу, но не запускаем его.

create ()
{
    this.add.text(32, 32, 'Щелкните, чтобы начать музыку', { fill: '#ffffff' });

    this.sound.pauseOnBlur = false;

    // Звук создается ЗАРАНЕЕ, здесь
    const music = this.sound.add('theme');

    this.input.once('pointerdown', () => {
        // А запускается уже по клику
        music.play({ loop: true });
        this.add.text(32, 64, '5 секунд до проверки цикла', { fill: '#ffffff' });
    });
}

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

Конфигурация игры и настройка сцены

Основа примера — стандартная конфигурация игры и класс сцены. Важным моментом является настройка this.sound.pauseOnBlur = false. Она предотвращает автоматическую паузу в воспроизведении звука, когда пользователь переключается на другую вкладку браузера.

Полная конфигурация игры выглядит так:

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

const game = new Phaser.Game(config);

Класс сцены Example наследуется от Phaser.Scene и содержит два обязательных метода: preload для загрузки ресурсов и create для их инициализации.

Загрузка аудиоресурсов

Все необходимые для сцены ресурсы загружаются в методе preload. В данном примере загружается один аудиофайл.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.audio('theme', [
        'assets/audio/kyobi/wavs/nextLevel.wav'
    ]);
}

Метод this.load.audio принимает два аргумента: ключ аудио ('theme'), по которому к нему можно будет обращаться, и массив путей к файлам. Phaser автоматически выберет подходящий формат (WAV, MP3, OGG) в зависимости от браузера. Указание базового URL через setBaseURL позволяет использовать относительные пути.

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

Основной вывод — для корректной работы зацикленных звуков в Phaser их объекты следует создавать на этапе инициализации сцены (create), а не откладывать создание до момента первого воспроизведения. Это позволяет аудиосистеме движка правильно «разогреться» и обрабатывать циклы. Для экспериментов попробуйте: 1. Запускать звук с задержкой через this.time.delayedCall. 2. Добавить несколько звуков с разными ключами и переключать их. 3. Управлять громкостью зацикленного трека в реальном времени через свойство volume объекта music.