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

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

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

Живой запуск

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

Исходный код


class Demo extends Phaser.Scene
{
    constructor()
    {
        super();
    }

    create ()
    {
        const g = this.add.graphics();

        g.fillRect(0, 0, 400, 300);

        const g2 = this.add.graphics();

        g2.fillRect(400, 0, 400, 300);

        this.add.rectangle(400, 300, 64, 64, 0xff0000);
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    pixelArt: true,
    backgroundColor: '#00007d',
    scene: Demo
};

const game = new Phaser.Game(config);

Анализ исходного кода

В примере создаётся сцена, где на холст добавляются три графических объекта. Первые два создаются через систему Graphics, а третий – через фабрику геометрических фигур. Ключевая деталь – включён режим pixelArt и задан тёмно-синий фон.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    pixelArt: true,
    backgroundColor: '#00007d',
    scene: Demo
};

Проблема: артефакты на стыке Graphics

Два объекта Graphics рисуют прямоугольники, которые соприкасаются по вертикальной линии x=400. Из-за режима pixelArt: true и особенностей рендеринга canvas/WebGL, на границе между ними может появиться видимая щель или артефакт в 1 пиксель.

const g = this.add.graphics();
g.fillRect(0, 0, 400, 300);

const g2 = this.add.graphics();
g2.fillRect(400, 0, 400, 300);

Объекты Graphics рисуют примитивы «как есть», и их границы могут некорректно совмещаться в пиксельной графике, особенно когда координаты целочисленные.

Решение: использование Rectangle

Третий объект создаётся через this.add.rectangle. Это не примитив для рисования, а полноценный игровой объект (Game Object) с текстурами и физическим телом (при необходимости). Его границы обрабатываются иначе, и он не создаёт артефактов на стыках.

this.add.rectangle(400, 300, 64, 64, 0xff0000);

Phaser внутренне оптимизирует рендеринг таких объектов, что делает их предпочтительными для статичной или динамической геометрии в сцене.

Когда использовать Graphics, а когда Rectangle

Выбор зависит от задачи: * Graphics: Для динамического рисования (карандаш, линии, сложные фигуры), временной графики или кастомных визуальных эффектов, где форма меняется каждый кадр. * Rectangle (или Circle, Triangle): Для статичных или редко меняющихся фигур в игровом мире. Эти объекты легче, поддерживают взаимодействие (ввод, физику) и не имеют проблем с пиксельными артефактами.

Использование Graphics для сетки из множества статичных квадратов – частая ошибка, ведущая к проблемам с производительностью и отрисовкой.

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

Всегда предпочитайте готовые игровые объекты (Rectangle, Circle) для статичной геометрии, а Graphics оставляйте для динамического рисования. Для экспериментов попробуйте

  1. отключить pixelArt: true и увидеть, как пропадает артефакт
  2. создать сетку из Rectangle и Graphics для сравнения производительности
  3. добавить физические тела к прямоугольникам и посмотреть, как они взаимодействуют