О чем этот пример
В 2D-аркадах часто нужны не просто прямоугольные столкновения, а реалистичное взаимодействие круглых форм. Phaser Arcade Physics позволяет легко настраивать форму коллайдера, выходящую за границы текстуры. В этой статье разберем пример, где 80 шариков с разными траекториями отскакивают от центрального статичного шара. Это полезно для создания динамичных сцен с мячами, планетами, шаровыми пушками — везде, где важна точная круговая физика.
Версия 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.spritesheet('ball', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });
this.load.image('wizball', 'assets/sprites/wizball.png');
}
create ()
{
this.cameras.main.centerOn(0, 0);
const globe = this.physics.add.staticImage(0, 0, 'wizball')
.setCircle(45);
const balls = this.physics.add.group({
defaultKey: 'ball',
bounceX: 1,
bounceY: 1
});
balls.defaults.setVelocityX = 100;
balls.defaults.setVelocityY = 100;
let created;
created = balls.createMultiple({
quantity: 20,
key: balls.defaultKey,
frame: 0
});
Phaser.Actions.PlaceOnCircle(created, { x: -200, y: -200, radius: 50 });
balls.defaults.setVelocityX = -100;
balls.defaults.setVelocityY = 100;
created = balls.createMultiple({
quantity: 20,
key: balls.defaultKey,
frame: 1
});
Phaser.Actions.PlaceOnCircle(created, { x: 400, y: -400, radius: 50 });
balls.defaults.setVelocityX = -100;
balls.defaults.setVelocityY = -100;
created = balls.createMultiple({
quantity: 20,
key: balls.defaultKey,
frame: 2
});
Phaser.Actions.PlaceOnCircle(created, { x: 600, y: 600, radius: 50 });
balls.defaults.setVelocityX = 100;
balls.defaults.setVelocityY = -100;
created = balls.createMultiple({
quantity: 20,
key: balls.defaultKey,
frame: 3
});
Phaser.Actions.PlaceOnCircle(created, { x: -800, y: 800, radius: 50 });
for (const ball of balls.getChildren())
{
ball.setCircle(8);
}
this.physics.add.collider(globe, balls);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: { debug: false }
},
scene: Example
};
const game = new Phaser.Game(config);
Подготовка ассетов и создание статичного шара
В методе preload загружаем два спрайта: спрайтшит с четырьмя разными цветами шаров и отдельное изображение большого шара (wizball).
this.load.spritesheet('ball', 'assets/sprites/balls.png', { frameWidth: 17, frameHeight: 17 });
this.load.image('wizball', 'assets/sprites/wizball.png');
В create сначала центрируем камеру на точке (0,0). Затем создаем центральный статичный объект — шар globe. Ключевой метод setCircle(45) задает круглый коллайдер радиусом 45 пикселей, который будет использоваться для физических расчетов, вместо прямоугольника по умолчанию. Это важно, так как текстура wizball может быть квадратной, но физика должна быть круглой.
const globe = this.physics.add.staticImage(0, 0, 'wizball')
.setCircle(45);
Создание и настройка группы динамических шаров
Далее создаем физическую группу balls. В её конфигурации задаем спрайт по умолчанию (defaultKey), а также коэффициенты упругости (bounceX, bounceY) равные 1, что означает идеальный отскок без потери энергии.
const balls = this.physics.add.group({
defaultKey: 'ball',
bounceX: 1,
bounceY: 1
});
Свойство balls.defaults позволяет задавать параметры по умолчанию для всех новых объектов группы. В примере это используется для предустановки скорости по осям перед каждым созданием группы шаров.
balls.defaults.setVelocityX = 100;
balls.defaults.setVelocityY = 100;
Массовое создание шаров и их начальное размещение
Шары создаются порциями по 20 штук с помощью метода createMultiple. Для каждого блока задается начальная скорость через defaults и конкретный кадр (frame) из спрайтшита, чтобы шары в группе отличались по цвету.
created = balls.createMultiple({
quantity: 20,
key: balls.defaultKey,
frame: 0
});
Созданные объекты затем размещаются по кругу с помощью утилиты Phaser.Actions.PlaceOnCircle. Это задает начальную позицию для каждого шара в блоке, формируя из них кольцо.
Phaser.Actions.PlaceOnCircle(created, { x: -200, y: -200, radius: 50 });
Этот процесс повторяется четыре раза для разных стартовых позиций на сцене и с разными векторами начальной скорости, создавая разнонаправленное движение.
Настройка круглых коллайдеров для всех шаров
После создания всех 80 шаров необходимо пройтись по ним в цикле и также установить круглые коллайдеры. Размер текстуры шара — 17x17 пикселей, но физический радиус задается в 8 пикселей, что примерно соответствует визуальному размеру шара.
for (const ball of balls.getChildren())
{
ball.setCircle(8);
}
Без этого шага коллайдеры шаров остались бы прямоугольными (размером с текстуру), и столкновения с центральным шаром выглядели бы менее реалистично, происходя по углам спрайтов.
Регистрация коллайдера для обработки столкновений
Финальный и самый важный шаг — создать коллайдер между статичным объектом globe и группой динамических объектов balls. Метод this.physics.add.collider автоматически заставляет движок Arcade Physics проверять и разрешать столкновения между этими телами, учитывая их круглую форму, скорости и упругость.
this.physics.add.collider(globe, balls);
Именно этот вызов "включает" физику отскока. Без него шары просто пролетали бы сквозь центральный шар, несмотря на наличие коллайдеров.
Что попробовать дальше
Использование метода setCircle для настройки круглых коллайдеров — мощный и простой способ сделать физику в игре более точной и приятной глазу. Экспериментируйте: попробуйте изменить радиус коллайдера у центрального шара, чтобы шары отскакивали дальше или, наоборот, проваливались внутрь. Замените статичный объект на динамический и посмотрите, как он будет реагировать на удары. Также можно поиграть с параметрами bounce и velocity, чтобы создать эффекты гравитации, трения или хаотичного движения.
