О чем этот пример
В 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('buttonBG', 'assets/sprites/button-bg.png');
this.load.image('buttonText', 'assets/sprites/button-text.png');
}
create ()
{
const bg = this.add.image(0, 0, 'buttonBG').setInteractive();
const text = this.add.image(0, 0, 'buttonText');
const container = this.add.container(0, 0, [ bg, text ]);
container.setAngle(20);
const container2 = this.add.container(400, 300, container);
container2.setScale(1.5);
this.tweens.add({
targets: text,
alpha: 0.5,
duration: 1000,
ease: 'Sine.easeOut',
yoyo: true,
repeat: -1
});
bg.on('pointerover', function ()
{
this.setTint(0x44ff44);
});
bg.on('pointerout', function ()
{
this.clearTint();
});
bg.once('pointerup', function ()
{
this.tweens.add({
targets: container,
y: 900,
duration: 500
});
}, this);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#010101',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание и вложение контейнеров
В примере создается кнопка из двух изображений (фон и текст) и помещается в контейнер. Затем этот контейнер становится дочерним элементом второго контейнера. Это демонстрирует иерархическую структуру.
const bg = this.add.image(0, 0, 'buttonBG').setInteractive();
const text = this.add.image(0, 0, 'buttonText');
const container = this.add.container(0, 0, [ bg, text ]);
container.setAngle(20);
const container2 = this.add.container(400, 300, container);
container2.setScale(1.5);
Здесь bg и text добавляются в container. Важно: координаты (0,0) изображений заданы относительно родительского контейнера. Далее container поворачивается на 20 градусов с помощью setAngle. Затем container передается в container2 — теперь он становится дочерним объектом. При масштабировании container2 в 1.5 раза (setScale(1.5)) все его дочерние элементы (включая container и его содержимое) также увеличатся. Позиция container2 задана как (400, 300), что определяет его точку привязки на сцене.
Анимация объектов внутри контейнера
Phaser позволяет анимировать свойства любого игрового объекта, даже если он находится внутри контейнера. В примере используется твин для создания эффекта пульсации текста кнопки.
this.tweens.add({
targets: text,
alpha: 0.5,
duration: 1000,
ease: 'Sine.easeOut',
yoyo: true,
repeat: -1
});
Твин применяется непосредственно к объекту text. Параметр targets указывает, что анимируется именно спрайт текста. Свойство alpha меняет прозрачность от начального значения до 0.5 за 1000 миллисекунд. Опции yoyo: true и repeat: -1 заставляют анимацию играть вперед-назад бесконечно. Ключевой момент: анимация работает независимо от иерархии контейнеров, потому что text остается доступным объектом в сцене.
Обработка событий интерактивного фона
Объект bg (фон кнопки) сделан интерактивным с помощью setInteractive(). Это позволяет отслеживать события мыши или касания. Обработчики событий привязаны непосредственно к bg, а не к контейнеру.
bg.on('pointerover', function () {
this.setTint(0x44ff44);
});
bg.on('pointerout', function () {
this.clearTint();
});
При наведении курсора (pointerover) фон окрашивается в зеленый оттенок с помощью setTint. При уходе курсора (pointerout) окраска сбрасывается clearTint. Здесь this внутри функций-обработчиков ссылается на сам объект bg, так как используется обычное объявление функции. Это важно для доступа к методам спрайта.
Однократное событие и анимация контейнера
Пример также показывает, как использовать событие pointerup (клик или касание) для запуска анимации всего контейнера. Событие сработает только один раз благодаря методу once.
bg.once('pointerup', function () {
this.tweens.add({
targets: container,
y: 900,
duration: 500
});
}, this);
При клике на bg создается твин, который перемещает container по оси Y до позиции 900. Обрати внимание на третий аргумент this в bg.once. Он задает контекст выполнения для функции-обработчика. Внутри обработчика this теперь ссылается на экземпляр сцены (Example), что позволяет вызвать this.tweens.add. Без этого аргумента this указывал бы на bg, у которого нет метода tweens.
Что попробовать дальше
Контейнеры в Phaser упрощают управление группами объектов, особенно когда нужны сложные преобразования (поворот, масштаб). Вложенность контейнеров позволяет строить многоуровневые иерархии. При этом события обрабатываются на уровне интерактивных объектов внутри контейнеров, а анимации можно применять как к отдельным объектам, так и ко всей группе. Для экспериментов попробуйте: изменить порядок вложения контейнеров, добавить физику к контейнеру, или привязать события не к bg, а к самому контейнеру, предварительно сделав его интерактивным.
