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

При разработке игр часто возникает задача вписать один объект в границы другого. Например, вы хотите, чтобы картинка фона заполнила весь экран, или чтобы иконка предмета идеально поместилась в заданную ячейку инвентаря. Ручной расчёт масштаба и позиции может быть утомительным. Класс `Phaser.Actions` предоставляет для этого удобный статический метод `FitToRegion`. Эта статья покажет, как им пользоваться, и объяснит ключевые параметры для точного контроля над вписыванием.

Версия 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('bg', 'assets/skies/bigsky.png');
        this.load.image('card1', 'assets/pics/card1.png');
        this.load.image('card2', 'assets/pics/card2.png');
        this.load.image('card3', 'assets/pics/card3.png');
    }

    create ()
    {
        const bg = this.add.image(640, 360, 'bg');

        // By default, the region is the screen.
        Phaser.Actions.FitToRegion(bg);

        // Create some non-square cards...
        const card1 = this.add.image(320, 360, 'card2');
        const card2 = this.add.image(640, 360, 'card1');
        const card3 = this.add.image(960, 360, 'card3');

        // ... and some square regions.
        // We could use anything with x, y, width, height values, e.g. Geom.Rectangle.
        const fitRect1 = this.add.rectangle(320, 360, 256, 256).setStrokeStyle(1, 0xffffff, 0.5);
        const fitRect2 = this.add.rectangle(640, 360, 256, 256).setStrokeStyle(1, 0xffffff, 0.5);
        const fitRect3 = this.add.rectangle(960, 360, 256, 256).setStrokeStyle(1, 0xffffff, 0.5);

        // Fit cards to regions.
        // Note we override the origin so it will align properly.
        Phaser.Actions.FitToRegion(card1, -1, fitRect1, { originX: 0, originY: 0 });
        Phaser.Actions.FitToRegion(card2, 0, fitRect2, { originX: 0, originY: 0 });
        Phaser.Actions.FitToRegion(card3, 1, fitRect3, { originX: 0, originY: 0 });

        this.add.text(320, 640, '-1: Fit inside', { fontFamily: 'sans-serif', fontColor: '#ffffff', fontSize: 24 }).setOrigin(0.5);
        this.add.text(640, 640, '0: Fit both', { fontFamily: 'sans-serif', fontColor: '#ffffff', fontSize: 24 }).setOrigin(0.5);
        this.add.text(960, 640, '1: Fit outside', { fontFamily: 'sans-serif', fontColor: '#ffffff', fontSize: 24 }).setOrigin(0.5);

        // Animate between fitted and original state.
        this.tweens.add({
            targets: [card1, card2, card3],
            scaleX: 1,
            scaleY: 1,
            duration: 1000,
            repeat: -1,
            repeatDelay: 1000,
            yoyo: true,
            ease: 'Quad.inout'
        });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 1280,
    height: 720,
    backgroundColor: '#2f3640',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Что такое FitToRegion и зачем он нужен

Phaser.Actions.FitToRegion — это статический метод, который масштабирует один или несколько игровых объектов, чтобы они вписались в заданную прямоугольную область (регион). Объект при этом растягивается или сжимается, сохраняя свои пропорции или игнорируя их, в зависимости от выбранного режима.

Основные сценарии использования: * Адаптация фонового изображения под любой размер экрана. * Создание сеток инвентаря или меню, где элементы должны чётко заполнять ячейки. * Динамическая подгонка контента (например, изображений из загрузки) под заранее заданные слоты в интерфейсе.

Базовое использование: фон на весь экран

В примере первым действием фон вписывается в регион по умолчанию — весь экран. Это самый простой вызов метода, который принимает только один аргумент — целевой объект.

// Фон 'bg' будет масштабирован, чтобы целиком заполнить область экрана.
Phaser.Actions.FitToRegion(bg);

Здесь не указан явный регион, поэтому FitToRegion использует в качестве области размеры текущей сцены (или камеры).

Вписывание в произвольные регионы с разными режимами

Мощь метода раскрывается при работе с явно заданными регионами и параметром fitMode. В примере создаются три карточки и три квадратных региона (прямоугольники с контуром).

Регион — это любой объект со свойствами `x,y,width,height. Это может бытьPhaser.Geom.Rectangleили, как в коде, игровой объектRectangle`.

const fitRect1 = this.add.rectangle(320, 360, 256, 256).setStrokeStyle(1, 0xffffff, 0.5);

Ключевой параметр fitMode (второй аргумент) определяет стратегию вписывания: * -1: Объект масштабируется, чтобы целиком поместиться *внутри* региона, сохраняя пропорции. Могут появиться пустые поля. * `0`: Объект масштабируется, чтобы *полностью заполнить* регион, сохраняя пропорции. Части объекта могут быть обрезаны. * `1`: Объект масштабируется, чтобы *полностью покрыть* регион, *игнорируя* пропорции. Регион будет заполнен целиком, но объект может исказиться.

// Карта card1 будет вписана внутрь региона fitRect1 (режим -1).
Phaser.Actions.FitToRegion(card1, -1, fitRect1, { originX: 0, originY: 0 });

Важность точки привязки (origin)

Обратите внимание на последний, необязательный аргумент — объект конфигурации. В примере в нём задаётся { originX: 0, originY: 0 }. Это критически важно для правильного выравнивания.

По умолчанию у изображения точка привязки (origin) находится в центре (0.5, 0.5). Метод FitToRegion масштабирует объект относительно его текущей позиции. Если не изменить origin, после масштабирования центр картинки сместится, и она не будет совпадать с регионом.

Установив origin в (0, 0) (левый верхний угол), мы говорим: "масштабируй объект, но его левый верхний угол должен остаться на месте". Поскольку регионы и карты созданы с одинаковыми координатами, это обеспечивает их точное совмещение после масштабирования.

// Без { originX: 0, originY: 0 } карта масштабировалась бы относительно своего центра и "уплыла" из региона.
Phaser.Actions.FitToRegion(card1, -1, fitRect1, { originX: 0, originY: 0 });

Динамика и анимация

Метод FitToRegion применяет только масштаб (scaleX, scaleY). Это значит, что с изменёнными объектами можно легко работать дальше. В примере используется Tween для анимации, которая плавно возвращает карточки к исходному размеру и обратно к вписанному.

this.tweens.add({
    targets: [card1, card2, card3],
    scaleX: 1,
    scaleY: 1,
    duration: 1000,
    // ... другие параметры твина
});

Так как FitToRegion лишь меняет свойства scale, его можно вызывать на лету, например, при изменении размера игрового окна, чтобы интерфейс адаптировался.

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

Phaser.Actions.FitToRegion — это мощный и лаконичный инструмент для решения задачи "вписать объект в прямоугольник". Понимание параметров fitMode и правильная настройка origin — залог точного результата. Идеи для экспериментов: 1. Создайте интерфейс настроек, где иконки вписываются в круглые области (используйте регион-квадрат, но задайте объекту круглую маску). 2. Реализуйте адаптивный фон для игры, который пересчитывается при каждом изменении размера окна браузера, снова вызывая FitToRegion для фонового изображения. 3. Используйте метод для нестандартных регионов: попробуйте вписать текст (Phaser.GameObjects.Text) в динамически меняющуюся область диалогового окна.