О чем этот пример
В 2D-играх спрайты часто имеют прямоугольную область для расчёта столкновений, что может выглядеть неестественно для круглых объектов. Phaser Arcade Physics позволяет задавать для спрайтов коллайдер в форме круга, что делает взаимодействие объектов более точным и визуально приятным. В этой статье мы разберём пример, где несколько шариков летят к центральному объекту, используя именно круговые коллайдеры, и объясним ключевые методы для работы с физикой.
Версия 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 wizball = this.physics.add.staticImage(0, 0, 'wizball')
.setCircle(45);
const balls = this.physics.add.group({
bounceX: 1,
bounceY: 1
});
balls.createMultiple({
quantity: 6,
key: 'ball',
frame: [ 0, 1, 2, 3, 4 ]
});
Phaser.Actions.PlaceOnCircle(balls.getChildren(), { x: 0, y: 0, radius: 300 });
for (const ball of balls.getChildren())
{
ball.setCircle(8);
this.physics.moveToObject(ball, wizball, 100);
}
this.physics.add.collider(wizball, 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);
Подготовка сцены и загрузка ассетов
Вся логика примера содержится в классе сцены Example. Метод preload отвечает за загрузку графики.
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');
}
Здесь мы устанавливаем базовый URL для загрузки и загружаем два ресурса: спрайтшит balls.png, который содержит несколько кадров шариков, и одиночное изображение wizball.png. Обратите внимание на параметры frameWidth и frameHeight для спрайтшита — они необходимы, чтобы Phaser правильно его разрезал.
Создание статического и динамических тел
В методе create происходит инициализация физических объектов. Сначала камера центрируется на точке (0,0).
create ()
{
this.cameras.main.centerOn(0, 0);
const wizball = this.physics.add.staticImage(0, 0, 'wizball')
.setCircle(45);
}
Ключевой объект wizball создаётся как статическое физическое тело с помощью this.physics.add.staticImage. Статическое тело не двигается под воздействием сил или столкновений. Сразу после создания для него вызывается метод .setCircle(45). Это заменяет стандартный прямоугольный коллайдер (хитбокс) на круговой с радиусом 45 пикселей, центрированный относительно спрайта.
Далее создаётся группа (Group) динамических шариков.
const balls = this.physics.add.group({
bounceX: 1,
bounceY: 1
});
balls.createMultiple({
quantity: 6,
key: 'ball',
frame: [ 0, 1, 2, 3, 4 ]
});
Группа balls создаётся с помощью this.physics.add.group. Параметры bounceX: 1 и bounceY: 1 задают коэффициент упругости (1 означает абсолютно упругое отскок, без потери энергии). Метод createMultiple создаёт 6 спрайтов, используя загруженный спрайтшит ball. Параметр frame — это массив индексов кадров из спрайтшита, которые будут случайным образом назначены созданным шарикам, чтобы они визуально отличались.
Расстановка объектов и настройка движения
После создания шариков их нужно расположить на сцене и задать им движение.
Phaser.Actions.PlaceOnCircle(balls.getChildren(), { x: 0, y: 0, radius: 300 });
for (const ball of balls.getChildren())
{
ball.setCircle(8);
this.physics.moveToObject(ball, wizball, 100);
}
Phaser.Actions.PlaceOnCircle — это утилита для размещения массива объектов по окружности. Мы передаём ей массив детей группы balls и конфигурацию окружности с центром в (0,0) и радиусом 300 пикселей. В результате все шарики равномерно распределяются по этому кругу.
Затем в цикле для каждого шарика выполняются две важные операции:
1. ball.setCircle(8) — так же, как и для wizball, заменяет хиктбокс шарика на круглый коллайдер с радиусом 8 пикселей.
2. this.physics.moveToObject(ball, wizball, 100) — функция, которая задаёт шарику скорость, направленную к целевому объекту (wizball). Третий аргумент (100) — это величина скорости в пикселях в секунду.
Завершение настройки: добавление коллайдера
Финальный штрих — регистрация столкновения между центральным шаром и группой шариков.
this.physics.add.collider(wizball, balls);
}
Метод this.physics.add.collider создаёт коллайдер, который будет обрабатывать столкновения между двумя объектами (или объектом и группой). Благодаря тому, что для всех объектов заданы круговые коллайдеры (setCircle), столкновения будут рассчитываться именно по кругу, а не по прямоугольнику, что обеспечивает реалистичное и точное физическое взаимодействие.
Конфигурация игры
Весь пример завершается стандартной конфигурацией игры Phaser.
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);
В конфиге указаны размеры canvas, родительский HTML-элемент и самое важное — активация физического движка Arcade с отключённым режимом отладки (debug: false). Если установить debug: true, на сцене будут отрисованы контуры коллайдеров, что очень полезно при разработке.
Что попробовать дальше
Использование метода setCircle для задания круговых коллайдеров — простой и эффективный способ значительно улучшить физику взаимодействия круглых объектов в Phaser. Это делает столкновения более предсказуемыми и естественными для игрока. Для экспериментов попробуйте изменить радиусы коллайдеров, скорость шариков, их количество или замените moveToObject на setVelocity для создания орбитального движения вокруг центрального шара.
