О чем этот пример
Анимации, созданные в Aseprite — мощный инструмент для 2D-игр, но иногда их скорость по умолчанию не подходит под геймплей. В этом примере показано, как загрузить анимации из Aseprite, создать из них теги в 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.path = 'assets/animations/aseprite/';
this.load.aseprite('paladin', 'paladin.png', 'paladin.json');
}
create ()
{
const tags = this.anims.createFromAseprite('paladin');
const sprite = this.add.sprite(500, 300).play({
key: 'Magnum Break',
repeat: -1,
frameRate: 4
}).setScale(6);
for (let i = 0; i < tags.length; i++)
{
const label = this.add.text(32, 32 + (i * 16), tags[ i ].key, { color: '#00ff00' });
label.setInteractive();
}
this.input.on('gameobjectdown', (pointer, obj) =>
{
// const frameRate = Phaser.Math.RND.between(0,1) ? 4 : undefined;
sprite.play({
key: obj.text,
repeat: -1,
// frameRate: frameRate
});
});
this.input.on('gameobjectover', (pointer, obj) =>
{
obj.setColor('#ff00ff');
});
this.input.on('gameobjectout', (pointer, obj) =>
{
obj.setColor('#00ff00');
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка данных Aseprite
Phaser может загружать не только изображения, но и данные об анимациях из формата Aseprite JSON. Для этого используется метод load.aseprite, который принимает три аргумента: ключ ассета, путь к изображению и путь к JSON-файлу с данными.
this.load.aseprite('paladin', 'paladin.png', 'paladin.json');
Здесь мы загружаем спрайт с ключом 'paladin'. Важно отметить использование load.setBaseURL и load.path — они задают базовый URL и путь для всех последующих загрузок, что упрощает указание путей к ресурсам.
Создание анимаций из тегов Aseprite
После загрузки данных мы можем создать анимации Phaser на основе тегов, определённых в Aseprite. Метод this.anims.createFromAseprite делает всю работу: он парсит JSON, находит все теги (tags) и создаёт из них готовые анимации в системе Phaser.
const tags = this.anims.createFromAseprite('paladin');
Метод возвращает массив созданных анимаций. Каждый элемент массива — это объект конфигурации анимации (Phaser.Animations.Animation), содержащий, среди прочего, свойство key с именем тега. Эти ключи мы позже используем для воспроизведения.
Воспроизведение анимации и управление скоростью
Создадим спрайт и сразу запустим на нём одну из анимаций. Ключ 'Magnum Break' должен соответствовать одному из тегов в файле Aseprite.
const sprite = this.add.sprite(500, 300).play({
key: 'Magnum Break',
repeat: -1,
frameRate: 4
}).setScale(6);
Метод play принимает объект конфигурации. Здесь repeat: -1 означает бесконечное повторение, а frameRate: 4 явно задаёт скорость анимации в кадрах в секунду. Это ключевой момент: даже если в Aseprite анимация была настроена на другой скорости, мы можем её переопределить. Если параметр frameRate не указать, будет использована скорость из исходных данных Aseprite.
Интерактивный переключатель анимаций
Для наглядности создадим интерфейс: выведем список всех доступных тегов-анимаций в виде текста на экране и сделаем их кликабельными.
for (let i = 0; i < tags.length; i++) {
const label = this.add.text(32, 32 + (i * 16), tags[i].key, { color: '#00ff00' });
label.setInteractive();
}
Каждая текстовая метка становится интерактивным игровым объектом. Далее мы настраиваем обработчик события gameobjectdown на системном объекте this.input.
this.input.on('gameobjectdown', (pointer, obj) => {
sprite.play({
key: obj.text,
repeat: -1
});
});
При клике на метку мы берём её текстовое содержимое (obj.text), которое совпадает с ключом анимации, и передаём его в метод sprite.play. Это переключает анимацию на выбранную. Обратите внимание, что здесь мы не передаём frameRate, поэтому анимация будет воспроизводиться со скоростью, взятой из данных Aseprite.
Визуальный фидбек для интерфейса
Чтобы интерфейс был более отзывчивым, добавим простой эффект наведения на текстовые метки. Для этого используем события gameobjectover и gameobjectout.
this.input.on('gameobjectover', (pointer, obj) => {
obj.setColor('#ff00ff');
});
this.input.on('gameobjectout', (pointer, obj) => {
obj.setColor('#00ff00');
});
Метод setColor объекта текста (Phaser.GameObjects.Text) меняет его цвет. При наведении курсора цвет меняется на розовый (#ff00ff), а при уходе — возвращается к зелёному (#00ff00).
Что попробовать дальше
Этот пример демонстрирует полный цикл работы с анимациями Aseprite в Phaser: от загрузки до интерактивного управления. Вы можете динамически переключать анимации и контролировать их скорость. Для экспериментов попробуйте раскомментировать закомментированные строки в обработчике клика, чтобы случайным образом задавать анимации фиксированный frameRate или скорость по умолчанию. Также можно изменить логику, чтобы скорость анимации зависела от состояния игрока (например, усталости или ускорения).
