О чем этот пример
При создании сложных игровых сцен часто возникает необходимость управлять группой объектов как единым целым: вращать их вместе, масштабировать или перемещать. Phaser предоставляет для этого мощный инструмент – `Container`. Эта статья покажет, как использовать контейнеры для группировки спрайтов и применения к ним комплексных анимаций, что значительно упрощает организацию игровой логики и визуальных эффектов.
Версия 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('rick', 'assets/sprites/rick.png');
}
create ()
{
// Our container
const container = this.add.container(400, 300);
// Create some sprites - positions are relative to the Container x/y
const sprite0 = this.add.sprite(-400, 0, 'rick');
const sprite1 = this.add.sprite(0, 0, 'rick');
const sprite2 = this.add.sprite(400, 0, 'rick');
const sprite3 = this.add.sprite(-200, -200, 'rick');
const sprite4 = this.add.sprite(200, -200, 'rick');
const sprite5 = this.add.sprite(200, 200, 'rick');
const sprite6 = this.add.sprite(-200, 200, 'rick');
container.add([ sprite0, sprite1, sprite2, sprite3, sprite4, sprite5, sprite6 ]);
this.tweens.add({
targets: container,
angle: { value: 360, duration: 6000 },
scaleX: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
scaleY: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
repeat: -1
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#662d91',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание и наполнение контейнера
Контейнер (Container) – это особый тип игрового объекта в Phaser, который сам не имеет графического представления, но может выступать в качестве родителя для других объектов. Все дочерние объекты наследуют трансформации (позицию, вращение, масштаб) контейнера.
Сначала создается сам контейнер с указанием его начальных мировых координат.
const container = this.add.container(400, 300);
Затем создаются спрайты. Важный нюанс: координаты спрайтов задаются не относительно мировых координат сцены, а относительно точки (`x,y`) самого контейнера.
const sprite1 = this.add.sprite(0, 0, 'rick');
const sprite2 = this.add.sprite(400, 0, 'rick');
Чтобы добавить спрайты в контейнер, используется метод add(). В него можно передать как массив объектов, так и отдельные аргументы.
container.add([ sprite0, sprite1, sprite2, sprite3, sprite4, sprite5, sprite6 ]);
Относительные координаты дочерних объектов
Ключевое преимущество контейнера – система координат. После добавления спрайта в контейнер его свойства `xиyстановятся относительными к позиции контейнера. Например, спрайт с координатами(0, 0)` будет отрисован прямо в центре контейнера.
В нашем примере спрайты размещаются по кругу и крестом относительно точки (400, 300) на сцене, потому что именно там создан контейнер. Если изменить позицию контейнера с помощью твина или прямого присваивания, все его дочерние спрайты синхронно сместятся вместе с ним, сохраняя свои относительные позиции внутри группы.
Это избавляет разработчика от необходимости вручную обновлять позиции каждого объекта в группе при их общем перемещении.
Применение анимации к контейнеру
Настоящая сила контейнеров раскрывается при работе с анимациями системы Tweens. Вместо того чтобы создавать твин для каждого спрайта в отдельности, можно создать один твин, нацеленный на контейнер.
В примере твин одновременно меняет три свойства контейнера: угол поворота и масштаб по обеим осям.
this.tweens.add({
targets: container,
angle: { value: 360, duration: 6000 },
scaleX: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
scaleY: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
repeat: -1
});
Параметр targets указывает, к какому объекту (нашему контейнеру) применяется анимация. Свойства angle, scaleX и scaleY анимируются с разной длительностью и эффектами. Например, yoyo: true заставляет анимацию масштаба проигрываться в обратном порядке после завершения, создавая эффект "пульсации". Все дочерние спрайты автоматически унаследуют эти трансформации, создавая синхронизированный визуальный эффект для всей группы.
Структура проекта и конфигурация
Пример представляет собой законченную сцену (Scene). В методе preload() загружается один спрайт.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('rick', 'assets/sprites/rick.png');
}
Основная логика находится в create(), где происходят все описанные операции: создание контейнера, спрайтов и анимации.
Конфигурация игры (config) стандартна: указывается тип рендерера, размеры холста, цвет фона и класс основной сцены.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#662d91',
parent: 'phaser-example',
scene: Example
};
Инициализация игры выполняется созданием экземпляра Phaser.Game с этой конфигурацией.
Что попробовать дальше
Контейнеры в Phaser – это фундаментальный инструмент для структурирования сложных игровых объектов. Они позволяют управлять группами спрайтов, текстов, частиц или других контейнеров как единым целым, что критически важно для создания иерархических сцен (например, персонаж с оружием в руке) и сложных анимаций.
**Идеи для экспериментов:**
1. Попробуйте вложить один контейнер в другой и применить анимации к родительскому контейнеру.
2. Добавьте в контейнер не только спрайты, но и текст (this.add.text) или графические примитивы (this.add.rectangle).
3. Используйте свойство setDepth контейнера, чтобы управлять порядком отрисовки всей группы объектов относительно других элементов сцены.
4. Поэкспериментируйте с изменением точки происхождения (originX, originY) контейнера и посмотрите, как это повлияет на вращение и масштабирование всей группы.
