О чем этот пример
При создании сложных игровых сцен часто возникает необходимость управлять группой объектов как единым целым — например, вращать или перемещать несколько спрайтов одновременно. В Phaser для этой задачи идеально подходит `Container`. В этой статье мы разберем, как создавать контейнеры, добавлять в них объекты и независимо управлять камерой с помощью плавного зума и панорамирования. Этот подход полезен для создания сложных игровых элементов вроде юнитов, интерфейсов или анимированных фонов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
controls;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('lemming', 'assets/sprites/lemming.png');
}
create ()
{
this.cameras.main.zoom = 0.5;
// Our container
const container = this.add.container(400, 300);
// Add some sprites - positions are relative to the Container x/y
const sprite0 = this.add.sprite(0, 0, 'lemming');
const sprite1 = this.add.sprite(-100, -100, 'lemming');
const sprite2 = this.add.sprite(100, -100, 'lemming');
const sprite3 = this.add.sprite(100, 100, 'lemming');
const sprite4 = this.add.sprite(-100, 100, 'lemming');
container.add(sprite0);
container.add(sprite1);
container.add(sprite2);
container.add(sprite3);
container.add(sprite4);
// You could also pass them in as an array, to save doing them one by one
this.tweens.add({
targets: container,
angle: 360,
duration: 6000,
yoyo: true,
repeat: -1
});
const cursors = this.input.keyboard.createCursorKeys();
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
up: cursors.up,
down: cursors.down,
zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
acceleration: 0.06,
drag: 0.0005,
maxSpeed: 1.0
};
this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
const cam = this.cameras.main;
const gui = new dat.GUI();
const help = {
line1: 'Cursors to move',
line2: 'Q & E to zoom'
};
const f1 = gui.addFolder('Camera');
f1.add(cam, 'x').listen();
f1.add(cam, 'y').listen();
f1.add(cam, 'scrollX').listen();
f1.add(cam, 'scrollY').listen();
f1.add(cam, 'rotation').min(0).step(0.01).listen();
f1.add(cam, 'zoom', 0.1, 2).step(0.1).listen();
f1.add(help, 'line1');
f1.add(help, 'line2');
f1.open();
}
update (time, delta)
{
this.controls.update(delta);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#010101',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание контейнера и добавление объектов
Контейнер (Container) — это специальный игровой объект, который выступает родителем для других объектов. Все дочерние объекты наследуют трансформации контейнера: его позицию, вращение и масштаб. Это позволяет управлять группой объектов, как одним целым.
В методе create() мы создаем контейнер в центре сцены. Затем создаем пять спрайтов лемминга. Обратите внимание: координаты спрайтов задаются относительно позиции контейнера. Например, спрайт с координатами (-100, -100) будет расположен на 100 пикселей левее и выше центра контейнера.
const container = this.add.container(400, 300);
const sprite0 = this.add.sprite(0, 0, 'lemming');
const sprite1 = this.add.sprite(-100, -100, 'lemming');
const sprite2 = this.add.sprite(100, -100, 'lemming');
const sprite3 = this.add.sprite(100, 100, 'lemming');
const sprite4 = this.add.sprite(-100, 100, 'lemming');
container.add(sprite0);
container.add(sprite1);
container.add(sprite2);
container.add(sprite3);
container.add(sprite4);
Анимация контейнера с помощью Tween
Чтобы оживить сцену, мы применяем анимацию (Tween) к самому контейнеру. Анимация вращает контейнер на 360 градусов, затем возвращает его обратно и повторяет бесконечно. Поскольку спрайты являются дочерними объектами, они вращаются вместе с контейнером, сохраняя свои относительные позиции.
Ключевые параметры твина:
- targets: объект для анимации (наш контейнер).
- angle: целевой угол вращения.
- duration: длительность анимации в миллисекундах.
- yoyo: если true, анимация проигрывается в обратном порядке после завершения.
- repeat: количество повторений (-1 для бесконечного повторения).
this.tweens.add({
targets: container,
angle: 360,
duration: 6000,
yoyo: true,
repeat: -1
});
Плавное управление камерой
Для интерактивного управления камерой в примере используется Phaser.Cameras.Controls.SmoothedKeyControl. Этот контроллер обеспечивает плавное движение и зум камеры с инерцией, что делает управление более приятным.
Конфигурация контроллера связывает клавиши стрелок для перемещения и клавиши Q/E для зума. Параметры acceleration, drag и maxSpeed настраивают физику движения: ускорение, замедление и максимальную скорость.
Важно: метод update контроллера должен вызываться каждый кадр в основном цикле игры, чтобы обрабатывать ввод и обновлять позицию камеры.
const cursors = this.input.keyboard.createCursorKeys();
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
up: cursors.up,
down: cursors.down,
zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
acceleration: 0.06,
drag: 0.0005,
maxSpeed: 1.0
};
this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
update (time, delta)
{
this.controls.update(delta);
}
Настройка камеры и отладка с dat.GUI
В примере камера сразу уменьшает масштаб в два раза (zoom = 0.5), чтобы мы могли видеть больше игрового пространства. Для отладки и наглядности используется библиотека dat.GUI, которая создает панель управления в реальном времени.
На панели отображаются и изменяются ключевые свойства камеры: её мировые координаты (`x,y), смещение (scrollX,scrollY), вращение и зум. Метод.listen()` заставляет значения автоматически обновляться в интерфейсе при их изменении в коде.
this.cameras.main.zoom = 0.5;
const cam = this.cameras.main;
const gui = new dat.GUI();
const f1 = gui.addFolder('Camera');
f1.add(cam, 'x').listen();
f1.add(cam, 'y').listen();
f1.add(cam, 'scrollX').listen();
f1.add(cam, 'scrollY').listen();
f1.add(cam, 'rotation').min(0).step(0.01).listen();
f1.add(cam, 'zoom', 0.1, 2).step(0.1).listen();
Что попробовать дальше
Контейнеры в Phaser — это мощный инструмент для группировки объектов и применения к ним общих трансформаций. В сочетании с плавным управлением камерой они позволяют создавать сложные и динамичные сцены. Для экспериментов попробуйте: добавить в контейнер другие типы объектов (текст, графику), изменить параметры инерции камеры для другого 'феeling' управления или анимировать не только вращение, но и масштаб контейнера.
