Анимации по ключам атласа

В 2D-играх спрайтовая анимация традиционно строится на последовательной смене кадров. В библиотеке Phaser одним из наиболее эффективных способов организации кадров является использование атласа текстур (Texture Atlas). Атлас объединяет множество изображений в один графический файл и сопровождается JSON-описанием, содержащим координаты, размеры и ключи каждого кадра.

Использование атласа решает сразу несколько задач:

  • уменьшение количества HTTP-запросов;
  • оптимизация работы GPU;
  • централизованное управление кадрами;
  • удобная генерация анимаций по ключам.

В контексте Phaser анимации могут создаваться не только по нумерованной последовательности (run_01, run_02, …), но и по ключам атласа, что особенно важно при работе с инструментами упаковки текстур (TexturePacker, Aseprite, CodeAndWeb и др.).


Загрузка атласа

Перед созданием анимации необходимо загрузить атлас в сцене. Phaser поддерживает несколько форматов:

  • atlas — JSON в формате TexturePacker;
  • atlasJSONHash — JSON с объектной структурой кадров;
  • atlasXML — XML-описание.

Пример загрузки JSON-атласа:

preload() {
    this.load.atlas('player', 'assets/player.png', 'assets/player.json');
}

Параметры:

  • 'player' — ключ текстуры;
  • путь к изображению;
  • путь к JSON-описанию.

После загрузки каждый кадр становится доступным по имени, указанному в JSON.


Структура кадров в атласе

Типичный JSON-файл атласа содержит объект frames, внутри которого находятся записи вида:

{
  "run_01": { ... },
  "run_02": { ... },
  "jump": { ... }
}

Ключ "run_01" — это идентификатор кадра, который используется при создании анимации. Phaser не требует строгой нумерации; допустимы произвольные строки.

Это открывает возможность формировать анимации:

  • по шаблону имени;
  • по списку ключей;
  • автоматически, если соблюдается числовой диапазон.

Создание анимации по ключам атласа

1. Использование generateFrameNames

Если кадры имеют последовательные имена (run_01, run_02, run_03), применяется генератор:

this.anims.create({
    key: 'run',
    frames: this.anims.generateFrameNames('player', {
        prefix: 'run_',
        start: 1,
        end: 6,
        zeroPad: 2
    }),
    frameRate: 12,
    repeat: -1
});

Ключевые параметры:

  • prefix — строка перед номером;
  • start, end — диапазон;
  • zeroPad — количество ведущих нулей;
  • 'player' — ключ загруженного атласа.

Phaser автоматически сформирует массив:

run_01
run_02
run_03
...

2. Использование generateFrameNames с массивом

Если имена не образуют строгий диапазон:

this.anims.create({
    key: 'jump',
    frames: this.anims.generateFrameNames('player', {
        frames: ['jump_start', 'jump_air', 'jump_end']
    }),
    frameRate: 10,
    repeat: 0
});

В данном случае список кадров задаётся вручную.


3. Прямое указание массива кадров

Анимацию можно сформировать без генератора:

this.anims.create({
    key: 'attack',
    frames: [
        { key: 'player', frame: 'attack_1' },
        { key: 'player', frame: 'attack_2' },
        { key: 'player', frame: 'attack_3' }
    ],
    frameRate: 8,
    repeat: 0
});

Такой способ удобен при смешении кадров из разных атласов или при нестандартной последовательности.


Параметры анимации

Объект конфигурации anims.create содержит важные свойства:

Свойство Назначение
key Уникальный идентификатор анимации
frames Массив кадров
frameRate Количество кадров в секунду
duration Общая длительность (альтернатива frameRate)
repeat Повтор (-1 — бесконечно)
yoyo Воспроизведение в обратном направлении
delay Задержка перед стартом
repeatDelay Пауза между повторами

При указании duration Phaser вычисляет frameRate автоматически.


Глобальные и локальные анимации

В Phaser анимации по умолчанию создаются глобально через this.anims.create(). Они доступны всем объектам сцен.

Однако существует возможность создания локальной анимации непосредственно у спрайта:

sprite.anims.create({
    key: 'blink',
    frames: ...
});

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


Воспроизведение анимации

После создания анимации она запускается следующим образом:

sprite.play('run');

Дополнительные варианты:

sprite.play('run', true);   // игнорировать повторный вызов
sprite.anims.stop();
sprite.anims.pause();
sprite.anims.resume();

Phaser автоматически переключает текстуру спрайта в соответствии с текущим кадром атласа.


Работа с событиями анимации

Система анимаций поддерживает события:

  • animationstart
  • animationupdate
  • animationrepeat
  • animationcomplete

Пример обработки:

sprite.on('animationcomplete', function (animation, frame) {
    if (animation.key === 'attack') {
        sprite.play('idle');
    }
});

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


Оптимизация и организация кадров

Именование

Рекомендуется придерживаться схемы:

action_direction_XX

Например:

run_left_01
run_left_02
run_right_01

Это позволяет формировать анимации динамически:

createRunAnimation(direction) {
    this.anims.create({
        key: `run_${direction}`,
        frames: this.anims.generateFrameNames('player', {
            prefix: `run_${direction}_`,
            start: 1,
            end: 6,
            zeroPad: 2
        }),
        frameRate: 12,
        repeat: -1
    });
}

Минимизация количества анимаций

Не рекомендуется создавать анимации повторно при каждом входе в сцену. Перед созданием полезно проверять наличие:

if (!this.anims.exists('run')) {
    this.anims.create({...});
}

Это предотвращает утечки памяти и дублирование данных.


Использование разных атласов

При разделении персонажей по атласам:

this.load.atlas('enemy', 'enemy.png', 'enemy.json');

Создание анимации:

this.anims.create({
    key: 'enemy_walk',
    frames: this.anims.generateFrameNames('enemy', {
        prefix: 'walk_',
        start: 1,
        end: 4
    }),
    frameRate: 6,
    repeat: -1
});

Каждый атлас имеет собственный набор ключей кадров.


Особенности pivot и trimmed кадров

Инструменты упаковки часто:

  • обрезают прозрачные области (trim);
  • сохраняют pivot-точку;
  • добавляют scale-данные.

Phaser корректно учитывает эти параметры, если они присутствуют в JSON. Это особенно важно для анимаций с вращением и физикой.


Динамическое создание анимаций

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

Пример динамического списка:

const frameNames = texture.getFrameNames()
    .filter(name => name.startsWith('effect_'));

this.anims.create({
    key: 'effect',
    frames: frameNames.map(name => ({
        key: 'effectsAtlas',
        frame: name
    })),
    frameRate: 15,
    repeat: 0
});

Метод getFrameNames() позволяет анализировать содержимое атласа.


Сравнение: отдельные изображения vs атлас

Подход Преимущества Недостатки
Отдельные PNG Простота Много запросов
Атлас Производительность, компактность Требуется сборка

В реальных проектах атласы практически обязательны.


Комбинирование анимаций и состояний

Типичная архитектура:

  • idle
  • run
  • jump
  • attack
  • death

Переходы управляются через конечный автомат состояний (FSM). Анимации по ключам атласа позволяют гибко переключать визуальные состояния без смены текстуры.


Глубинная настройка кадров

Каждый кадр может иметь собственную длительность:

frames: [
    { key: 'player', frame: 'attack_1', duration: 100 },
    { key: 'player', frame: 'attack_2', duration: 50 },
    { key: 'player', frame: 'attack_3', duration: 200 }
]

Это позволяет:

  • выделять ударные моменты;
  • замедлять финальный кадр;
  • создавать эффект “anticipation”.

Управление временем анимации

Phaser использует внутренний таймер сцены. Скорость можно изменять глобально:

this.anims.globalTimeScale = 0.5;

Или локально:

sprite.anims.timeScale = 2;

Это полезно для эффектов замедления времени (slow motion).


Кэширование и удаление анимаций

Удаление анимации:

this.anims.remove('run');

Полная очистка:

this.anims.clear();

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


Практическая архитектура проекта

Оптимальный подход:

  • Загрузка всех атласов в Preload-сцене.
  • Создание глобальных анимаций в Create-методе основной сцены.
  • Управление воспроизведением через контроллер персонажа.
  • Использование соглашения об именовании для автоматической генерации.

Анимации по ключам атласа являются центральным элементом построения производительных 2D-игр на Phaser, обеспечивая масштабируемость, управляемость и высокую эффективность отрисовки.