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

В разработке игр часто требуются интерфейсные элементы, которые могут плавно менять размер без искажения текстуры. Техника Nine Slice (или 9-сегментное растяжение) решает эту проблему, позволяя создавать кнопки, панели и другие UI-элементы, которые сохраняют чёткие углы и границы при любых размерах. В этой статье мы разберём практический пример из официальной документации Phaser, покажем как работает Nine Slice и как анимировать такие элементы для создания динамичного интерфейса.

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

Живой запуск

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

Исходный код


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

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.atlas('ui', 'assets/ui/nine-slice.png', 'assets/ui/nine-slice.json');
    }

    create ()
    {
        const button1 = this.add.nineslice(0, 100, 'ui', 'button-bg', 128, 110, 64, 64).setOrigin(0, 0.5);
        const button2 = this.add.nineslice(400, 300, 'ui', 'button-bg', 128, 110, 64, 64);
        const button3 = this.add.nineslice(800, 500, 'ui', 'button-bg', 128, 110, 64, 64).setOrigin(1, 0.5);

        this.tweens.add({
            targets: [ button1, button2, button3 ],
            width: 700,
            duration: 3000,
            ease: 'sine.inout',
            yoyo: true,
            repeat: -1,
        });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#7b0046',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

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

Nine Slice — это техника разделения текстуры на 9 частей: 4 угла, 4 стороны и центральная часть. Углы остаются неизменными при масштабировании, стороны растягиваются только по одной оси, а центр — по обеим. Это идеально подходит для кнопок, окон диалогов, панелей здоровья — любых элементов, где важны чёткие границы.

В Phaser реализация доступна через метод this.add.nineslice(). В примере используется текстура кнопки, которая корректно масштабируется по ширине от 128 до 700 пикселей, сохраняя скруглённые углы.

Загрузка ресурсов: Атлас текстур

Перед созданием кнопок необходимо загрузить текстуру и данные атласа. В методе preload() используется this.load.atlas(), который загружает изображение и JSON-файл с координатами фреймов.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.atlas('ui', 'assets/ui/nine-slice.png', 'assets/ui/nine-slice.json');
}

Метод setBaseURL() задаёт базовый URL для всех последующих загрузок. Это удобно, если все ресурсы лежат в одной директории. Ключ 'ui' — это идентификатор, по которому мы обращаемся к атласу в коде. Фрейм 'button-bg' внутри этого атласа содержит текстуру для нашей кнопки.

Создание кнопок с разными точками отсчёта

В методе create() создаются три кнопки с помощью this.add.nineslice(). Параметры метода определяют позицию, текстуру и логику масштабирования.

const button1 = this.add.nineslice(0, 100, 'ui', 'button-bg', 128, 110, 64, 64).setOrigin(0, 0.5);
const button2 = this.add.nineslice(400, 300, 'ui', 'button-bg', 128, 110, 64, 64);
const button3 = this.add.nineslice(800, 500, 'ui', 'button-bg', 128, 110, 64, 64).setOrigin(1, 0.5);

Разберём параметры по порядку: 1. 0, 100 — координаты X и Y на сцене. 2. 'ui' — ключ атласа, загруженного в preload(). 3. 'button-bg' — имя фрейма внутри атласа. 4. 128 — начальная ширина объекта. 5. 110 — начальная высота объекта. 6. 64, 64 — размер левого/верхнего и правого/нижнего срезов (в пикселях). Эти значения определяют, какие области текстуры являются углами и не будут растягиваться.

Метод setOrigin() меняет точку привязки (origin) объекта. Для button1 это (0, 0.5) — левый край по центру по вертикали, поэтому кнопка будет растягиваться вправо. Для button3(1, 0.5) (правый край), поэтому анимация ширины будет идти влево. button2 использует стандартный origin (0.5, 0.5) — центр.

Анимация ширины с помощью Tween

Чтобы продемонстрировать работу Nine Slice, к кнопкам применяется анимация изменения ширины. Phaser предоставляет мощную систему твинов через this.tweens.add().

this.tweens.add({
    targets: [ button1, button2, button3 ],
    width: 700,
    duration: 3000,
    ease: 'sine.inout',
    yoyo: true,
    repeat: -1,
});

Конфигурация твина: - targets: массив объектов, к которым применяется анимация. - width: 700 — целевое значение свойства width. - duration: 3000 — длительность анимации в миллисекундах (3 секунды). - ease: 'sine.inout' — функция плавности, создающая мягкий старт и остановку. - yoyo: true — после достижения цели анимация проигрывается в обратном порядке. - repeat: -1 — бесконечное повторение всей последовательности (вперёд-назад).

Именно здесь видна магия Nine Slice: несмотря на радикальное изменение ширины, скруглённые углы и градиенты кнопок остаются идеальными.

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

Nine Slice — это незаменимый инструмент для создания гибкого и визуально consistent игрового интерфейса в Phaser. Он избавляет от необходимости готовить отдельные текстуры для каждого размера кнопки. Для экспериментов попробуйте: изменить параметры срезов (например, 32, 32), анимировать высоту вместо ширины, привязать к кнопкам текст или иконки, используя их как контейнеры, или создать сложную панель HUD с несколькими Nine Slice-элементами.