О чем этот пример
Звуковой чип SID (Sound Interface Device) из легендарного компьютера Commodore 64 — это не просто ретро, а целая культура. Его характерное звучание до сих пор используется в инди-играх для создания атмосферы. В этой статье мы разберем, как интегрировать настоящую SID-музыку в вашу игру на Phaser, используя готовый плагин. Вы научитесь загружать бинарные файлы .sid, переключать треки и сабтреки, а также отображать метаданные композиции прямо в игре.
Версия 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('title1', 'assets/tests/c64/thrust.png');
this.load.image('title2', 'assets/tests/c64/cybernoid.png');
this.load.image('title3', 'assets/tests/c64/robocop.png');
this.load.image('title4', 'assets/tests/c64/cybernoid2.png');
this.load.image('title5', 'assets/tests/c64/warhawk.png');
this.load.image('title6', 'assets/tests/c64/stormlord.png');
this.load.image('title7', 'assets/tests/c64/zoids.png');
this.load.binary('tune1', 'assets/audio/sid/thrust.sid');
this.load.binary('tune2', 'assets/audio/sid/cybernoid.sid');
this.load.binary('tune3', 'assets/audio/sid/robocop.sid');
this.load.binary('tune4', 'assets/audio/sid/cybernoid2.sid');
this.load.binary('tune5', 'assets/audio/sid/warhawk.sid');
this.load.binary('tune6', 'assets/audio/sid/stormlord.sid');
this.load.binary('tune7', 'assets/audio/sid/zoids.sid');
this.load.plugin('SIDPlayerPlugin', 'assets/audio/sid/SIDPlayerPluginES5.js', true);
this.load.script('jsSID', 'assets/audio/sid/jsSID.js');
}
create ()
{
this.currenTune = 1;
let tune = 1;
this.title = this.add.image(400, 350, `title${tune}`);
this.add.text(400, 570, 'Click to change Tune. Left / Right cursor changes Sub-Tune', { font: '16px Courier', fill: '#ffffff' }).setShadow(1, 1).setOrigin(0.5, 0);
const text = this.add.text(10, 10, 'SID Player', { font: '16px Courier', fill: '#ffffff' }).setShadow(1, 1);
const SIDplayer = this.plugins.get('SIDPlayerPlugin');
let sidData = this.cache.binary.get(`tune${tune}`);
SIDplayer.loadLocal(sidData);
SIDplayer.setmodel(6581);
let i = 0;
let max = SIDplayer.getsubtunes();
this.updateText(tune, text, SIDplayer, i);
this.input.keyboard.on('keyup-LEFT', () =>
{
if (i > 0)
{
i--;
SIDplayer.loadLocal(sidData, i);
this.updateText(tune, text, SIDplayer, i);
}
});
this.input.keyboard.on('keyup-RIGHT', () =>
{
if (i < max)
{
i++;
SIDplayer.loadLocal(sidData, i);
this.updateText(tune, text, SIDplayer, i);
}
});
this.input.on('pointerdown', () =>
{
if (tune < 7)
{
tune++;
}
else
{
tune = 1;
}
sidData = this.cache.binary.get(`tune${tune}`);
SIDplayer.loadLocal(sidData);
i = 0;
max = SIDplayer.getsubtunes();
this.updateText(tune, text, SIDplayer, i);
});
}
updateText (tune, text, SIDplayer, i)
{
const title = SIDplayer.gettitle().replace(/\0/g, '');
const author = SIDplayer.getauthor().replace(/\0/g, '');
const info = SIDplayer.getinfo().replace(/\0/g, '');
text.setText([
'Title: ' + title,
'Author: ' + author,
'Info: ' + info,
'Current Sub-Tune: ' + i,
'Total Sub-Tunes: ' + SIDplayer.getsubtunes(),
'Pref. Model: ' + SIDplayer.getprefmodel(),
'Playtime: ' + SIDplayer.getplaytime(),
'Playback Model: ' + SIDplayer.getmodel()
]);
if (this.currenTune !== tune)
{
this.currenTune = tune;
this.title.setTexture(`title${tune}`);
}
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#3c39a9',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов: картинки, музыка и плагин
В методе preload() происходит подготовка всех необходимых ресурсов. Для каждого музыкального трека загружается его обложка (изображение) и сам бинарный файл .sid. Ключевой момент — загрузка внешнего плагина SIDPlayerPlugin и скрипта jsSID, которые и обеспечивают декодирование и воспроизведение SID-формата.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('title1', 'assets/tests/c64/thrust.png');
this.load.binary('tune1', 'assets/audio/sid/thrust.sid');
this.load.plugin('SIDPlayerPlugin', 'assets/audio/sid/SIDPlayerPluginES5.js', true);
this.load.script('jsSID', 'assets/audio/sid/jsSID.js');
Инициализация и запуск первого трека
В create() происходит начальная настройка. Сначала из кэша извлекаются бинарные данные первого трека с помощью this.cache.binary.get. Затем через this.plugins.get получаем экземпляр загруженного плагина SIDPlayerPlugin. Метод loadLocal() плагина загружает данные трека, а setmodel() явно устанавливает модель эмулируемого чипа SID (в данном случае 6581).
const SIDplayer = this.plugins.get('SIDPlayerPlugin');
let sidData = this.cache.binary.get(`tune${tune}`);
SIDplayer.loadLocal(sidData);
SIDplayer.setmodel(6581);
Управление воспроизведением: треки и сабтреки
В примере реализовано два типа управления. Клик мыши (или тап) переключает между семью основными мелодиями. При этом обновляются данные в кэше и происходит перезагрузка трека в плагин. Клавиши LEFT и RIGHT на клавиатуре переключают сабтреки (sub-tunes) внутри текущей композиции. Это типично для SID-файлов, где одна композиция может содержать несколько вариаций (интро, основной трек, аутро).
this.input.on('pointerdown', () => {
if (tune < 7) { tune++; } else { tune = 1; }
sidData = this.cache.binary.get(`tune${tune}`);
SIDplayer.loadLocal(sidData);
});
this.input.keyboard.on('keyup-LEFT', () => {
if (i > 0) { i--; SIDplayer.loadLocal(sidData, i); }
});
Отображение метаданных композиции
Плагин SIDPlayer предоставляет методы для извлечения метаинформации, которая хранится в заголовке файла .sid. Метод updateText() форматирует эти данные и выводит на экран. Важный нюанс: строки из плагина могут содержать нулевые символы \0, которые необходимо обрезать с помощью .replace(/\0/g, '') для корректного отображения. Также здесь обновляется текстура изображения-обложки.
const title = SIDplayer.gettitle().replace(/\0/g, '');
const author = SIDplayer.getauthor().replace(/\0/g, '');
const info = SIDplayer.getinfo().replace(/\0/g, '');
text.setText([
'Title: ' + title,
'Author: ' + author,
'Info: ' + info,
'Current Sub-Tune: ' + i
]);
if (this.currenTune !== tune) {
this.title.setTexture(`title${tune}`);
}
Что попробовать дальше
Интеграция SID-музыки через внешний плагин — отличный способ добавить в вашу игру на Phaser аутентичный ретро-саунд. Вы можете экспериментировать: создать собственный аудиоплеер с визуализацией, привязать смену треков к игровым событиям (уровень, босс, меню) или собрать библиотеку из свободно распространяемых .sid-файлов. Это придаст проекту уникальное звуковое оформление.
