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

При создании сложных игровых объектов часто возникает ситуация, когда визуальное представление (спрайт) не совпадает с физической формой (collider). Это может быть необходимо для анимаций, поворотов или стилистических решений. В примере из официального репозитория Phaser демонстрируется, как корректно отделить спрайт треугольника от его физического тела с помощью смещения (offset), используя мощь физического движка Matter.js. Эта техника позволяет создавать более реалистичные и визуально привлекательные взаимодействия, сохраняя при этом точность физических столкновений.

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

    create ()
    {
        const shapes = {
            triangle: [
                [ {x: 99,y: 79}, {x: 77,y: 118}, {x: 124,y: 118} ]
            ]
        };

        const triangle = this.matter.add.sprite(400, 100, 'triangle', null, {
            shape: { type: 'fromVerts', verts: shapes.triangle },
            render: { sprite: { xOffset: 0.30, yOffset: 0.15 } }
        });

        triangle.setAngle(16);
        triangle.setBounce(0.9);

        this.matter.add.image(400, 550, 'platform', null, { isStatic: true });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1b1464',
    parent: 'phaser-example',
    physics: {
        default: 'matter',
        matter: {
            gravity: { y: 0.6 },
            debug: true
        }
    },
    scene: Example
};

const game = new Phaser.Game(config);

Загрузка ресурсов и определение формы

В методе preload загружаются два изображения: спрайт треугольника и платформы. Ключевой момент происходит в create. Для физического тела треугольника используется не стандартный прямоугольник (bounding box), а произвольная форма, заданная вершинами (vertices). Это позволяет физике точно соответствовать визуальной форме спрайта.

const shapes = {
    triangle: [
        [ {x: 99,y: 79}, {x: 77,y: 118}, {x: 124,y: 118} ]
    ]
};

Массив shapes.triangle содержит один полигон (массив точек), описывающий треугольник. Координаты вершин заданы относительно центра спрайта. Это стандартный способ задания сложных форм в Matter.js через опцию shape.

Создание спрайта со смещением и кастомной формой

Спрайт создается с помощью this.matter.add.sprite. Пятый параметр — это конфигурационный объект для настройки Matter.js. Именно здесь происходит магия.

const triangle = this.matter.add.sprite(400, 100, 'triangle', null, {
    shape: { type: 'fromVerts', verts: shapes.triangle },
    render: { sprite: { xOffset: 0.30, yOffset: 0.15 } }
});

В опции shape указывается, что форма (Body) должна быть создана "из вершин" (fromVerts), используя массив verts. Опция render.sprite не влияет на физику, она управляет только отрисовкой. Параметры xOffset и yOffset смещают точку отрисовки спрайта относительно центра физического тела. Значения 0.30 и 0.15 означают смещение на 30% ширины и 15% высоты спрайта соответственно. Это позволяет визуально "поднять" треугольник, чтобы его острие совпадало с вершиной физического тела.

Настройка поведения и статичная платформа

После создания задаются базовые физические свойства.

triangle.setAngle(16);
triangle.setBounce(0.9);

Метод setAngle поворачивает физическое тело (и, как следствие, спрайт) на 16 градусов. setBounce устанавливает коэффициент упругости (отскока) равным 0.9, что делает объект очень "прыгучим".

this.matter.add.image(400, 550, 'platform', null, { isStatic: true });

Платформа создается как статичное тело (isStatic: true). Это означает, что она не подвержена силам гравитации или импульсам от других тел, выполняя роль неподвижной поверхности или стены.

Конфигурация игры и физики Matter

Конфигурация игры включает настройку физического движка Matter.js.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#1b1464',
    parent: 'phaser-example',
    physics: {
        default: 'matter',
        matter: {
            gravity: { y: 0.6 },
            debug: true
        }
    },
    scene: Example
};

В блоке physics.matter задается гравитация по оси Y (gravity: { y: 0.6 }). Включение debug: true — крайне полезная опция при разработке. Она отображает контуры всех физических тел (в нашем случае — треугольник по заданным вершинам и платформу), позволяя визуально убедиться, что форма и смещение спрайта настроены корректно.

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

Использование смещения спрайта (xOffset, yOffset) в связке с кастомной физической формой — мощный инструмент для тонкой настройки визуала и физики объектов. Это особенно актуально для несимметричных спрайтов или сложных анимаций. Для экспериментов попробуйте изменить значения смещения на отрицательные, чтобы сместить спрайт в другую сторону. Или задайте более сложную форму из нескольких полигонов для составного тела, также применив к нему смещение спрайта. Отключите debug: false, чтобы увидеть финальный визуальный результат без отладочной информации.