О чем этот пример
Работа с анимациями на базе Spine — мощный инструмент для создания плавной и сложной графики в играх. Однако неправильная загрузка атласов может привести к ошибкам, когда модель отображается без текстур. Этот пример демонстрирует корректную настройку загрузки данных Spine, включая JSON-файл скелета и атлас текстур, а также показывает разницу между немедленным и отложенным созданием объектов. Понимание этого механизма поможет вам избежать распространённых проблем и эффективно управлять ресурсами в проекте.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super({
pack: {
files: [
{ type: 'scenePlugin', key: 'SpinePlugin', url: 'plugins/3.8.95/SpinePluginDebug.js', sceneKey: 'spine' }
]
}
});
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('logo', 'assets/sprites/phaser2.png');
this.load.setPath('assets/spine/3.8/demos/');
this.load.spine('set1', 'demos.json', [ 'atlas1.atlas' ], true);
}
create ()
{
this.add.image(32, 32, 'logo').setOrigin(0);
this.input.once('pointerdown', () => {
this.make.spine({
x: 600,
y: 600,
key: 'set1.spineboy'
}, true);
});
window.setTimeout(() => {
this.make.spine({
x: 400,
y: 600,
key: 'set1.spineboy'
}, false);
}, 1000);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#000000',
scene: Example
};
const game = new Phaser.Game(config);
Настройка сцены и загрузка плагина
В конструкторе сцены происходит предварительная настройка. Ключевой момент — указание, что для этой сцены нужно загрузить и использовать плагин SpinePlugin. Это делается через конфигурационный объект, передаваемый в super().
constructor ()
{
super({
pack: {
files: [
{ type: 'scenePlugin', key: 'SpinePlugin', url: 'plugins/3.8.95/SpinePluginDebug.js', sceneKey: 'spine' }
]
}
});
}
Параметр pack определяет файлы, которые нужно загрузить до вызова preload(). Здесь мы указываем загрузку Scene Plugin (type: 'scenePlugin'). Плагин будет доступен в сцене по ключу sceneKey: 'spine'. Использование отладочной версии (SpinePluginDebug.js) может быть полезно для диагностики.
Загрузка ресурсов: изображение и данные Spine
Метод preload() отвечает за загрузку всех необходимых для сцены ресурсов. Важно правильно задавать пути и использовать специфичные для Spine методы загрузки.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('logo', 'assets/sprites/phaser2.png');
this.load.setPath('assets/spine/3.8/demos/');
this.load.spine('set1', 'demos.json', [ 'atlas1.atlas' ], true);
}
Сначала задаётся базовый URL для всех последующих загрузок. Затем загружается обычное изображение-логотип. Далее метод this.load.setPath() меняет текущий путь на папку с демо-данными Spine. Ключевой вызов — this.load.spine(). Он загружает данные Spine:
- 'set1' — ключ, по которому набор данных будет доступен в кеше.
- 'demos.json' — файл скелета (скелет, кости, анимации).
- [ 'atlas1.atlas' ] — массив файлов атласов текстур. Именно здесь часто возникает ошибка, если указать неверный путь или имя файла.
- true — флаг, указывающий на необходимость загрузки связанных с атласом PNG-изображений текстур. Если false, текстуры нужно загружать отдельно.
Создание Spine-объектов: немедленно и с задержкой
В методе create() мы создаём объекты. Пример наглядно показывает разницу между созданием объекта по клику мыши и созданием с задержкой.
create ()
{
this.add.image(32, 32, 'logo').setOrigin(0);
this.input.once('pointerdown', () => {
this.make.spine({
x: 600,
y: 600,
key: 'set1.spineboy'
}, true);
});
window.setTimeout(() => {
this.make.spine({
x: 400,
y: 600,
key: 'set1.spineboy'
}, false);
}, 1000);
}
Сначала добавляется статичное лого. Затем на событие однократного клика (pointerdown) назначается создание Spine-объекта через фабрику this.make.spine(). Объект создаётся в точке (600, 600). Ключ 'set1.spineboy' состоит из двух частей: 'set1' — ключ загруженного набора данных, 'spineboy' — имя конкретного скелета внутри этого JSON-файла. Второй аргумент true означает, что анимация начнёт проигрываться сразу после создания.
Далее, с помощью setTimeout, через секунду создаётся второй такой же объект, но с аргументом false. Это значит, что его анимация будет остановлена в начальном состоянии (T-pose).
Конфигурация игры и запуск
Код завершается созданием экземпляра игры Phaser.Game с необходимой конфигурацией.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#000000',
scene: Example
};
const game = new Phaser.Game(config);
Конфиг задаёт использование WebGL-рендерера (type: Phaser.WEBGL), что рекомендуется для Spine из-за его производительности. Указывается ID родительского HTML-элемента (parent), размеры холста и цвет фона. Сама сцена Example передаётся в свойстве scene. После этого создание объекта new Phaser.Game(config) запускает весь жизненный цикл.
Что попробовать дальше
Корректная загрузка Spine-анимаций в Phaser сводится к точному указанию путей к JSON-файлу скелета и файлам атласов в методе this.load.spine(). Фабрика this.make.spine() позволяет удобно создавать экземпляры моделей. Для экспериментов попробуйте
- изменить второй параметр в
this.make.spine()наfalseдля первого объекта и наtrueдля второго, чтобы наблюдать разницу в старте анимации - загрузить другой набор данных Spine и создать из него объект
- добавить обработку событий анимации (start, complete) для созданных spine-объектов через их свойство
.on
