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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    image3;
    image2;
    image1;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');

        this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
        this.load.image('bunny', 'assets/sprites/bunny.png');
        this.load.image('tetris', 'assets/sprites/tetrisblock1.png');

    }

    create ()
    {

        this.image1 = this.add.image(500, 200, 'eye');
        this.image2 = this.add.image(180, 150, 'tetris');
        this.image3 = this.add.image(400, 300, 'bunny');

    }
}

const config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Базовое создание изображений

В примере используется класс Phaser.Scene. В методе preload() загружаются три изображения с разных URL. Важно понимать, что загрузка — это лишь подготовка ресурсов. Их фактическое создание и размещение происходит в методе create().

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
    this.load.image('bunny', 'assets/sprites/bunny.png');
    this.load.image('tetris', 'assets/sprites/tetrisblock1.png');
}

После загрузки в методе create() мы создаем три игровых объекта типа Image, используя this.add.image(x, y, key). Первые два аргумента — это координаты X и Y на канвасе. По умолчанию изображение позиционируется относительно своей центральной точки.

create ()
{
    this.image1 = this.add.image(500, 200, 'eye');
    this.image2 = this.add.image(180, 150, 'tetris');
    this.image3 = this.add.image(400, 300, 'bunny');
}

Что такое точка привязки (origin)?

Ключевой момент, который не виден в коде напрямую, — это свойство origin. По умолчанию у объектов Image и Sprite оно установлено в 0.5. Это означает, что точка (0.5, 0.5), то есть центр текстуры, будет помещена в указанные координаты (X, Y).

Когда вы вызываете this.add.image(400, 300, 'bunny'), центр изображения кролика окажется в точках x=400, y=300. Это удобно для вращения или симметричного размещения, но может сбивать с толку, если вы ожидаете, что в координатах окажется левый верхний угол картинки.

Чтобы изменить точку привязки, используйте свойства originX и originY или метод setOrigin().

// Поместить левый верхний угол изображения в точку (400, 300)
this.image3.setOrigin(0, 0);

Смещение (offset) против позиции (position)

В примере все изображения создаются с разными координатами. Позиция (`x,y) — это финальная точка на экране, куда помещаетсяorigin` объекта.

Смещение (texture offset) — это другое понятие. Оно относится к самой текстуре (загруженному изображению) и определяет, какая ее часть будет использована для отрисовки. В этом примере смещение не применяется, так как используются целые изображения.

Смещение часто используется в атласах спрайтов (spritesheets), чтобы отобразить один конкретный кадр. Для простого изображения (this.load.image) смещение по умолчанию равно (0, 0), то есть используется вся текстура с ее верхнего левого угла.

// Смещение обычно настраивается через frame в конфигурации спрайта
this.add.sprite(400, 300, 'atlasKey', 'frameName');

Практика: контроль над отображением

Давайте модифицируем пример, чтобы четко увидеть разницу. Мы разместим все три изображения в одной точке, но с разными точками привязки.

create ()
{
    const centerX = 400;
    const centerY = 300;

    // Изображение 1: стандартная точка привязки (центр)
    this.image1 = this.add.image(centerX, centerY, 'eye');
    this.image1.setOrigin(0.5, 0.5); // Значение по умолчанию, можно не писать

    // Изображение 2: точка привязки в левом верхнем углу
    this.image2 = this.add.image(centerX, centerY, 'tetris');
    this.image2.setOrigin(0, 0);

    // Изображение 3: точка привязки в правом нижнем углу
    this.image3 = this.add.image(centerX, centerY, 'bunny');
    this.image3.setOrigin(1, 1);
}

В результате все три изображения будут иметь одну и ту же позицию (400, 300), но их origin привязан к разным частям текстуры. Глаз будет центрирован на точке, тетрис-блок коснется ее своим левым верхним углом, а кролик — правым нижним.

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

Понимание разницы между позицией объекта, его точкой привязки и смещением текстуры — фундаментально для точного UI и геймдизайна в Phaser. Экспериментируйте: попробуйте анимировать изменение свойства origin для создания эффекта "качания" объекта за разные углы или используйте setOrigin для выравнивания интерфейсных элементов (например, чтобы все кнопки были выровнены по левому краю, установив originX = 0). Для работы с фреймами из атласа изучите метод setFrame(), который неявно управляет смещением текстуры.