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

Библиотека Phaser предоставляет мощный API для работы с аудио, позволяя создавать сложные музыкальные системы для игр. В основе лежит объект Sound, доступный через сцену (this.sound), который поддерживает воспроизведение, паузы, останавливать и управлять громкостью и петлями. Для организации очереди треков используется массив или очередь объектов Sound, управляемых вручную или с помощью событий Phaser.

Создание и загрузка треков

Треки добавляются через загрузчик сцены preload:

preload() {
    this.load.audio('track1', 'assets/audio/track1.mp3');
    this.load.audio('track2', 'assets/audio/track2.mp3');
    this.load.audio('track3', 'assets/audio/track3.mp3');
}

После загрузки можно создать объекты Sound:

create() {
    this.track1 = this.sound.add('track1');
    this.track2 = this.sound.add('track2');
    this.track3 = this.sound.add('track3');
    
    this.playQueue = [this.track1, this.track2, this.track3];
}

Реализация очереди воспроизведения

Очередь воспроизведения представляет собой упорядоченный массив треков, которые воспроизводятся последовательно. В Phaser удобно использовать события on('complete', callback) для автоматического перехода к следующему треку:

playNextTrack(index = 0) {
    if (index >= this.playQueue.length) {
        return; // очередь завершена
    }
    
    let currentTrack = this.playQueue[index];
    currentTrack.play();
    
    currentTrack.once('complete', () => {
        this.playNextTrack(index + 1);
    });
}

Метод once('complete', ...) гарантирует, что событие сработает один раз и не создаст лишних подписок.

Перебивка треков

Перебивка трека — это немедленное прекращение текущего воспроизведения и запуск нового трека. Для этого используется метод stop():

interruptTrack(newTrack) {
    if (this.currentTrack && this.currentTrack.isPlaying) {
        this.currentTrack.stop();
    }
    this.currentTrack = newTrack;
    this.currentTrack.play();
}

Можно расширить логику перебивки, учитывая плавное затухание (fade out) текущего трека перед запуском нового:

fadeOutAndPlay(newTrack, duration = 1000) {
    if (this.currentTrack && this.currentTrack.isPlaying) {
        this.tweens.add({
            targets: this.currentTrack,
            volume: 0,
            duration: duration,
            onComplete: () => {
                this.currentTrack.stop();
                newTrack.volume = 1;
                newTrack.play();
                this.currentTrack = newTrack;
            }
        });
    } else {
        newTrack.play();
        this.currentTrack = newTrack;
    }
}

Использование tweens позволяет сделать перебивку плавной, без резких изменений громкости.

Циклическая очередь и случайный порядок

Для создания циклической очереди после завершения последнего трека можно перезапускать массив:

playNextTrackLoop(index = 0) {
    let currentTrack = this.playQueue[index % this.playQueue.length];
    currentTrack.play();
    
    currentTrack.once('complete', () => {
        this.playNextTrackLoop(index + 1);
    });
}

Для случайного воспроизведения используется перемешивание массива:

shuffleQueue() {
    for (let i = this.playQueue.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [this.playQueue[i], this.playQueue[j]] = [this.playQueue[j], this.playQueue[i]];
    }
}

Управление громкостью и панорамой

Phaser позволяет индивидуально настраивать громкость и панораму трека:

this.track1.setVolume(0.8); // от 0 до 1
this.track1.setPan(-1);     // от -1 (лево) до 1 (право)

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

Автоматизация очереди с объектами конфигурации

Для крупных проектов удобно хранить треки в массиве объектов с дополнительной конфигурацией:

this.playQueue = [
    { sound: this.track1, volume: 0.8 },
    { sound: this.track2, volume: 1.0 },
    { sound: this.track3, volume: 0.5 }
];

playNextConfiguredTrack(index = 0) {
    if (index >= this.playQueue.length) return;
    let trackConfig = this.playQueue[index];
    trackConfig.sound.setVolume(trackConfig.volume);
    trackConfig.sound.play();
    
    trackConfig.sound.once('complete', () => {
        this.playNextConfiguredTrack(index + 1);
    });
}

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

Взаимодействие с другими системами Phaser

Очередь аудио может быть интегрирована с игровыми событиями:

  • Смена уровня — перебивка текущего трека новым музыкальным фоном.
  • События игрока — воспроизведение коротких эффектов поверх фонового трека.
  • Пауза игры — приостанавливать все треки через this.sound.pauseAll().
  • Возобновление — через this.sound.resumeAll().

Использование этих методов позволяет синхронизировать музыку и игровые события без дополнительных сложностей.