О чем этот пример
В играх часто нужно проигрывать короткие звуки, например, выстрел или прыжок. Загружать каждый эффект отдельным файлом неудобно: это много запросов и сложно управлять. В Phaser есть мощный инструмент — аудиомаркеры. Они позволяют хранить все эффекты в одном аудиофайле и точно включать нужный фрагмент. В этой статье мы разберём пример, где создаётся панель с кнопками для проигрывания маркеров. Вы научитесь настраивать маркеры, создавать интерактивные кнопки и управлять звуком с точностью до миллисекунды.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
markers = [
{ name: 'alien death', start: 1, duration: 1.0, config: {} },
{ name: 'boss hit', start: 3, duration: 0.5, config: {} },
{ name: 'escape', start: 4, duration: 3.2, config: {} },
{ name: 'meow', start: 8, duration: 0.5, config: {} },
{ name: 'numkey', start: 9, duration: 0.1, config: {} },
{ name: 'ping', start: 10, duration: 1.0, config: {} },
{ name: 'death', start: 12, duration: 4.2, config: {} },
{ name: 'shot', start: 17, duration: 1.0, config: {} },
{ name: 'squit', start: 19, duration: 0.3, config: {} }
];
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('title', 'assets/pics/catastrophi.png');
this.load.spritesheet('button', 'assets/ui/flixel-button.png', { frameWidth: 80, frameHeight: 20 });
this.load.bitmapFont('nokia', 'assets/fonts/bitmap/nokia16black.png', 'assets/fonts/bitmap/nokia16black.xml');
this.load.audio('sfx', [
'assets/audio/SoundEffects/fx_mixdown.ogg',
'assets/audio/SoundEffects/fx_mixdown.mp3'
]);
}
create ()
{
this.add.image(400, 300, 'title');
for (let i = 0; i < this.markers.length; i++)
{
this.makeButton.call(this, this.markers[i].name, i);
}
this.input.on('gameobjectover', (pointer, button) =>
{
this.setButtonFrame(button, 0);
});
this.input.on('gameobjectout', (pointer, button) =>
{
this.setButtonFrame(button, 1);
});
this.input.on('gameobjectdown', function (pointer, button)
{
const index = button.getData('index');
this.sound.play('sfx', this.markers[index]);
this.setButtonFrame(button, 2);
}, this);
this.input.on('gameobjectup', (pointer, button) =>
{
this.setButtonFrame(button, 0);
});
}
makeButton (name, index)
{
const button = this.add.image(680, 115 + index * 40, 'button', 1).setInteractive();
button.setData('index', index);
button.setScale(2, 1.5);
const text = this.add.bitmapText(button.x - 40, button.y - 8, 'nokia', name, 16);
text.x += (button.width - text.width) / 2;
}
setButtonFrame (button, frame)
{
button.frame = button.scene.textures.getFrame('button', frame);
}
}
/**
* @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
*/
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example,
pixelArt: true,
audio: {
noAudio: true
}
};
const game = new Phaser.Game(config);
Что такое аудиомаркеры и зачем они нужны?
Аудиомаркеры — это метки внутри одного звукового файла. Каждая метка имеет имя, время начала и длительность. Вместо десятков маленьких файлов вы работаете с одним. Это уменьшает количество HTTP-запросов и упрощает загрузку.
В примере массив markers описывает девять звуковых эффектов в файле fx_mixdown. Например, маркер 'alien death' начинается на 1-й секунде и длится 1 секунду. Параметр config оставлен пустым для передачи дополнительных опций воспроизведения, таких как громкость или цикл.
markers = [
{ name: 'alien death', start: 1, duration: 1.0, config: {} },
{ name: 'boss hit', start: 3, duration: 0.5, config: {} },
// ... другие маркеры
];
Загрузка ресурсов и настройка аудио
В методе preload загружаются все необходимые ресурсы. Обратите внимание на загрузку аудио: используется this.load.audio с массивом путей для поддержки разных форматов (OGG и MP3). Ключ 'sfx' — это идентификатор, по которому мы будем обращаться к аудио.
Важный момент — конфигурация аудиосистемы в объекте config. Параметр audio: { noAudio: true } означает, что игра запустится даже если в браузере нет аудиоконтекста (например, на мобильных устройствах до взаимодействия пользователя). Звук будет воспроизводиться, как только контекст станет доступен.
this.load.audio('sfx', [
'assets/audio/SoundEffects/fx_mixdown.ogg',
'assets/audio/SoundEffects/fx_mixdown.mp3'
]);
const config = {
// ... другие настройки
audio: {
noAudio: true
}
};
Создание интерактивных кнопок
Для каждого маркера в массиве создаётся кнопка. Функция makeButton принимает имя маркера и его индекс.
Кнопка — это Image объект, использующий спрайтшит 'button'. Метод setInteractive делает её кликабельной. Важный прием — сохранение индекса маркера в данных кнопки с помощью setData('index', index). Позже по этому индексу мы найдём нужный маркер в массиве.
Рядом с кнопкой создаётся текст с именем эффекта, используя bitmap-шрифт 'nokia'. Позиция текста центрируется относительно кнопки.
makeButton (name, index)
{
const button = this.add.image(680, 115 + index * 40, 'button', 1).setInteractive();
button.setData('index', index);
button.setScale(2, 1.5);
const text = this.add.bitmapText(button.x - 40, button.y - 8, 'nokia', name, 16);
text.x += (button.width - text.width) / 2;
}
Обработка событий мыши и воспроизведение звука
Основная логика находится в обработчиках событий ввода, назначенных в create. События gameobjectover и gameobjectout меняют кадр кнопки при наведении и уходе курсора, создавая визуальный отклик.
Ключевое событие — gameobjectdown (кнопка мыши нажата). В его обработчике мы:
1. Получаем индекс маркера из данных кнопки: button.getData('index').
2. Воспроизводим звук с этим маркером: this.sound.play('sfx', this.markers[index]). Вторым аргументом передаётся объект маркера, что указывает Phaser проиграть именно этот фрагмент.
3. Меняем кадр кнопки на "нажатый".
Функция setButtonFrame изменяет отображаемый кадр спрайтшита кнопки.
this.input.on('gameobjectdown', function (pointer, button)
{
const index = button.getData('index');
this.sound.play('sfx', this.markers[index]);
this.setButtonFrame(button, 2);
}, this);
setButtonFrame (button, frame)
{
button.frame = button.scene.textures.getFrame('button', frame);
}
Что попробовать дальше
Использование аудиомаркеров в Phaser — это профессиональный подход к управлению звуковыми эффектами. Он экономит ресурсы и даёт точный контроль над временем воспроизведения. На основе этого примера можно создать систему звукового меню для тестирования, редактор маркеров или сложную логику воспроизведения, где эффекты запускаются в ответ на игровые события. Попробуйте расширить пример: добавьте регулировку громкости для отдельных маркеров, визуализацию waveforms или возможность динамически создавать маркеры через UI.
