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

В играх объекты редко двигаются в идеальном вакууме. Часто их движение должно замедляться из-за трения или сопротивления среды. Встроенный физический движок Arcade в Phaser позволяет легко добавить такое сопротивление по осям X и Y, делая поведение объектов более реалистичным и управляемым. В этой статье мы разберем, как настроить сопротивление (`drag`) для группы физических тел, чтобы они не скользили вечно по экрану.

Версия 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('block', 'assets/sprites/block.png');
    }

    create ()
    {
        const group = this.physics.add.group({
            bounceX: 0.5,
            bounceY: 0.5,
            collideWorldBounds: true,
            dragX: 100,
            dragY: 100
        });

        group.create(100, 200, 'block').setVelocity(100, 200);
        group.create(500, 200, 'block').setVelocity(-100, -100);
        group.create(300, 400, 'block').setVelocity(60, 100);
        group.create(600, 300, 'block').setVelocity(-30, -50);

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

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

const game = new Phaser.Game(config);

Настройка физического мира и загрузка ассетов

Первым делом в методе preload мы загружаем спрайт, который будет использоваться в качестве физического тела. Важно установить базовый URL для загрузчика, чтобы корректно найти ресурсы.

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

Конфигурация игры определяет, что мы используем физический движок Arcade. Включен режим отладки (debug: true), который рисует хитбоксы, и задана гравитация по оси Y (gravity: { y: 200 }), которая будет тянуть объекты вниз.

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

Создание группы с общими физическими свойствами

В методе create мы создаем физическую группу объектов с помощью this.physics.add.group. Группа — это удобный способ управлять множеством объектов с одинаковыми свойствами.

Ключевые параметры конфигурации группы: * bounceX, bounceY: Коэффициент упругости (от 0 до 1) при столкновениях. * collideWorldBounds: Разрешает объектам сталкиваться с границами мира (экрана). * dragX, dragY: **Сопротивление движению** по соответствующим осям. Чем выше значение, тем быстрее объект будет терять скорость. В нашем примере установлено значение 100 для обеих осей.

const group = this.physics.add.group({
    bounceX: 0.5,
    bounceY: 0.5,
    collideWorldBounds: true,
    dragX: 100,
    dragY: 100
});

Добавление объектов в группу и настройка коллизий

После создания группы мы добавляем в нее отдельные спрайты с помощью метода group.create. Каждому спрайту сразу задается начальная позиция и, что важно, начальная скорость с помощью setVelocity. Благодаря свойствам группы, все созданные спрайты автоматически получают физическое тело с заданным сопротивлением, упругостью и будут взаимодействовать с границами мира.

group.create(100, 200, 'block').setVelocity(100, 200);
group.create(500, 200, 'block').setVelocity(-100, -100);
group.create(300, 400, 'block').setVelocity(60, 100);
group.create(600, 300, 'block').setVelocity(-30, -50);

Затем мы настраиваем коллизии между всеми объектами внутри одной группы. Вызов this.physics.add.collider(group) заставляет объекты группы сталкиваться друг с другом, отталкиваясь согласно заданным параметрам bounce.

this.physics.add.collider(group);

Как работает сопротивление (Drag) на практике

Без параметров dragX и dragY объекты под действием гравитации и начальной скорости двигались бы практически бесконечно, лишь отскакивая от стен и друг от друга. Сопротивление имитирует силу трения.

1. **Начало движения:** Объект получает начальный импульс от setVelocity. 2. **Влияние гравитации:** Сила тяжести постоянно добавляет ускорение вниз. 3. **Действие сопротивления:** Каждый кадр физический движок Arcade уменьшает скорость объекта на значение drag (100 единиц в секунду), но не ниже нуля. Это приводит к плавному, а не мгновенному, замедлению. 4. **Результат:** Объекты постепенно теряют скорость, их движение становится более "тяжелым" и реалистичным. В сочетании с гравитацией и отскоками это создает интересную физическую симуляцию.

Сопротивление можно настраивать индивидуально для каждого объекта после его создания, изменяя свойства body.drag.x и body.drag.y.

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

Использование dragX и dragY в Arcade Physics — это простой, но мощный способ контролировать инерцию объектов. Это основа для создания ощущения движения по песку, воде, льду или просто для предотвращения бесконечного скольжения. **Идеи для экспериментов:** * Создайте разные группы с разными значениями сопротивления (например, 10, 50, 200) и понаблюдайте за разницей в поведении. * Попробуйте асимметричные значения, например dragX: 200, dragY: 20, чтобы смоделировать движение в вязкой горизонтальной среде. * Динамически меняйте body.drag объекта при определенных событиях (например, когда герой заходит в воду).