О чем этот пример
При работе с физикой в Phaser 3 по умолчанию коллайдер объекта соответствует границам его текстуры (прямоугольнику). Это может привести к неточным и неожиданным столкновениям, особенно для круглых спрайтов. В этой статье мы разберем, как использовать метод `setCircle()` для создания точного кругового коллайдера, который сделает взаимодействие объектов физически достоверным. Это особенно полезно в играх с шарами, мячами, планетами или любыми другими круглыми объектами, где важна точность отскока и столкновений. Мы рассмотрим пример с двумя шарами, движущимися под действием гравитации и реалистично сталкивающимися друг с другом.
Версия 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('wizball', 'assets/sprites/wizball.png');
}
create ()
{
const ball1 = this.physics.add.image(100, 240, 'wizball');
const ball2 = this.physics.add.image(700, 240, 'wizball');
ball1.setCircle(46);
ball2.setCircle(46);
ball1.setCollideWorldBounds(true);
ball2.setCollideWorldBounds(true);
ball1.setBounce(1);
ball2.setBounce(1);
ball1.setVelocity(150);
ball2.setVelocity(-200, 60);
this.physics.add.collider(ball1, ball2);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
debug: true,
gravity: { y: 100 }
}
},
scene: Example
};
const game = new Phaser.Game(config);
Проблема прямоугольного коллайдера
По умолчанию Arcade Physics в Phaser 3 присваивает каждому физическому телу коллайдер в форме прямоугольника (AABB - Axis-Aligned Bounding Box), который соответствует размерам текстуры спрайта. Для квадратных объектов это работает отлично, но для круглых спрайтов это создает проблемы.
Представьте круглый мяч внутри квадратной текстуры. Физический движок будет обрабатывать столкновения так, как будто объект квадратный. Это приводит к нереалистичным отскокам, когда мяч может "зацепиться" углом невидимого прямоугольника, или к преждевременным столкновениям.
// Без setCircle() коллайдер будет таким же широким и высоким, как изображение 'wizball'.
const ball = this.physics.add.image(100, 240, 'wizball');
Решение: метод setCircle()
Метод setCircle() позволяет переопределить форму коллайдера тела, сделав его идеальным кругом с заданным радиусом. Это основной инструмент для точной настройки физики круглых объектов.
Метод принимает один обязательный аргумент - радиус круга в пикселях. Центр этого круга автоматически помещается в геометрический центр спрайта. Важно правильно подобрать радиус, чтобы он соответствовал видимой части круглого спрайта, игнорируя прозрачные края текстуры.
// Создаем физическое тело из изображения
const ball1 = this.physics.add.image(100, 240, 'wizball');
// Заменяем прямоугольный коллайдер на круговой с радиусом 46 пикселей
ball1.setCircle(46);
Настройка свойств физического тела
После создания кругового коллайдера нужно настроить дополнительные физические свойства тела, чтобы добиться желаемого поведения. В примере мы настраиваем отскок от границ мира и других объектов, а также задаем начальную скорость.
Метод setCollideWorldBounds(true) заставляет тело отскакивать от границ игрового мира. Метод setBounce(1) устанавливает коэффициент упругости (реституции) в 1, что означает идеально упругий отскок без потерь энергии. Значение 1 — это максимум, при котором скорость при отскоке сохраняется по модулю.
ball1.setCollideWorldBounds(true);
ball2.setCollideWorldBounds(true);
ball1.setBounce(1);
ball2.setBounce(1);
ball1.setVelocity(150); // Скорость только по оси X (150 пикселей в секунду)
ball2.setVelocity(-200, 60); // Скорость по X: -200, по Y: 60
Оркестровка столкновений
Чтобы тела действительно взаимодействовали друг с другом, необходимо явно добавить коллайдер между ними. Фабричный метод this.physics.add.collider() создает и возвращает объект Collider, который отслеживает столкновения между двумя телами или группами тел.
При столкновении Arcade Physics автоматически рассчитает и применит ответные силы, основываясь на скорости, массе (в данном примере массы равны по умолчанию) и упругости тел. Поскольку мы установили debug: true в конфигурации физики, на сцене будут отрисованы зеленые контуры круговых коллайдеров, что помогает в отладке.
// Регистрируем столкновение между ball1 и ball2
this.physics.add.collider(ball1, ball2);
Конфигурация игры и физики
Ключевой момент для работы физики — правильная настройка конфигурационного объекта игры. Необходимо указать default: 'arcade' и при необходимости задать параметры гравитации и отладки внутри объекта arcade.
Гравитация (gravity: { y: 100 }) постоянно применяет ускорение к телам по оси Y, имитируя силу притяжения. Включенный режим отладки (debug: true) визуализирует коллайдеры и скорость тел, что невероятно полезно при разработке и балансировке физики.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: { // Включаем систему физики
default: 'arcade', // Используем Arcade Physics
arcade: {
debug: true, // Визуализация коллайдеров
gravity: { y: 100 } // Гравитация, направленная вниз
}
},
scene: Example // Указываем наш класс сцены
};
Что попробовать дальше
Использование setCircle() — это простой и эффективный способ сделать физику круглых объектов в Phaser 3 точной и реалистичной. Он устраняет артефакты столкновений, связанные с прямоугольными коллайдерами по умолчанию.
**Идеи для экспериментов:**
1. Измените радиус в setCircle() на большее или меньшее значение и понаблюдайте за изменением "хитбокса".
2. Поиграйте с коэффициентом setBounce() (например, 0.5 или 0) для создания менее упругих, "тяжелых" шаров.
3. Добавьте третье тело с помощью setCircle() и организуйте столкновения между всеми тремя, используя this.physics.add.collider(ball1, ball2, ball3).
4. Отключите гравитацию в конфиге (gravity: { y: 0 }) и создайте симуляцию бильярдного шара или воздушного хоккея.
