О чем этот пример

Движок физики Arcade в Phaser 3 предлагает простой и мощный способ реализовать столкновения между игровыми объектами. В этой статье мы разберем, как использовать статическую группу объектов и `collider`, чтобы создать сложные взаимодействия с минимумом кода. Этот подход полезен для создания стен, препятствий, платформ или любого окружения, которое должно реагировать на движение главного героя или других динамических тел.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    group;
    sprite;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('mushroom', 'assets/sprites/mushroom2.png');
        this.load.image('ball', 'assets/sprites/shinyball.png');
    }

    create ()
    {
        this.sprite = this.physics.add.image(400, 300, 'mushroom');

        this.group = this.physics.add.staticGroup({
            key: 'ball',
            frameQuantity: 30
        });

        Phaser.Actions.PlaceOnRectangle(this.group.getChildren(), new Phaser.Geom.Rectangle(84, 84, 616, 416));

        //  We need to call this because placeOnRectangle has changed the coordinates of all the children
        //  If we don't call it, the static physics bodies won't be updated to reflect them
        this.group.refresh();

        this.sprite.setVelocity(100, 200).setBounce(1, 1).setCollideWorldBounds(true).setGravityY(200);

        this.physics.add.collider(this.sprite, this.group);
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    physics: {
        default: 'arcade',
        arcade: {
            debug: true
        }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка сцены и загрузка ассетов

Как и в любой сцене Phaser, мы начинаем с методов preload и create. В preload загружаются изображения для наших спрайтов. Важно использовать setBaseURL, чтобы указать базовый путь для загрузки, что упрощает работу с внешними ресурсами.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('mushroom', 'assets/sprites/mushroom2.png');
    this.load.image('ball', 'assets/sprites/shinyball.png');
}

В методе create происходит основная настройка физического мира и создание объектов. Обратите внимание, что конфигурация физики arcade с debug: true включена на уровне игры, что позволяет видеть хитбоксы объектов во время отладки.

Создание динамического и статических тел

В Arcade физике есть два основных типа тел: динамические (подвижные) и статические (неподвижные). В нашем примере гриб (mushroom) — это динамическое тело, которое будет двигаться и сталкиваться. Он создается с помощью this.physics.add.image, что сразу добавляет ему физическое тело.

this.sprite = this.physics.add.image(400, 300, 'mushroom');

Статическая группа (staticGroup) создается для шариков (ball). Параметр frameQuantity задает количество создаваемых объектов. Статические тела не двигаются под действием физики, но могут участвовать в столкновениях.

this.group = this.physics.add.staticGroup({
    key: 'ball',
    frameQuantity: 30
});

Расстановка объектов и обновление физики

После создания группы шариков, мы используем Phaser.Actions.PlaceOnRectangle, чтобы расположить их по периметру прямоугольника. Это удобный метод для геометрического размещения.

Phaser.Actions.PlaceOnRectangle(this.group.getChildren(), new Phaser.Geom.Rectangle(84, 84, 616, 416));

Ключевой момент: после изменения координат объектов в статической группе **необходимо вызвать** refresh(). Этот метод обновляет позиции физических тел в группе. Без этого вызова столкновения будут рассчитываться для старых, неактуальных координат.

this.group.refresh();

Настройка движения и создание коллайдера

Динамическому спрайту гриба задаются начальные физические свойства: скорость (setVelocity), упругость (setBounce), столкновение с границами мира (setCollideWorldBounds) и гравитация (setGravityY).

this.sprite.setVelocity(100, 200).setBounce(1, 1).setCollideWorldBounds(true).setGravityY(200);

Сердцевина примера — создание коллайдера с помощью this.physics.add.collider. Эта функция автоматически обрабатывает столкновения и отскоки между динамическим спрайтом и каждым объектом в статической группе.

this.physics.add.collider(this.sprite, this.group);

Что попробовать дальше

Использование staticGroup и collider — это эффективный способ добавить в игру сложные взаимодействия с окружением. Для экспериментов попробуйте: изменить форму размещения объектов (например, на круг с PlaceOnCircle), добавить больше динамических тел в коллайдер или заменить статическую группу на динамическую, чтобы шарики тоже начали двигаться при столкновениях.