О чем этот пример
Работа с множеством игровых объектов как с единым целым — частая задача в разработке игр. Phaser предлагает мощный инструмент — `Container`, который позволяет группировать спрайты, тексты и другие объекты. Однако, чтобы применить физику Arcade ко всей такой группе, нужно знать одну важную деталь. Эта статья покажет, как превратить статичный контейнер в динамичное физическое тело, которое отскакивает от границ мира и вращается при движении, используя всего несколько строк кода.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
container;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('mushroom', 'assets/sprites/mushroom2.png');
}
create ()
{
const image1 = this.add.image(0, -30, 'mushroom');
const image2 = this.add.image(-40, 30, 'mushroom');
const image3 = this.add.image(40, 30, 'mushroom');
this.container = this.add.container(400, 200, [ image1, image2, image3 ]);
// A Container has a default size of 0x0, so we need to give it a size before enabling a physics
// body or it'll be given the default body size of 64x64.
this.container.setSize(128, 64);
this.physics.world.enable(this.container);
this.container.body.setVelocity(100, 200).setBounce(1, 1).setCollideWorldBounds(true);
}
update ()
{
if (this.container.body.velocity.x < 0)
{
this.container.rotation -= 0.02;
}
else
{
this.container.rotation += 0.02;
}
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#010101',
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 200 },
debug: true
}
},
scene: Example
};
const game = new Phaser.Game(config);
Что такое Container и зачем ему физика?
Container в Phaser — это специальный игровой объект, который может содержать в себе список других объектов (дочерних элементов). Он управляет их видимостью, положением, масштабом и вращением как единой группой. Это удобно для создания сложных составных объектов, например, танка (корпус + башня) или персонажа из нескольких частей.
По умолчанию контейнер не имеет физического тела. Чтобы он мог взаимодействовать с миром через Arcade Physics (иметь скорость, ускорение, сталкиваться), тело нужно создать и настроить. Это открывает возможности для создания динамичных групповых объектов, управляемых физикой.
Ключевой шаг: задание размера контейнера
Самая важная и часто упускаемая деталь — перед включением физики для контейнера необходимо явно задать его размер. Без этого тело получит размер по умолчанию (64x64 пикселя), что может не соответствовать реальным границам вашей группы спрайтов.
В нашем примере три гриба расположены так, что общая занимаемая область примерно 128x64 пикселя. Мы явно указываем этот размер.
// Контейнер имеет размер 0x0 по умолчанию.
// Мы задаем размер вручную перед включением физики.
this.container.setSize(128, 64);
Только после этого мы активируем физическое тело для контейнера с помощью this.physics.world.enable().
Создание и настройка физического тела
После задания размера мы включаем физику Arcade для объекта контейнера. Метод enable создает и присоединяет к контейнеру тело типа Arcade Physics Body.
Затем мы настраиваем это тело, как и любое другое: задаем начальную скорость, упругость (отскок) и включаем столкновение с границами игрового мира.
// Включаем физику Arcade для контейнера
this.physics.world.enable(this.container);
// Настраиваем свойства тела контейнера
this.container.body.setVelocity(100, 200).setBounce(1, 1).setCollideWorldBounds(true);
Теперь контейнер, как единый объект, будет летать по сцене, отскакивать от стен (setBounce(1,1) означает 100% упругость по обеим осям) и оставаться в пределах холста.
Связываем физику с визуалом: вращение в update()
Физическое тело управляет положением и скоростью контейнера. Мы можем использовать эти данные, чтобы влиять на его визуальные свойства. В методе update(), который вызывается каждый кадр, мы проверяем горизонтальную скорость тела.
В зависимости от направления скорости по оси X, мы медленно вращаем весь контейнер (а вместе с ним и все дочерние грибы) в ту или иную сторону. Это создает простой, но эффектный визуальный отклик на движение.
update ()
{
if (this.container.body.velocity.x < 0)
{
// Если движемся влево, вращаем против часовой стрелки
this.container.rotation -= 0.02;
}
else
{
// Если движемся вправо или стоит, вращаем по часовой стрелке
this.container.rotation += 0.02;
}
}
Обратите внимание: мы меняем свойство rotation самого контейнера (this.container), а не его физического тела.
Что попробовать дальше
Использование Container в связке с Arcade Physics позволяет легко создавать сложные составные объекты, которые ведут себя в мире как единое целое. Главное правило — не забывать задавать корректный размер контейнера с помощью setSize() перед включением физики.
Для экспериментов попробуйте:
1. Добавить в контейнер больше спрайтов разных размеров и подобрать новый размер для setSize().
2. Заставить контейнер реагировать на клики или ввод с клавиатуры, применяя силу (setAcceleration) или импульс (setVelocity) к this.container.body.
3. Реализовать столкновение контейнера с другими физическими телами на сцене с помощью this.physics.add.collider().
