О чем этот пример
При создании игр с множеством однотипных объектов, например, шаров или ящиков, управлять их взаимодействием поодиночке неэффективно. Phaser предоставляет мощный инструмент — физические группы (Physics Group). Эта статья покажет, как быстро создать группу из множества объектов с физикой и настроить их столкновения друг с другом, используя метод `this.physics.add.collider`. Мы разберем два подхода: стандартное столкновение и столкновение с пользовательской функцией обратного вызова, которая позволяет реагировать на каждый факт соударения.
Версия 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('ball', 'assets/sprites/shinyball.png');
}
create ()
{
const crates = this.physics.add.group({
key: 'ball',
quantity: 24,
bounceX: 1,
bounceY: 1,
collideWorldBounds: true,
velocityX: 300,
velocityY: 150
});
Phaser.Actions.RandomRectangle(crates.getChildren(), this.physics.world.bounds);
this.physics.add.collider(crates);
// OR
// this.physics.add.collider(
// crates,
// undefined,
// function (crate1, crate2)
// {
// crate1.setAlpha(0.5);
// crate2.setAlpha(0.5);
// }
// );
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade',
arcade: {
debug: false,
gravity: { y: 300 }
}
},
scene: Example
};
const game = new Phaser.Game(config);
Создание физической группы
Вместо ручного создания и настройки каждого спрайта с физикой, Phaser позволяет использовать группы. Метод this.physics.add.group создает и возвращает PhysicsGroup — особый тип группы, все дочерние элементы которой уже являются физическими телами Arcade.
Ключевые параметры конфигурационного объекта:
- key: текстура для всех создаваемых спрайтов.
- quantity: количество объектов в группе.
- bounceX, bounceY: коэффициенты упругости (от 0 до 1).
- collideWorldBounds: флаг, разрешающий столкновения с границами мира.
- velocityX, velocityY: начальная скорость для всех объектов.
const crates = this.physics.add.group({
key: 'ball',
quantity: 24,
bounceX: 1,
bounceY: 1,
collideWorldBounds: true,
velocityX: 300,
velocityY: 150
});
Сразу после создания все 24 шара ('ball') уже имеют тела Arcade Physics с заданной упругостью, скоростью и будут отскакивать от границ игрового мира.
Распределение объектов и простой коллайдер
После создания группы объекты находятся в одной точке. Их нужно распределить по игровой области. Для этого удобно использовать Phaser.Actions.RandomRectangle, которая случайным образом размещает массив объектов внутри заданного прямоугольника.
Phaser.Actions.RandomRectangle(crates.getChildren(), this.physics.world.bounds);
Теперь, чтобы объекты группы сталкивались друг с другом, используется метод this.physics.add.collider. Самый простой способ — передать одну и ту же группу в оба аргумента. Это создаст коллайдер для парного столкновения всех тел внутри этой группы.
this.physics.add.collider(crates);
В этом случае метод автоматически подставляет группу и в первый (объект A), и во второй (объект B) параметры, что эквивалентно this.physics.add.collider(crates, crates). Теперь все шары будут реалистично отскакивать друг от друга.
Коллайдер с пользовательским callback
Часто при столкновении нужно выполнить дополнительную логику: проиграть звук, изменить внешний вид объектов, нанести урон. Для этого this.physics.add.collider принимает третий аргумент — функцию обратного вызова (callback).
В примере ниже callback-функция делает оба столкнувшихся шара полупрозрачными. Важно: функция вызывается для каждой пары столкнувшихся тел.
this.physics.add.collider(
crates,
undefined,
function (crate1, crate2)
{
crate1.setAlpha(0.5);
crate2.setAlpha(0.5);
}
);
Здесь есть важный нюанс. Мы передаем группу crates как первый объект для столкновений, а вторым аргументом указываем undefined. Это означает: "Проверять столкновения объектов из группы crates... ни с чем другим?" На самом деле, когда второй аргумент не указан (или undefined), система по умолчанию подставляет ту же самую группу, что и в первом аргументе. Таким образом, эта запись также настраивает столкновения внутри группы, но уже с кастомной логикой при каждом соударении.
Настройка сцены и физики
Весь описанный функционал работает благодаря правильной конфигурации игры. Ключевой момент — активация Arcade Physics в настройках игры.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
physics: {
default: 'arcade', // Включаем Arcade Physics
arcade: {
debug: false, // Отключаем отладочную визуалицию тел
gravity: { y: 300 } // Задаем силу тяжести, направленную вниз
}
},
scene: Example // Указываем наш класс сцены
};
Именно параметр default: 'arcade' дает нам доступ к объекту this.physics внутри сцены и ко всем его методам, таким как add.group и add.collider. Гравитация, заданная здесь, будет влиять на все физические тела в сцене, включая наши шары.
Что попробовать дальше
Использование PhysicsGroup в связке с this.physics.add.collider — это основа для создания эффективных симуляций множества взаимодействующих объектов. Для экспериментов попробуйте:
1. Изменить параметры группы: bounceY на 0, чтобы шары не отскакивали от пола, или dragX для создания эффекта трения.
2. В callback-функции коллайдера изменить не alpha, а, например, setTint для окрашивания сталкивающихся шаров.
3. Создать две разные группы (например, balls и boxes) и настроить коллайдер между ними с уникальной логикой взаимодействия.
