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

Добавление звукового сопровождения — ключевой элемент игровой атмосферы. В этом примере мы разберем, как загрузить несколько аудиодорожек и привязать их воспроизведение к нажатию клавиш на клавиатуре, создав простой интерактивный аудиомикшер. Этот паттерн полезен не только для музыкальных игр, но и для управления звуковыми эффектами (выстрелы, шаги, диалоги) в любом проекте. Вы научитесь работать с системой аудио 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.image('touhou', 'assets/pics/touhou1.png');

        this.load.setPath('assets/audio/tech');

        this.load.audio('bass', [ 'bass.ogg', 'bass.mp3' ]);
        this.load.audio('drums', [ 'drums.ogg', 'drums.mp3' ]);
        this.load.audio('percussion', [ 'percussion.ogg', 'percussion.mp3' ]);
        this.load.audio('synth1', [ 'synth1.ogg', 'synth1.mp3' ]);
        this.load.audio('synth2', [ 'synth2.ogg', 'synth2.mp3' ]);
        this.load.audio('top1', [ 'top1.ogg', 'top1.mp3' ]);
        this.load.audio('top2', [ 'top2.ogg', 'top2.mp3' ]);
    }

    create ()
    {
        this.add.image(790, 600, 'touhou').setOrigin(1);

        const bass = this.sound.add('bass');
        const drums = this.sound.add('drums');
        const percussion = this.sound.add('percussion');
        const synth1 = this.sound.add('synth1');
        const synth2 = this.sound.add('synth2');
        const top1 = this.sound.add('top1');
        const top2 = this.sound.add('top2');

        const keys = [
            'Press A for Bass',
            'Press B for Drums',
            'Press C for Percussion',
            'Press D for Synth1',
            'Press E for Synth2',
            'Press F for Top1',
            'Press G for Top2',
            '',
            'SPACE to stop all sounds'
        ];

        const text = this.add.text(10, 10, keys, { font: '32px Courier', fill: '#00ff00' });

        if (this.sound.locked)
        {
            text.setText('Click to start');

            this.sound.once('unlocked', () =>
            {
                text.setText(keys);
            });
        }

        this.input.keyboard.on('keydown-SPACE', function ()
        {
            this.sound.stopAll();
        }, this);

        this.input.keyboard.on('keydown-A', () =>
        {
            bass.play();
        });

        this.input.keyboard.on('keydown-B', () =>
        {
            drums.play();
        });

        this.input.keyboard.on('keydown-C', () =>
        {
            percussion.play();
        });

        this.input.keyboard.on('keydown-D', () =>
        {
            synth1.play();
        });

        this.input.keyboard.on('keydown-E', () =>
        {
            synth2.play();
        });

        this.input.keyboard.on('keydown-F', () =>
        {
            top1.play();
        });

        this.input.keyboard.on('keydown-G', () =>
        {
            top2.play();
        });
    }
}

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

const game = new Phaser.Game(config);

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

Перед использованием звуков их необходимо загрузить. В методе preload() мы настраиваем базовые пути и загружаем один изображение для фона и семь аудиофайлов.

Важно: Phaser рекомендует загружать аудио в нескольких форматах (например, .ogg и .mp3) для максимальной кросс-браузерной совместимости. Метод this.load.audio() принимает ключ для идентификации звука и массив путей к файлам.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('touhou', 'assets/pics/touhou1.png');

this.load.setPath('assets/audio/tech');

this.load.audio('bass', [ 'bass.ogg', 'bass.mp3' ]);
this.load.audio('drums', [ 'drums.ogg', 'drums.mp3' ]);
// ... загрузка остальных звуков

Создание звуковых объектов и управляющего интерфijейса

В методе create() мы создаем игровые объекты, которые будут управлять звуком и отображать подсказки.

Сначала создаются экземпляры звуков с помощью this.sound.add(). Каждый экземпляр можно контролировать независимо (воспроизводить, останавливать, настраивать громкость).

Затем на экран выводится текстовая подсказка, которая показывает, какая клавиша отвечает за какой звук.

const bass = this.sound.add('bass');
const drums = this.sound.add('drums');
// ... создание остальных звуковых объектов

const keys = [
    'Press A for Bass',
    'Press B for Drums',
    // ... остальные подсказки
    'SPACE to stop all sounds'
];

const text = this.add.text(10, 10, keys, { font: '32px Courier', fill: '#00ff00' });

Обработка блокировки автовоспроизведения

Современные браузеры блокируют автовоспроизведение аудио до первого взаимодействия пользователя со страницей. Phaser предоставляет свойство this.sound.locked для отслеживания этого состояния.

Если звук заблокирован, мы меняем текст на 'Click to start'. Как только пользователь кликнет по странице (или нажмет любую клавишу), сработает событие unlocked, и мы восстановим оригинальные подсказки. Это обязательный паттерн для корректной работы аудио в браузере.

if (this.sound.locked)
{
    text.setText('Click to start');

    this.sound.once('unlocked', () =>
    {
        text.setText(keys);
    });
}

Привязка звуков к событиям клавиатуры

Ядро примера — обработка нажатий клавиш. Мы используем менеджер ввода this.input.keyboard.on(), чтобы назначить обработчики для конкретных клавиш.

Для каждой клавиши (от A до G) создается слушатель события keydown, который вызывает метод .play() у соответствующего звукового объекта. Это позволяет мгновенно запускать звуки по требованию игрока.

Отдельно обрабатывается клавиша SPACE, которая через метод this.sound.stopAll() останавливает все воспроизводимые в данный момент звуки, что полезно для быстрого сброса.

this.input.keyboard.on('keydown-A', () =>
{
    bass.play();
});

// ... обработчики для клавиш B-G

this.input.keyboard.on('keydown-SPACE', function ()
{
    this.sound.stopAll();
}, this);

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

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