О чем этот пример
В разработке игр часто нужны панели, кнопки или рамки, которые могут плавно менять размер, но при этом сохранять чёткие углы и края без видимого растягивания. Техника "nine slice" (девять слайсов) решает именно эту задачу. В Phaser она реализована через метод `nineSlice` у `RenderTexture`, что позволяет создавать динамические UI-элементы на лету, используя минимальный набор текстур. Эта статья покажет, как загрузить необходимые фрагменты изображения и собрать из них масштабируемый объект, который будет идеально выглядеть при любых размерах. Это особенно полезно для диалоговых окон, инвентарей или любых элементов интерфейса, размер которых может меняться в процессе игры.
Версия 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.setPath('assets/tests/9slice');
this.load.image('topLeft', 'topLeft.png');
this.load.image('top', 'top.png');
this.load.image('topRight', 'topRight.png');
this.load.image('botLeft', 'botLeft.png');
this.load.image('bot', 'bot.png');
this.load.image('botRight', 'botRight.png');
this.load.image('left', 'left.png');
this.load.image('right', 'right.png');
}
create ()
{
const rt = this.add.renderTexture(50, 50, 512, 256);
rt.nineSlice({
topLeft: 'topLeft',
topBackground: 'top',
topRight: 'topRight',
botLeft: 'botLeft',
botBackground: 'bot',
botRight: 'botRight',
left: 'left',
right: 'right'
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: 0x0567f9,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка текстур: зачем нужно девять частей
Метод nineSlice работает по принципу разделения изображения на девять частей: четыре угла, четыре стороны (верх, низ, лево, право) и центральная область. Углы никогда не масштабируются, стороны растягиваются только по одной оси, а центр может растягиваться по обеим осям. Это сохраняет пропорции рамки и предотвращает размытие важных деталей.
В примере загружаются восемь текстур: все части, кроме центра. Центр в данном случае не загружается отдельно, так как по умолчанию он остаётся прозрачным или заполняется цветом фона RenderTexture. Загрузка происходит в методе preload с указанием базового URL и пути.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.setPath('assets/tests/9slice');
this.load.image('topLeft', 'topLeft.png');
this.load.image('top', 'top.png');
this.load.image('topRight', 'topRight.png');
this.load.image('botLeft', 'botLeft.png');
this.load.image('bot', 'bot.png');
this.load.image('botRight', 'botRight.png');
this.load.image('left', 'left.png');
this.load.image('right', 'right.png');
Создание RenderTexture и применение Nine Slice
Основная магия происходит в методе create. Сначала создаётся объект RenderTexture с заданными координатами, шириной и высотой. RenderTexture — это особый игровой объект, который действует как динамический холст для рисования.
const rt = this.add.renderTexture(50, 50, 512, 256);
Затем к этой текстуре применяется метод nineSlice. В него передаётся объект-конфигурация, где ключи соответствуют частям изображения, а значения — это ключи загруженных ранее текстур. Обратите внимание, что для верхнего и нижнего фона используются ключи topBackground и botBackground, которые ссылаются на текстуры сторон.
rt.nineSlice({
topLeft: 'topLeft',
topBackground: 'top',
topRight: 'topRight',
botLeft: 'botLeft',
botBackground: 'bot',
botRight: 'botRight',
left: 'left',
right: 'right'
});
После вызова метода nineSlice текстура сразу отрисовывается на экране в виде готовой рамки размером 512x256 пикселей.
Как работает конфигурация Nine Slice
Каждый ключ в объекте, передаваемом в rt.nineSlice(), отвечает за свою зону итогового изображения. Важно понимать логику:
- topLeft, topRight, botLeft, botRight — это углы. Они занимают место согласно своему исходному размеру и не растягиваются.
- topBackground и botBackground — это верхняя и нижняя стороны. Они будут растянуты по горизонтали, чтобы заполнить пространство между углами.
- left и right — левая и правая стороны. Они растягиваются по вертикали.
Центральная область (middle) в данном примере не задана, поэтому остаётся пустой (прозрачной). Если бы нужно было заполнить центр, можно было бы добавить текстуру и указать её в ключе middle. Размеры RenderTexture определяют итоговые габариты собранного объекта: система автоматически рассчитывает, как растянуть стороны, чтобы заполнить заданную ширину и высоту, сохраняя углы неизменными.
Динамическое изменение размера и перерисовка
Одно из ключевых преимуществ использования RenderTexture с nineSlice — возможность динамически менять размер и перерисовывать элемент. Например, если размеры RenderTexture изменить после создания, рамка автоматически не обновится. Нужно очистить текстуру и вызвать nineSlice снова с новыми параметрами или в новом размере.
// Пример изменения размера и перерисовки
rt.clear(); // Очищаем RenderTexture
rt.setSize(600, 300); // Меняем размер
rt.nineSlice({
// ... конфигурация слайсов
});
Это открывает возможности для анимированных интерфейсов, где панели плавно расширяются или сжимаются в зависимости от контента. Важно помнить, что исходные текстуры для слайсов должны быть подготовлены правильно: стороны должны быть такими, чтобы их можно было бесшовно растягивать по одной оси.
Что попробовать дальше
Метод nineSlice в Phaser — это мощный и элегантный способ создания масштабируемых графических элементов для интерфейсов. Он избавляет от необходимости создавать отдельные текстуры для каждого возможного размера панели или кнопки. Для экспериментов попробуйте:
1. Добавить текстуру для центральной области (middle) и создать полноценную плитку.
2. Анимировать изменение ширины и высоты RenderTexture с последующей перерисовкой nineSlice.
3. Комбинировать несколько RenderTexture с разными стилями рамок для сложных UI-компоновок.
4. Использовать эту технику для создания динамических health bar или индикаторов прогресса со стилизованными краями.
