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

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

Версия 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('platform', 'assets/demoscene/sunset-raster.png');
        this.load.image('lemming', 'assets/sprites/lemming.png');
    }

    create ()
    {
        const platform = this.physics.add.image(400, 200, 'platform')
            .setFriction(0, 1)
            .setImmovable(true)
            .setVelocityY(100);

        const sprites = this.physics.add.group({
            key: 'lemming',
            quantity: 4,
            setXY: { x: -400, y: 300, stepX: 200, stepY: 0 },
            gravityX: 100,
            velocityX: 300
        });

        this.time.addEvent({
            delay: 2000,
            loop: true,
            callback: function ()
            {
                platform.body.velocity.y *= -1;
            }
        });

        this.physics.add.collider(sprites, platform);
    }
}

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);

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

В методе preload мы загружаем два изображения: статичную текстуру для платформы и спрайт лемминга. Обратите внимание на использование setBaseURL — это удобно, когда все ресурсы хранятся в одном месте.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('platform', 'assets/demoscene/sunset-raster.png');
    this.load.image('lemming', 'assets/sprites/lemming.png');
}

Создание движущейся платформы с трением

В методе create мы создаём физический объект платформы. Ключевой момент — настройка трения с помощью метода setFriction(0, 1). Первый аргумент (0) устанавливает трение по оси X, второй (1) — по оси Y. Значение 1 означает максимальное трение: объект, столкнувшись с платформой, мгновенно потеряет всю вертикальную скорость.

Платформа также делается неподвижной для физики (setImmovable(true)) и получает начальную вертикальную скорость (setVelocityY(100)), чтобы двигаться вниз.

const platform = this.physics.add.image(400, 200, 'platform')
    .setFriction(0, 1)
    .setImmovable(true)
    .setVelocityY(100);

Группа спрайтов с гравитацией

Далее создаётся группа физических спрайтов леммингов. Параметры setXY с stepX автоматически расставляют четыре спрайта в линию. Для каждого спрайта в группе задаётся горизонтальная гравитация (gravityX: 100) и начальная горизонтальная скорость (velocityX: 300). Это заставляет их "падать" вправо и двигаться в начальном направлении.

const sprites = this.physics.add.group({
    key: 'lemming',
    quantity: 4,
    setXY: { x: -400, y: 300, stepX: 200, stepY: 0 },
    gravityX: 100,
    velocityX: 300
});

Таймер для изменения направления платформы

Чтобы платформа двигалась вверх и вниз, мы используем событие по таймеру this.time.addEvent. Каждые 2000 миллисекунд (2 секунды) оно инвертирует вертикальную скорость платформы, умножая её на -1. Это создаёт циклическое движение.

this.time.addEvent({
    delay: 2000,
    loop: true,
    callback: function ()
    {
        platform.body.velocity.y *= -1;
    }
});

Обработка столкновений

Самое важное — регистрация коллайдера между группой спрайтов и платформой с помощью this.physics.add.collider. Благодаря настройке трения платформы (frictionY: 1), при столкновении вертикальная скорость спрайтов обнуляется, но горизонтальная (от гравитации и начального импульса) сохраняется. Это создаёт эффект, будто спрайты "едят" по платформе, не отскакивая от неё по вертикали.

this.physics.add.collider(sprites, platform);

Настройка конфигурации игры

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

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);

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

Пример демонстрирует, как комбинация setFriction, setImmovable и горизонтальной гравитации позволяет создавать необычные физические взаимодействия. Для экспериментов попробуйте изменить значения трения (например, setFriction(0.5, 0)), добавить вертикальную гравитацию спрайтам или заставить платформу двигаться по сложной траектории с помощью tweens. Это открывает двери к механикам вроде конвейерных лент, магнитных полей или скользких поверхностей.