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

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

Версия 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/atlas/nine-slice.png', 'assets/atlas/nine-slice.json');
    }

    create ()
    {
        this.add.nineslice(400, 300, 'ui', 'blue-box', 600, 400);

        this.add.nineslice(400, 300, 'ui', 'flectrum', 600);

        this.add.nineslice(400, 300, 'ui', 'button-bg');

        // this.add.nineslice(400, 300, 'ui', 'copy-that-floppy');
    }
}

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

const game = new Phaser.Game(config);

Что такое 9-слайс и зачем он нужен

Представьте, что вам нужно нарисовать кнопку, ширина которой зависит от длины текста внутри. Если просто растянуть квадратную текстуру кнопки по горизонтали, её закруглённые углы исказятся, а границы станут слишком тонкими или толстыми. 9-слайс решает эту проблему.

Текстура мысленно делится на 9 частей (как сетка 3x3). Угловые части (1, 3, 7, 9) никогда не растягиваются. Боковые части (2 и 8) растягиваются только по горизонтали, а верхняя и нижняя (4 и 6) — только по вертикали. Центральная часть (5) растягивается по обоим направлениям. Такой подход сохраняет пропорции важных деталей (углов, границ) при любом размере объекта.

В Phaser для работы с 9-слайсом используется метод this.add.nineslice().

Подготовка атласа и загрузка ресурсов

Для использования 9-слайса текстуры должны быть подготовлены в атласе (texture packer) с корректно определёнными областями (frames). В примере используется атлас 'ui', состоящий из PNG-изображения и JSON-файла с описанием фреймов.

В методе preload() мы загружаем этот атлас. Ключевой момент — JSON-файл уже содержит данные о том, как именно нарезана текстура для каждого фрейма, включая информацию о 9-слайсе (если она была задана при создании атласа в редакторе, например, в Texture Packer или подобном).

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

Метод this.load.atlas() загружает изображение и JSON-манифест, связывая их под ключом 'ui'. Теперь мы можем обращаться к отдельным фреймам этого атласа по их именам, например, 'blue-box' или 'flectrum'.

Создание 9-слайсовых объектов разными способами

Основной метод для создания объекта — this.add.nineslice(x, y, texture, frame, width, height). Он принимает координаты, ключ текстуры (или атласа), имя фрейма из атласа, а также опциональные ширину и высоту итогового объекта.

В сцене create() показаны три варианта использования. Обратите внимание, как меняется поведение при указании разных параметров.

create ()
{
    // Вариант 1: Указываем и ширину, и высоту.
    this.add.nineslice(400, 300, 'ui', 'blue-box', 600, 400);

    // Вариант 2: Указываем только ширину. Высота берётся из исходного фрейма.
    this.add.nineslice(400, 300, 'ui', 'flectrum', 600);

    // Вариант 3: Не указываем размеры. Объект создаётся в исходном размере фрейма.
    this.add.nineslice(400, 300, 'ui', 'button-bg');
}

1. **Первый вызов:** Создаёт объект размером 600x400 пикселей на основе фрейма 'blue-box'. Все растягиваемые области будут масштабированы, чтобы заполнить эту площадь. 2. **Второй вызов:** Создаёт объект шириной 600 пикселей. Высота остаётся такой же, как у исходного фрейма 'flectrum'. Это полезно для создания горизонтальных полос или панелей. 3. **Третий вызов:** Создаёт объект в его "нативном" размере, как он определён в атласе. Это подходит для статических элементов, которые не планируется масштабировать.

Настройка сцены и запуск игры

Конфигурация игры стандартна. Мы указываем тип рендерера, размеры холста, цвет фона, ID родительского HTML-элемента и класс нашей сцены.

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

const game = new Phaser.Game(config);

Важно, что backgroundColor задан чёрным (#000000), чтобы контрастно отобразить светлые UI-элементы, созданные в примере. Класс Example, содержащий логику загрузки и создания объектов, передаётся в конфиг как основная сцена.

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

9-слайсовые спрайты — это фундаментальный инструмент для построения гибкого и визуально приятного игрового интерфейса в Phaser. Они позволяют отделить логику размеров UI от его художественного оформления. **Идеи для экспериментов:** 1. Попробуйте динамически менять размер объекта nineslice после его создания через свойства .width и .height. Объект должен плавно перерисовываться. 2. Создайте интерактивную кнопку, которая меняет фрейм (например, на 'pressed') при нажатии, используя тот же принцип 9-слайса. 3. Поэкспериментируйте с подготовкой собственного атласа в редакторе, который поддерживает экспорт данных о 9-слайсе (например, в Unity или специальных программах для упаковки текстур).